[{"data":1,"prerenderedAt":16853},["ShallowReactive",2],{"portfolio-en-pixelx":3,"employee-bernd-helm":281,"related-blog-security_devops--en":388,"content-query-GCsGFnjSrZ":510,"content-query-lDWCmQfCc3":1720,"content-query-pY5GjeCLfZ":6122,"content-query-DexhC6jnXN":7203,"content-query-TPh1lFGN9c":9482,"content-query-AVfm838iln":10952,"content-query-8xB9vY4DHX":11483,"content-query-yliWk2uBx7":14394,"content-query-t20WiKE4uI":15641,"content-query-Fqgo9f8ijK":16199,"content-query-KtO3wftRle":16669,"content-query-vhr2h3d1hs":16739,"content-query-1PFeYVQSzn":16804,"related-refs-security_devops-pixelx-en":16840},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":7,"subtitle":9,"heroImage":10,"areaOfApplication":11,"industry":12,"technologies":13,"period":17,"teamDescription":19,"budget":20,"tags":21,"body":24,"_type":275,"_id":276,"_source":277,"_file":278,"_stem":279,"_extension":280},"/en/portfolio/pixelx","portfolio",false,"","PixelX","TARGETED SECURITY ANALYSIS AND RAPID VULNERABILITY IDENTIFICATION","/images/portfolio/pixelx/pixelx_secured.png","IT Security and Vulnerability Analysis","IT Security and Consulting",[14,15,16],"linux","apache","mysql",{"from":18,"to":18},"February 2017","1 IT security expert","four-figure",[22,23],"security","devops",{"type":25,"children":26,"toc":270},"root",[27,75,161,263],{"type":28,"tag":29,"props":30,"children":33},"element","section-component",{"className":31},[32],"no-pattern",[34,69],{"type":28,"tag":35,"props":36,"children":45},"v-card",{"className":37,"style":44},[38,39,40,41,42,43],"description__card","text-justify","px-4","px-md-18","py-4","py-md-14","background-color: rgba(var(--v-theme-primary), 0.1)",[46,64],{"type":28,"tag":47,"props":48,"children":49},"p",{},[50,57,59],{"type":28,"tag":51,"props":52,"children":53},"strong",{},[54],{"type":55,"value":56},"text","In today's digital world, even single security vulnerabilities can have serious consequences",{"type":55,"value":58},"\nfor the integrity of company data and the protection of sensitive information.\nPixelX needed a quick, efficient review of their web applications for potential vulnerabilities.\n",{"type":28,"tag":51,"props":60,"children":61},{},[62],{"type":55,"value":63},"Our task was to identify possible risks and security gaps in the shortest possible time,\nin order to achieve maximum security gains with minimal effort.",{"type":28,"tag":47,"props":65,"children":66},{},[67],{"type":55,"value":68},"Thanks to our deep technical understanding and our experience in IT security, we were able to proceed quickly\nand in a targeted manner. During the analysis, we discovered a critical SQL injection vulnerability that could potentially\nhave allowed unauthorized access to the database. After immediately reporting this security gap, we were able\nto provide concrete recommendations for remediation. This targeted approach demonstrates how substantial security\nimprovements can be achieved even with limited time investment.",{"type":28,"tag":70,"props":71,"children":74},"v-divider",{"className":72},[73],"hw-my",[],{"type":28,"tag":29,"props":76,"children":77},{},[78,91],{"type":28,"tag":79,"props":80,"children":88},"h2",{"className":81,"id":87},[82,83,84,85,86],"justify-center","mt-12","mb-4","mb-md-8","pt-0","our-services",[89],{"type":55,"value":90}," Our Services ",{"type":28,"tag":35,"props":92,"children":98},{"className":93},[94,95,40,41,42,43,96,97],"background","transparent-4","mb-8","mb-md-12",[99,130],{"type":28,"tag":100,"props":101,"children":103},"v-row",{":no-gutters":102,"no-gutters":7},"true",[104,126],{"type":28,"tag":105,"props":106,"children":109},"v-col",{"cols":107,"md":108},12,"8",[110],{"type":28,"tag":111,"props":112,"children":114},"h3",{"id":113},"targeted-security-analysis-with-quick-results",[115],{"type":28,"tag":116,"props":117,"children":123},"span",{"className":118},[119,120,121,122],"w-100","text-center","mt-sm-n5","mt-md-n6",[124],{"type":55,"value":125},"Targeted Security Analysis with Quick Results",{"type":28,"tag":105,"props":127,"children":129},{"cols":107,"md":128},"4",[],{"type":28,"tag":100,"props":131,"children":134},{"className":132},[133],"mt-0",[135,153],{"type":28,"tag":105,"props":136,"children":137},{"cols":107,"md":108},[138,143,148],{"type":28,"tag":47,"props":139,"children":140},{},[141],{"type":55,"value":142},"For PixelX, we conducted a focused security analysis aimed at maximum effectiveness with minimal time investment.\nInstead of a comprehensive audit, we concentrated on the most common and critical vulnerabilities in\nweb applications to quickly deliver relevant results.",{"type":28,"tag":47,"props":144,"children":145},{},[146],{"type":55,"value":147},"With our solid technical background, we were able to identify and test potential entry points in a targeted manner.\nIn doing so, we discovered an SQL injection vulnerability that represented a significant security risk.\nThis type of security gap allows attackers to execute unauthorized database queries and potentially\naccess or manipulate sensitive data.",{"type":28,"tag":47,"props":149,"children":150},{},[151],{"type":55,"value":152},"After identifying the vulnerability, we created precise documentation that not only described the problem\nbut also outlined concrete solution approaches. Our practical recommendations for addressing the security gap\nwere directly implementable and did not require extensive system changes. This pragmatic approach enabled\nPixelX to respond quickly without affecting their ongoing business processes.",{"type":28,"tag":105,"props":154,"children":155},{"cols":107,"md":128},[156],{"type":28,"tag":157,"props":158,"children":160},"employees-card",{":showExecutiveRole":102,"name":159},"bernd-helm",[],{"type":28,"tag":29,"props":162,"children":163},{},[164,171,259],{"type":28,"tag":79,"props":165,"children":168},{"className":166,"id":167},[82,83,84,85,86],"special-challenges",[169],{"type":55,"value":170}," Special Challenges ",{"type":28,"tag":35,"props":172,"children":174},{"className":173},[94,95,40,41,42,43],[175],{"type":28,"tag":100,"props":176,"children":177},{},[178,199,224,236],{"type":28,"tag":105,"props":179,"children":182},{"cols":107,"md":180,"sm":181},"2","3",[183],{"type":28,"tag":184,"props":185,"children":193},"v-responsive",{"aspect-ratio":186,"className":187,"content-class":191,"style":192},"0.921",[188,189,190],"bg-primary-lighten-3","hw-hexagon","mx-auto","d-flex justify-center align-center","width: 100%; max-width: 120px;",[194],{"type":28,"tag":195,"props":196,"children":198},"hw-image",{"src":197},"/images/security-logo.svg",[],{"type":28,"tag":105,"props":200,"children":203},{"cols":107,"md":201,"sm":202},"10","9",[204,214,219],{"type":28,"tag":111,"props":205,"children":207},{"id":206},"maximum-efficiency-with-minimal-effort",[208],{"type":28,"tag":116,"props":209,"children":211},{"className":210},[121,122],[212],{"type":55,"value":213},"Maximum Efficiency with Minimal Effort",{"type":28,"tag":47,"props":215,"children":216},{},[217],{"type":55,"value":218},"The particular challenge in this project was to identify relevant security vulnerabilities with limited resources and in a short time.\nUnlike comprehensive security audits, which can take weeks, we had to choose a highly efficient approach that quickly leads\nto actionable results.",{"type":28,"tag":47,"props":220,"children":221},{},[222],{"type":55,"value":223},"Thanks to our deep technical understanding and our experience in application security, we were able to\nfocus on the most likely vulnerabilities. This targeted approach paid off as we quickly discovered\na critical SQL injection vulnerability. The case exemplifies how even a focused\nsecurity review can create substantial added value when conducted by experts with the right technical background.",{"type":28,"tag":105,"props":225,"children":226},{"cols":107,"md":180,"sm":181},[227],{"type":28,"tag":184,"props":228,"children":231},{"aspect-ratio":186,"className":229,"content-class":191,"style":192},[230,189,190],"bg-primary-lighten-1",[232],{"type":28,"tag":195,"props":233,"children":235},{"src":234},"/images/Consulting.svg",[],{"type":28,"tag":105,"props":237,"children":238},{"cols":107,"md":201,"sm":202},[239,249,254],{"type":28,"tag":111,"props":240,"children":242},{"id":241},"clear-communication-of-technical-vulnerabilities",[243],{"type":28,"tag":116,"props":244,"children":246},{"className":245},[121,122],[247],{"type":55,"value":248},"Clear Communication of Technical Vulnerabilities",{"type":28,"tag":47,"props":250,"children":251},{},[252],{"type":55,"value":253},"Another challenge was to communicate technically complex security issues in a way that is understandable to\nall stakeholders. SQL injection is a technically sophisticated topic whose implications and\nsolution approaches are not always easy to convey.",{"type":28,"tag":47,"props":255,"children":256},{},[257],{"type":55,"value":258},"We therefore placed special emphasis on clear, accessible documentation that is understandable both for technical experts\nand for decision-makers without in-depth IT knowledge. Instead of getting lost in technical details,\nwe highlighted the practical implications of the discovered vulnerability and presented pragmatic\nsolution proposals. This communication strategy enabled PixelX to understand the urgency of the problem and\nquickly initiate the necessary measures.",{"type":28,"tag":70,"props":260,"children":262},{"className":261},[73],[],{"type":28,"tag":29,"props":264,"children":265},{},[266],{"type":28,"tag":267,"props":268,"children":269},"contact-form",{},[],{"title":7,"searchDepth":271,"depth":271,"links":272},2,[273,274],{"id":87,"depth":271,"text":90},{"id":167,"depth":271,"text":170},"markdown","common:en:portfolio:9010.pixelx:index.md","common","en/portfolio/9010.pixelx/index.md","en/portfolio/9010.pixelx/index","md",{"_path":282,"_dir":283,"_draft":6,"_partial":6,"_locale":7,"slug":159,"teams":284,"primaryTeam":286,"firstName":287,"lastName":288,"prefixTitle":7,"suffixTitle":7,"education":289,"executiveRole":294,"role":295,"workingSince":303,"inTheCompanySince":304,"techSkills":305,"skills":351,"projects":364,"contactDetails":377,"_image":381,"image":382,"_id":383,"_type":384,"title":385,"_source":283,"_file":386,"_stem":387,"_extension":384},"/employees/bernd-helm","employees",[285,286],"ai","devOps","Bernd","Helm",[290],[291,292,293],"B. Sc. Angewandte Informatik","FHDW Dresden","2010","CTO",[296,297,286,298,299,300,301,302],"founder","chiefTechnologyOfficer","databaseSpecialist","admin","softwareDeveloper","backendDeveloper","consultant","2005","2008",[306,310,313,315,318,320,323,325,327,329,332,336,339,342,345,348],{"name":307,"level":308,"icon":309},"Docker","expert","/images/Docker.svg",{"name":311,"level":308,"icon":312},"Linux","/images/linux_os-mono.svg",{"name":314,"level":308},"Zabbix",{"name":316,"level":308,"icon":317},"MariaDB ColumnStore","/images/maria-db-logo.svg",{"name":319,"level":308},"OpenAI",{"name":321,"level":308,"icon":322},"Pytorch","/images/PyTorch.svg",{"name":324,"level":308},"PHP",{"name":326,"level":308},"Java",{"name":328,"level":308},"Python",{"name":330,"level":308,"icon":331},"SQL","/images/SQL.svg",{"name":333,"level":334,"icon":335},"C++","advanced","/images/cpp-logo.svg",{"name":337,"level":334,"icon":338},"C#","/images/csharp.svg",{"name":340,"level":334,"icon":341},"CSS","/images/css.svg",{"name":343,"level":334,"icon":344},"HTML","/images/html.svg",{"name":346,"level":334,"icon":347},"OpenCV","/images/OpenCV.svg",{"name":349,"level":334,"icon":350},"Vue.js","/images/vuejs.svg",[352,354,356,358,360,362],{"name":353,"level":308},"artificialIntelligence",{"name":355,"level":308},"codingGuidelines",{"name":357,"level":308},"databases",{"name":359,"level":308},"linuxServerAdministration",{"name":361,"level":308},"softwareArchitect",{"name":363,"level":334},"qualityAssurance",[365,368,370,372,375],{"project":366,"position":367},"Gridside","Technical Consultant",{"project":369,"position":367},"Herole",{"project":371,"position":367},"Montagespezis",{"project":373,"position":374},"Orsee","Technical Manager",{"project":376,"position":367},"Vipr",{"eMail":378,"phone":379,"visibility":380},"bernd.helm@helmundwalter.de","+49 351 799 035 20","1","images/employees/Portraits/bernd_helm.webp","images/employees/Portraits/BerndHelm_MS.webp","employees:employees:1.bernd-helm.json","json","Bernd Helm","employees/1.bernd-helm.json","employees/1.bernd-helm",[389,405,419,429,439,450,461,473,486,499],{"_path":390,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":392,"description":393,"author":394,"image":395,"releaseDate":396,"blogCategories":397,"articleTags":400,"tags":401,"_type":275,"_id":402,"_source":277,"_file":403,"_stem":404,"_extension":280},"/en/blog/traefik-magic","blog","Using Traefik as reverse proxy - convention over configuration","How to configure Traefik reverse proxy to get rid of any Traefik specific labels and automatically route to subdomains matching compose project name","robert-juzak","/images/dev-ops-dark.svg","2026-03-13",[398,399],"What moves us","DevOps",[399],[23],"common:en:blog:21.traefik-magic.md","en/blog/21.traefik-magic.md","en/blog/21.traefik-magic",{"_path":406,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":407,"description":408,"author":394,"image":395,"releaseDate":409,"blogCategories":410,"articleTags":411,"tags":414,"_type":275,"_id":416,"_source":277,"_file":417,"_stem":418,"_extension":280},"/en/blog/shopware-plugin-gitlab-pipeline-release","Test, build and release a Shopware 6 Plugin with GitLab CI - Part 1: release","Part 1 - release - of using GitLab for testing, building and releasing a Shopware 6 Plugin","2026-02-26",[398,399],[399,412,413],"Open Source","Shopware",[415,23],"shopware","common:en:blog:18.shopware-plugin-gitlab-pipeline-release.md","en/blog/18.shopware-plugin-gitlab-pipeline-release.md","en/blog/18.shopware-plugin-gitlab-pipeline-release",{"_path":420,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":421,"description":422,"author":394,"image":395,"releaseDate":409,"blogCategories":423,"articleTags":424,"tags":425,"_type":275,"_id":426,"_source":277,"_file":427,"_stem":428,"_extension":280},"/en/blog/shopware-plugin-gitlab-pipeline-build","Test, build and release a Shopware 6 Plugin with GitLab CI - Part 2: build","Part 2 - Build - of using GitLab for testing, building and releasing a Shopware 6 Plugin",[398,399],[399,412,413],[415,23],"common:en:blog:19.shopware-plugin-gitlab-pipeline-build.md","en/blog/19.shopware-plugin-gitlab-pipeline-build.md","en/blog/19.shopware-plugin-gitlab-pipeline-build",{"_path":430,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":431,"description":432,"author":394,"image":395,"releaseDate":409,"blogCategories":433,"articleTags":434,"tags":435,"_type":275,"_id":436,"_source":277,"_file":437,"_stem":438,"_extension":280},"/en/blog/shopware-plugin-gitlab-pipeline-test","Test, build and release a Shopware 6 Plugin with GitLab CI - Part 3: test","Part 3 - Test - of using GitLab for testing, building and releasing a Shopware 6 Plugin",[398,399],[399,412,413],[415,23],"common:en:blog:20.shopware-plugin-gitlab-pipeline-test.md","en/blog/20.shopware-plugin-gitlab-pipeline-test.md","en/blog/20.shopware-plugin-gitlab-pipeline-test",{"_path":440,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":441,"description":442,"author":394,"image":395,"releaseDate":443,"blogCategories":444,"articleTags":445,"tags":446,"_type":275,"_id":447,"_source":277,"_file":448,"_stem":449,"_extension":280},"/en/blog/gitops-docker-renovate","Software management with GitLab, Renovate Bot and Docker","Managing software on a server is not easy. Is it?","2025-10-30",[398,399],[399,412],[23],"common:en:blog:17.gitops-docker-renovate.md","en/blog/17.gitops-docker-renovate.md","en/blog/17.gitops-docker-renovate",{"_path":451,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":452,"description":453,"author":394,"image":395,"releaseDate":454,"blogCategories":455,"articleTags":456,"tags":457,"_type":275,"_id":458,"_source":277,"_file":459,"_stem":460,"_extension":280},"/en/blog/shopware-renovate-bot","Configuring Renovate to properly handle Shopware packages","Shopware is using a custom versioning schema. To allow Renovate to automatically create PR's, we need to adjust the Renovate config","2025-09-08",[398,399],[399,412],[415,23],"common:en:blog:16.shopware-renovate-bot.md","en/blog/16.shopware-renovate-bot.md","en/blog/16.shopware-renovate-bot",{"_path":462,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":463,"description":464,"author":394,"image":395,"releaseDate":465,"blogCategories":466,"articleTags":468,"tags":469,"_type":275,"_id":470,"_source":277,"_file":471,"_stem":472,"_extension":280},"/en/blog/gitlab-behind-traefik","Installing Gitlab behind Traefik","It's super easy to install GitLab with docker on a dedicated host. But what when you need to deploy it alongside you outher deployments?","2025-07-16",[398,467],"Infrastructure",[399],[23],"common:en:blog:14.gitlab-behind-traefik.md","en/blog/14.gitlab-behind-traefik.md","en/blog/14.gitlab-behind-traefik",{"_path":474,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":475,"description":476,"author":477,"image":395,"releaseDate":478,"blogCategories":479,"articleTags":481,"tags":482,"_type":275,"_id":483,"_source":277,"_file":484,"_stem":485,"_extension":280},"/en/blog/a-tribute-to-our-dev-ops","A Tribute to Our Dev Ops","Web applications are mostly developed and tested in a dev environment - however the true endurance test comes from practical scenarios on the prod systems.","jens-bornschein","2025-03-31",[480],"What Moves Us",[399],[23],"common:en:blog:12.a-tribute-to-our-dev-ops.md","en/blog/12.a-tribute-to-our-dev-ops.md","en/blog/12.a-tribute-to-our-dev-ops",{"_path":487,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":488,"description":489,"author":159,"image":490,"releaseDate":491,"blogCategories":492,"articleTags":493,"tags":495,"_type":275,"_id":496,"_source":277,"_file":497,"_stem":498,"_extension":280},"/en/blog/how-to-use-different-dns-servers-on-specific-domains","How to use different DNS servers for specific domains name resolution – VPN Use-Case","How to resolve selected domains over VPN on linux. In today's world, more people than ever use VPN services to work from remote. However, in some cases it's not desirable to route all traffic and all domain name resolutions over the VPN connection.","/blog/thumbnails/VPN.png","2022-04-21",[398,399],[494],"VPN",[23],"common:en:blog:10.how-to-use-different-dns-servers-on-specific-domains.md","en/blog/10.how-to-use-different-dns-servers-on-specific-domains.md","en/blog/10.how-to-use-different-dns-servers-on-specific-domains",{"_path":500,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":501,"description":502,"author":159,"image":503,"releaseDate":504,"blogCategories":505,"tags":506,"_type":275,"_id":507,"_source":277,"_file":508,"_stem":509,"_extension":280},"/en/blog/btrfs-finding-and-fixing-highly-fragmented-files","BTRFS: Finding and fixing highly fragmented files","Most of the best BTRFS features are powered by the copy-on-write technology. If an application wants to rewrite a part of a file, like the first MB, the Data is not written in-place but in an so-called extend. This enables BTRFS to keep multiple versions of partially rewritten files with only claiming ...","/blog/thumbnails/BTRFS_white.png","2020-10-21",[398,467],[23],"common:en:blog:8.btrfs-finding-and-fixing-highly-fragmented-files.md","en/blog/8.btrfs-finding-and-fixing-highly-fragmented-files.md","en/blog/8.btrfs-finding-and-fixing-highly-fragmented-files",{"_path":390,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":392,"description":393,"author":394,"image":395,"releaseDate":396,"blogCategories":511,"articleTags":512,"tags":513,"body":514,"_type":275,"_id":402,"_source":277,"_file":403,"_stem":404,"_extension":280},[398,399],[399],[23],{"type":25,"children":515,"toc":1710},[516,528,533,680,685,760,766,795,800,824,837,856,862,879,980,985,990,1015,1061,1065,1070,1435,1440,1476,1482,1490,1541,1545,1552,1580,1586,1591,1597,1602,1614,1622,1628,1640,1704],{"type":28,"tag":47,"props":517,"children":518},{},[519,526],{"type":28,"tag":520,"props":521,"children":523},"a",{"href":522},"https://doc.traefik.io/traefik/",[524],{"type":55,"value":525},"Traefik",{"type":55,"value":527}," is a reverse proxy with excellent docker integration. It uses labeln attached to containers to route traffic to them.",{"type":28,"tag":47,"props":529,"children":530},{},[531],{"type":55,"value":532},"A common label set looks similar to this:",{"type":28,"tag":534,"props":535,"children":546},"pre",{"code":536,"filename":537,"highlights":538,"language":544,"meta":7,"className":545,"style":7},"services:\n  whoami:\n    image: traefik/whoami\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.whoami.rule=Host(`whoami.example.com`)\"\n      - \"traefik.http.routers.whoami.entrypoints=websecure\"\n      - \"traefik.http.routers.whoami.tls=true\"\n      - \"traefik.http.routers.whoami.tls.certresolver=letsencrypt\"\n","whoami/docker-compose.yaml",[539,540,541,542,543],5,6,7,8,9,"yaml","language-yaml shiki shiki-themes github-dark github-dark monokai",[547],{"type":28,"tag":548,"props":549,"children":550},"code",{"__ignoreMap":7},[551,568,580,600,613,628,641,654,667],{"type":28,"tag":116,"props":552,"children":555},{"class":553,"line":554},"line",1,[556,562],{"type":28,"tag":116,"props":557,"children":559},{"style":558},"--shiki-default:#85E89D;--shiki-dark:#85E89D;--shiki-sepia:#F92672",[560],{"type":55,"value":561},"services",{"type":28,"tag":116,"props":563,"children":565},{"style":564},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2",[566],{"type":55,"value":567},":\n",{"type":28,"tag":116,"props":569,"children":570},{"class":553,"line":271},[571,576],{"type":28,"tag":116,"props":572,"children":573},{"style":558},[574],{"type":55,"value":575},"  whoami",{"type":28,"tag":116,"props":577,"children":578},{"style":564},[579],{"type":55,"value":567},{"type":28,"tag":116,"props":581,"children":583},{"class":553,"line":582},3,[584,589,594],{"type":28,"tag":116,"props":585,"children":586},{"style":558},[587],{"type":55,"value":588},"    image",{"type":28,"tag":116,"props":590,"children":591},{"style":564},[592],{"type":55,"value":593},": ",{"type":28,"tag":116,"props":595,"children":597},{"style":596},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74",[598],{"type":55,"value":599},"traefik/whoami\n",{"type":28,"tag":116,"props":601,"children":603},{"class":553,"line":602},4,[604,609],{"type":28,"tag":116,"props":605,"children":606},{"style":558},[607],{"type":55,"value":608},"    labels",{"type":28,"tag":116,"props":610,"children":611},{"style":564},[612],{"type":55,"value":567},{"type":28,"tag":116,"props":614,"children":617},{"class":615,"line":539},[553,616],"highlight",[618,623],{"type":28,"tag":116,"props":619,"children":620},{"style":564},[621],{"type":55,"value":622},"      - ",{"type":28,"tag":116,"props":624,"children":625},{"style":596},[626],{"type":55,"value":627},"\"traefik.enable=true\"\n",{"type":28,"tag":116,"props":629,"children":631},{"class":630,"line":540},[553,616],[632,636],{"type":28,"tag":116,"props":633,"children":634},{"style":564},[635],{"type":55,"value":622},{"type":28,"tag":116,"props":637,"children":638},{"style":596},[639],{"type":55,"value":640},"\"traefik.http.routers.whoami.rule=Host(`whoami.example.com`)\"\n",{"type":28,"tag":116,"props":642,"children":644},{"class":643,"line":541},[553,616],[645,649],{"type":28,"tag":116,"props":646,"children":647},{"style":564},[648],{"type":55,"value":622},{"type":28,"tag":116,"props":650,"children":651},{"style":596},[652],{"type":55,"value":653},"\"traefik.http.routers.whoami.entrypoints=websecure\"\n",{"type":28,"tag":116,"props":655,"children":657},{"class":656,"line":542},[553,616],[658,662],{"type":28,"tag":116,"props":659,"children":660},{"style":564},[661],{"type":55,"value":622},{"type":28,"tag":116,"props":663,"children":664},{"style":596},[665],{"type":55,"value":666},"\"traefik.http.routers.whoami.tls=true\"\n",{"type":28,"tag":116,"props":668,"children":670},{"class":669,"line":543},[553,616],[671,675],{"type":28,"tag":116,"props":672,"children":673},{"style":564},[674],{"type":55,"value":622},{"type":28,"tag":116,"props":676,"children":677},{"style":596},[678],{"type":55,"value":679},"\"traefik.http.routers.whoami.tls.certresolver=letsencrypt\"\n",{"type":28,"tag":47,"props":681,"children":682},{},[683],{"type":55,"value":684},"In this example:",{"type":28,"tag":686,"props":687,"children":688},"ul",{},[689,701,717,722,734,739],{"type":28,"tag":690,"props":691,"children":692},"li",{},[693,699],{"type":28,"tag":548,"props":694,"children":696},{"className":695},[],[697],{"type":55,"value":698},"whoami",{"type":55,"value":700}," the name of the \"main\" service (2)",{"type":28,"tag":690,"props":702,"children":703},{},[704,709,711],{"type":28,"tag":548,"props":705,"children":707},{"className":706},[],[708],{"type":55,"value":698},{"type":55,"value":710}," the also the default ",{"type":28,"tag":520,"props":712,"children":714},{"href":713},"https://docs.docker.com/compose/how-tos/project-name/",[715],{"type":55,"value":716},"compose project name",{"type":28,"tag":690,"props":718,"children":719},{},[720],{"type":55,"value":721},"Traefik is activated (5)",{"type":28,"tag":690,"props":723,"children":724},{},[725,727,732],{"type":55,"value":726},"It is exposed under ",{"type":28,"tag":548,"props":728,"children":730},{"className":729},[],[731],{"type":55,"value":698},{"type":55,"value":733}," subdomain (6)",{"type":28,"tag":690,"props":735,"children":736},{},[737],{"type":55,"value":738},"It is served over https (7)",{"type":28,"tag":690,"props":740,"children":741},{},[742,744,750,752,758],{"type":55,"value":743},"A preconfigured certresolver named ",{"type":28,"tag":548,"props":745,"children":747},{"className":746},[],[748],{"type":55,"value":749},"letsencrypt",{"type":55,"value":751}," is used for ",{"type":28,"tag":548,"props":753,"children":755},{"className":754},[],[756],{"type":55,"value":757},"tls",{"type":55,"value":759}," (8-9)",{"type":28,"tag":79,"props":761,"children":763},{"id":762},"the-problem",[764],{"type":55,"value":765},"The problem",{"type":28,"tag":47,"props":767,"children":768},{},[769,771,777,779,785,787,793],{"type":55,"value":770},"In my ",{"type":28,"tag":520,"props":772,"children":774},{"href":773},"/blog/gitops-docker-renovate",[775],{"type":55,"value":776},"other post about gitops with docker",{"type":55,"value":778}," I introduced a concept of using ",{"type":28,"tag":548,"props":780,"children":782},{"className":781},[],[783],{"type":55,"value":784},"git",{"type":55,"value":786},"\nas the sources of truth for docker deployments using ",{"type":28,"tag":520,"props":788,"children":790},{"href":789},"https://docs.docker.com/compose/",[791],{"type":55,"value":792},"docker compose",{"type":55,"value":794},".",{"type":28,"tag":47,"props":796,"children":797},{},[798],{"type":55,"value":799},"Now there are some requirements to this approach:",{"type":28,"tag":686,"props":801,"children":802},{},[803,814],{"type":28,"tag":690,"props":804,"children":805},{},[806,808],{"type":55,"value":807},"every stack is exposer under ",{"type":28,"tag":548,"props":809,"children":811},{"className":810},[],[812],{"type":55,"value":813},"\u003Cstack_name>.\u003Cyour_domain>",{"type":28,"tag":690,"props":815,"children":816},{},[817,819],{"type":55,"value":818},"every stack is protected with ",{"type":28,"tag":548,"props":820,"children":822},{"className":821},[],[823],{"type":55,"value":757},{"type":28,"tag":47,"props":825,"children":826},{},[827,829,835],{"type":55,"value":828},"We could of course edit every ",{"type":28,"tag":548,"props":830,"children":832},{"className":831},[],[833],{"type":55,"value":834},"docker-compose.yaml",{"type":55,"value":836}," file and add the required labels, but it quickly becomes obvious,\nthat all the labels are the same!",{"type":28,"tag":838,"props":839,"children":840},"ol",{},[841,846,851],{"type":28,"tag":690,"props":842,"children":843},{},[844],{"type":55,"value":845},"Enable Traefik",{"type":28,"tag":690,"props":847,"children":848},{},[849],{"type":55,"value":850},"Assign a subdomain",{"type":28,"tag":690,"props":852,"children":853},{},[854],{"type":55,"value":855},"Enable HTTPS",{"type":28,"tag":79,"props":857,"children":859},{"id":858},"the-solution",[860],{"type":55,"value":861},"The solution",{"type":28,"tag":47,"props":863,"children":864},{},[865,867,877],{"type":55,"value":866},"By using ",{"type":28,"tag":520,"props":868,"children":870},{"href":869},"https://docs.docker.com/compose/how-tos/environment-variables/envvars/#compose_project_name",[871],{"type":28,"tag":548,"props":872,"children":874},{"className":873},[],[875],{"type":55,"value":876},"$COMPOSE_PROJECT_NAME",{"type":55,"value":878},"\nvariable we can create a more generic template.\nThis ensures that the Traefik rules are consistent.",{"type":28,"tag":534,"props":880,"children":883},{"code":881,"filename":882,"language":544,"meta":7,"className":545,"style":7},"services:\n  \u003Cmain_service>:\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`\u003Cstack_name>.example.com`)\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true\"\n      - \"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt\"\n","\u003Cstack_name>/docker-compose.yaml",[884],{"type":28,"tag":548,"props":885,"children":886},{"__ignoreMap":7},[887,898,910,921,932,944,956,968],{"type":28,"tag":116,"props":888,"children":889},{"class":553,"line":554},[890,894],{"type":28,"tag":116,"props":891,"children":892},{"style":558},[893],{"type":55,"value":561},{"type":28,"tag":116,"props":895,"children":896},{"style":564},[897],{"type":55,"value":567},{"type":28,"tag":116,"props":899,"children":900},{"class":553,"line":271},[901,906],{"type":28,"tag":116,"props":902,"children":903},{"style":558},[904],{"type":55,"value":905},"  \u003Cmain_service>",{"type":28,"tag":116,"props":907,"children":908},{"style":564},[909],{"type":55,"value":567},{"type":28,"tag":116,"props":911,"children":912},{"class":553,"line":582},[913,917],{"type":28,"tag":116,"props":914,"children":915},{"style":558},[916],{"type":55,"value":608},{"type":28,"tag":116,"props":918,"children":919},{"style":564},[920],{"type":55,"value":567},{"type":28,"tag":116,"props":922,"children":923},{"class":553,"line":602},[924,928],{"type":28,"tag":116,"props":925,"children":926},{"style":564},[927],{"type":55,"value":622},{"type":28,"tag":116,"props":929,"children":930},{"style":596},[931],{"type":55,"value":627},{"type":28,"tag":116,"props":933,"children":934},{"class":553,"line":539},[935,939],{"type":28,"tag":116,"props":936,"children":937},{"style":564},[938],{"type":55,"value":622},{"type":28,"tag":116,"props":940,"children":941},{"style":596},[942],{"type":55,"value":943},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`\u003Cstack_name>.example.com`)\"\n",{"type":28,"tag":116,"props":945,"children":946},{"class":553,"line":540},[947,951],{"type":28,"tag":116,"props":948,"children":949},{"style":564},[950],{"type":55,"value":622},{"type":28,"tag":116,"props":952,"children":953},{"style":596},[954],{"type":55,"value":955},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure\"\n",{"type":28,"tag":116,"props":957,"children":958},{"class":553,"line":541},[959,963],{"type":28,"tag":116,"props":960,"children":961},{"style":564},[962],{"type":55,"value":622},{"type":28,"tag":116,"props":964,"children":965},{"style":596},[966],{"type":55,"value":967},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true\"\n",{"type":28,"tag":116,"props":969,"children":970},{"class":553,"line":542},[971,975],{"type":28,"tag":116,"props":972,"children":973},{"style":564},[974],{"type":55,"value":622},{"type":28,"tag":116,"props":976,"children":977},{"style":596},[978],{"type":55,"value":979},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt\"\n",{"type":28,"tag":47,"props":981,"children":982},{},[983],{"type":55,"value":984},"The good news is that Traefik lets us configure some defaults that will cover the above boilerplate!",{"type":28,"tag":47,"props":986,"children":987},{},[988],{"type":55,"value":989},"Let's us define two simple conventions:",{"type":28,"tag":838,"props":991,"children":992},{},[993,1004],{"type":28,"tag":690,"props":994,"children":995},{},[996,1002],{"type":28,"tag":548,"props":997,"children":999},{"className":998},[],[1000],{"type":55,"value":1001},"app",{"type":55,"value":1003}," is the main container, where Traefik will route the traffic",{"type":28,"tag":690,"props":1005,"children":1006},{},[1007,1013],{"type":28,"tag":548,"props":1008,"children":1010},{"className":1009},[],[1011],{"type":55,"value":1012},"\u003Cstack_name>",{"type":55,"value":1014}," (the compose project name) is the subdomain",{"type":28,"tag":534,"props":1016,"children":1019},{"code":1017,"filename":537,"language":544,"meta":1018,"className":545,"style":7},"services:\n  app:\n    image: traefik/whoami\n","(1)",[1020],{"type":28,"tag":548,"props":1021,"children":1022},{"__ignoreMap":7},[1023,1034,1046],{"type":28,"tag":116,"props":1024,"children":1025},{"class":553,"line":554},[1026,1030],{"type":28,"tag":116,"props":1027,"children":1028},{"style":558},[1029],{"type":55,"value":561},{"type":28,"tag":116,"props":1031,"children":1032},{"style":564},[1033],{"type":55,"value":567},{"type":28,"tag":116,"props":1035,"children":1036},{"class":553,"line":271},[1037,1042],{"type":28,"tag":116,"props":1038,"children":1039},{"style":558},[1040],{"type":55,"value":1041},"  app",{"type":28,"tag":116,"props":1043,"children":1044},{"style":564},[1045],{"type":55,"value":567},{"type":28,"tag":116,"props":1047,"children":1048},{"class":553,"line":582},[1049,1053,1057],{"type":28,"tag":116,"props":1050,"children":1051},{"style":558},[1052],{"type":55,"value":588},{"type":28,"tag":116,"props":1054,"children":1055},{"style":564},[1056],{"type":55,"value":593},{"type":28,"tag":116,"props":1058,"children":1059},{"style":596},[1060],{"type":55,"value":599},{"type":28,"tag":1062,"props":1063,"children":1064},"hr",{},[],{"type":28,"tag":47,"props":1066,"children":1067},{},[1068],{"type":55,"value":1069},"Now let's configure traefik to do \"the magic\"",{"type":28,"tag":534,"props":1071,"children":1075},{"code":1072,"filename":1073,"language":544,"meta":1074,"className":545,"style":7},"volumes:\n  letsencrypt:\n    \nservices:\n  traefik:\n    container_name: traefik\n    restart: always\n    image: traefik:3\n    network_mode: host\n    command:\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true\n      - --certificatesresolvers.letsencrypt.acme.email=\u003Cyour_email_here>\n      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n\n      - --entrypoints.web.address=:80\n      - --entrypoints.websecure.address=:443\n      \n      - --entrypoints.web.http.redirections.entrypoint.to=websecure\n      - --entrypoints.web.http.redirections.entrypoint.scheme=https\n      - --entrypoints.websecure.http.tls.certresolver=letsencrypt\n\n      - --providers.docker\n      - --providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)\n      - --providers.docker.constraints=Label(`com.docker.compose.service`,`app`)\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock:ro\n      - /letsencrypt:/letsencrypt\n","traefik/docker-compose.yaml","(2)",[1076],{"type":28,"tag":548,"props":1077,"children":1078},{"__ignoreMap":7},[1079,1091,1103,1111,1122,1134,1151,1168,1184,1201,1214,1227,1239,1252,1265,1275,1288,1301,1310,1323,1336,1349,1357,1370,1383,1396,1409,1422],{"type":28,"tag":116,"props":1080,"children":1081},{"class":553,"line":554},[1082,1087],{"type":28,"tag":116,"props":1083,"children":1084},{"style":558},[1085],{"type":55,"value":1086},"volumes",{"type":28,"tag":116,"props":1088,"children":1089},{"style":564},[1090],{"type":55,"value":567},{"type":28,"tag":116,"props":1092,"children":1093},{"class":553,"line":271},[1094,1099],{"type":28,"tag":116,"props":1095,"children":1096},{"style":558},[1097],{"type":55,"value":1098},"  letsencrypt",{"type":28,"tag":116,"props":1100,"children":1101},{"style":564},[1102],{"type":55,"value":567},{"type":28,"tag":116,"props":1104,"children":1105},{"class":553,"line":582},[1106],{"type":28,"tag":116,"props":1107,"children":1108},{"style":564},[1109],{"type":55,"value":1110},"    \n",{"type":28,"tag":116,"props":1112,"children":1113},{"class":553,"line":602},[1114,1118],{"type":28,"tag":116,"props":1115,"children":1116},{"style":558},[1117],{"type":55,"value":561},{"type":28,"tag":116,"props":1119,"children":1120},{"style":564},[1121],{"type":55,"value":567},{"type":28,"tag":116,"props":1123,"children":1124},{"class":553,"line":539},[1125,1130],{"type":28,"tag":116,"props":1126,"children":1127},{"style":558},[1128],{"type":55,"value":1129},"  traefik",{"type":28,"tag":116,"props":1131,"children":1132},{"style":564},[1133],{"type":55,"value":567},{"type":28,"tag":116,"props":1135,"children":1136},{"class":553,"line":540},[1137,1142,1146],{"type":28,"tag":116,"props":1138,"children":1139},{"style":558},[1140],{"type":55,"value":1141},"    container_name",{"type":28,"tag":116,"props":1143,"children":1144},{"style":564},[1145],{"type":55,"value":593},{"type":28,"tag":116,"props":1147,"children":1148},{"style":596},[1149],{"type":55,"value":1150},"traefik\n",{"type":28,"tag":116,"props":1152,"children":1153},{"class":553,"line":541},[1154,1159,1163],{"type":28,"tag":116,"props":1155,"children":1156},{"style":558},[1157],{"type":55,"value":1158},"    restart",{"type":28,"tag":116,"props":1160,"children":1161},{"style":564},[1162],{"type":55,"value":593},{"type":28,"tag":116,"props":1164,"children":1165},{"style":596},[1166],{"type":55,"value":1167},"always\n",{"type":28,"tag":116,"props":1169,"children":1170},{"class":553,"line":542},[1171,1175,1179],{"type":28,"tag":116,"props":1172,"children":1173},{"style":558},[1174],{"type":55,"value":588},{"type":28,"tag":116,"props":1176,"children":1177},{"style":564},[1178],{"type":55,"value":593},{"type":28,"tag":116,"props":1180,"children":1181},{"style":596},[1182],{"type":55,"value":1183},"traefik:3\n",{"type":28,"tag":116,"props":1185,"children":1186},{"class":553,"line":543},[1187,1192,1196],{"type":28,"tag":116,"props":1188,"children":1189},{"style":558},[1190],{"type":55,"value":1191},"    network_mode",{"type":28,"tag":116,"props":1193,"children":1194},{"style":564},[1195],{"type":55,"value":593},{"type":28,"tag":116,"props":1197,"children":1198},{"style":596},[1199],{"type":55,"value":1200},"host\n",{"type":28,"tag":116,"props":1202,"children":1204},{"class":553,"line":1203},10,[1205,1210],{"type":28,"tag":116,"props":1206,"children":1207},{"style":558},[1208],{"type":55,"value":1209},"    command",{"type":28,"tag":116,"props":1211,"children":1212},{"style":564},[1213],{"type":55,"value":567},{"type":28,"tag":116,"props":1215,"children":1217},{"class":553,"line":1216},11,[1218,1222],{"type":28,"tag":116,"props":1219,"children":1220},{"style":564},[1221],{"type":55,"value":622},{"type":28,"tag":116,"props":1223,"children":1224},{"style":596},[1225],{"type":55,"value":1226},"--certificatesresolvers.letsencrypt.acme.httpchallenge=true\n",{"type":28,"tag":116,"props":1228,"children":1229},{"class":553,"line":107},[1230,1234],{"type":28,"tag":116,"props":1231,"children":1232},{"style":564},[1233],{"type":55,"value":622},{"type":28,"tag":116,"props":1235,"children":1236},{"style":596},[1237],{"type":55,"value":1238},"--certificatesresolvers.letsencrypt.acme.email=\u003Cyour_email_here>\n",{"type":28,"tag":116,"props":1240,"children":1242},{"class":553,"line":1241},13,[1243,1247],{"type":28,"tag":116,"props":1244,"children":1245},{"style":564},[1246],{"type":55,"value":622},{"type":28,"tag":116,"props":1248,"children":1249},{"style":596},[1250],{"type":55,"value":1251},"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n",{"type":28,"tag":116,"props":1253,"children":1255},{"class":553,"line":1254},14,[1256,1260],{"type":28,"tag":116,"props":1257,"children":1258},{"style":564},[1259],{"type":55,"value":622},{"type":28,"tag":116,"props":1261,"children":1262},{"style":596},[1263],{"type":55,"value":1264},"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n",{"type":28,"tag":116,"props":1266,"children":1268},{"class":553,"line":1267},15,[1269],{"type":28,"tag":116,"props":1270,"children":1272},{"emptyLinePlaceholder":1271},true,[1273],{"type":55,"value":1274},"\n",{"type":28,"tag":116,"props":1276,"children":1278},{"class":553,"line":1277},16,[1279,1283],{"type":28,"tag":116,"props":1280,"children":1281},{"style":564},[1282],{"type":55,"value":622},{"type":28,"tag":116,"props":1284,"children":1285},{"style":596},[1286],{"type":55,"value":1287},"--entrypoints.web.address=:80\n",{"type":28,"tag":116,"props":1289,"children":1291},{"class":553,"line":1290},17,[1292,1296],{"type":28,"tag":116,"props":1293,"children":1294},{"style":564},[1295],{"type":55,"value":622},{"type":28,"tag":116,"props":1297,"children":1298},{"style":596},[1299],{"type":55,"value":1300},"--entrypoints.websecure.address=:443\n",{"type":28,"tag":116,"props":1302,"children":1304},{"class":553,"line":1303},18,[1305],{"type":28,"tag":116,"props":1306,"children":1307},{"style":564},[1308],{"type":55,"value":1309},"      \n",{"type":28,"tag":116,"props":1311,"children":1313},{"class":553,"line":1312},19,[1314,1318],{"type":28,"tag":116,"props":1315,"children":1316},{"style":564},[1317],{"type":55,"value":622},{"type":28,"tag":116,"props":1319,"children":1320},{"style":596},[1321],{"type":55,"value":1322},"--entrypoints.web.http.redirections.entrypoint.to=websecure\n",{"type":28,"tag":116,"props":1324,"children":1326},{"class":553,"line":1325},20,[1327,1331],{"type":28,"tag":116,"props":1328,"children":1329},{"style":564},[1330],{"type":55,"value":622},{"type":28,"tag":116,"props":1332,"children":1333},{"style":596},[1334],{"type":55,"value":1335},"--entrypoints.web.http.redirections.entrypoint.scheme=https\n",{"type":28,"tag":116,"props":1337,"children":1339},{"class":553,"line":1338},21,[1340,1344],{"type":28,"tag":116,"props":1341,"children":1342},{"style":564},[1343],{"type":55,"value":622},{"type":28,"tag":116,"props":1345,"children":1346},{"style":596},[1347],{"type":55,"value":1348},"--entrypoints.websecure.http.tls.certresolver=letsencrypt\n",{"type":28,"tag":116,"props":1350,"children":1352},{"class":553,"line":1351},22,[1353],{"type":28,"tag":116,"props":1354,"children":1355},{"emptyLinePlaceholder":1271},[1356],{"type":55,"value":1274},{"type":28,"tag":116,"props":1358,"children":1360},{"class":553,"line":1359},23,[1361,1365],{"type":28,"tag":116,"props":1362,"children":1363},{"style":564},[1364],{"type":55,"value":622},{"type":28,"tag":116,"props":1366,"children":1367},{"style":596},[1368],{"type":55,"value":1369},"--providers.docker\n",{"type":28,"tag":116,"props":1371,"children":1373},{"class":553,"line":1372},24,[1374,1378],{"type":28,"tag":116,"props":1375,"children":1376},{"style":564},[1377],{"type":55,"value":622},{"type":28,"tag":116,"props":1379,"children":1380},{"style":596},[1381],{"type":55,"value":1382},"--providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)\n",{"type":28,"tag":116,"props":1384,"children":1386},{"class":553,"line":1385},25,[1387,1391],{"type":28,"tag":116,"props":1388,"children":1389},{"style":564},[1390],{"type":55,"value":622},{"type":28,"tag":116,"props":1392,"children":1393},{"style":596},[1394],{"type":55,"value":1395},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`)\n",{"type":28,"tag":116,"props":1397,"children":1399},{"class":553,"line":1398},26,[1400,1405],{"type":28,"tag":116,"props":1401,"children":1402},{"style":558},[1403],{"type":55,"value":1404},"    volumes",{"type":28,"tag":116,"props":1406,"children":1407},{"style":564},[1408],{"type":55,"value":567},{"type":28,"tag":116,"props":1410,"children":1412},{"class":553,"line":1411},27,[1413,1417],{"type":28,"tag":116,"props":1414,"children":1415},{"style":564},[1416],{"type":55,"value":622},{"type":28,"tag":116,"props":1418,"children":1419},{"style":596},[1420],{"type":55,"value":1421},"/var/run/docker.sock:/var/run/docker.sock:ro\n",{"type":28,"tag":116,"props":1423,"children":1425},{"class":553,"line":1424},28,[1426,1430],{"type":28,"tag":116,"props":1427,"children":1428},{"style":564},[1429],{"type":55,"value":622},{"type":28,"tag":116,"props":1431,"children":1432},{"style":596},[1433],{"type":55,"value":1434},"/letsencrypt:/letsencrypt\n",{"type":28,"tag":47,"props":1436,"children":1437},{},[1438],{"type":55,"value":1439},"Let's explain this a little",{"type":28,"tag":838,"props":1441,"children":1442},{},[1443,1456,1461,1466,1471],{"type":28,"tag":690,"props":1444,"children":1445},{},[1446,1448,1454],{"type":55,"value":1447},"We configure a ",{"type":28,"tag":520,"props":1449,"children":1451},{"href":1450},"https://letsencrypt.org/",[1452],{"type":55,"value":1453},"Let's Encrypt",{"type":55,"value":1455}," certificates resolvers (11-14)",{"type":28,"tag":690,"props":1457,"children":1458},{},[1459],{"type":55,"value":1460},"We listen on port 80 and 443 (16-17)",{"type":28,"tag":690,"props":1462,"children":1463},{},[1464],{"type":55,"value":1465},"We redirect all http traffic to https (19-20)",{"type":28,"tag":690,"props":1467,"children":1468},{},[1469],{"type":55,"value":1470},"and attach the configured certificates resolvers to it (21)",{"type":28,"tag":690,"props":1472,"children":1473},{},[1474],{"type":55,"value":1475},"We setup the docker provider (23-25)",{"type":28,"tag":111,"props":1477,"children":1479},{"id":1478},"explanation-for-lines-24-25",[1480],{"type":55,"value":1481},"Explanation for lines 24-25",{"type":28,"tag":534,"props":1483,"children":1485},{"code":1484},"--providers.docker.defaultrule=Host(`{{ trimPrefix 'app-'.Name }}.example.com`)\n",[1486],{"type":28,"tag":548,"props":1487,"children":1488},{"__ignoreMap":7},[1489],{"type":55,"value":1484},{"type":28,"tag":686,"props":1491,"children":1492},{},[1493,1525],{"type":28,"tag":690,"props":1494,"children":1495},{},[1496,1502,1504,1510,1512,1517,1519],{"type":28,"tag":548,"props":1497,"children":1499},{"className":1498},[],[1500],{"type":55,"value":1501},".Name",{"type":55,"value":1503}," is autogenerated as ",{"type":28,"tag":548,"props":1505,"children":1507},{"className":1506},[],[1508],{"type":55,"value":1509},"\u003Cservice-name>-\u003Cstack_name>",{"type":55,"value":1511}," so for your ",{"type":28,"tag":548,"props":1513,"children":1515},{"className":1514},[],[1516],{"type":55,"value":698},{"type":55,"value":1518}," example it would be ",{"type":28,"tag":548,"props":1520,"children":1522},{"className":1521},[],[1523],{"type":55,"value":1524},"app-whoami",{"type":28,"tag":690,"props":1526,"children":1527},{},[1528,1534,1536],{"type":28,"tag":548,"props":1529,"children":1531},{"className":1530},[],[1532],{"type":55,"value":1533},"trimPrefix 'app-'.Name",{"type":55,"value":1535}," resolves in ",{"type":28,"tag":548,"props":1537,"children":1539},{"className":1538},[],[1540],{"type":55,"value":698},{"type":28,"tag":1542,"props":1543,"children":1544},"br",{},[],{"type":28,"tag":534,"props":1546,"children":1547},{"code":1395},[1548],{"type":28,"tag":548,"props":1549,"children":1550},{"__ignoreMap":7},[1551],{"type":55,"value":1395},{"type":28,"tag":47,"props":1553,"children":1554},{},[1555,1557,1562,1564,1570,1572,1578],{"type":55,"value":1556},"All services should be exposed by default but should be filtered down, only to ",{"type":28,"tag":548,"props":1558,"children":1560},{"className":1559},[],[1561],{"type":55,"value":1001},{"type":55,"value":1563}," services. The label ",{"type":28,"tag":548,"props":1565,"children":1567},{"className":1566},[],[1568],{"type":55,"value":1569},"com.docker.compose.service",{"type":55,"value":1571}," is added by ",{"type":28,"tag":548,"props":1573,"children":1575},{"className":1574},[],[1576],{"type":55,"value":1577},"docker-compose",{"type":55,"value":1579}," to all containers .",{"type":28,"tag":79,"props":1581,"children":1583},{"id":1582},"bonus-configuration",[1584],{"type":55,"value":1585},"Bonus configuration",{"type":28,"tag":47,"props":1587,"children":1588},{},[1589],{"type":55,"value":1590},"We can tweak this configuration even more.",{"type":28,"tag":111,"props":1592,"children":1594},{"id":1593},"exposing-other-services-in-the-stack",[1595],{"type":55,"value":1596},"Exposing other services in the stack",{"type":28,"tag":47,"props":1598,"children":1599},{},[1600],{"type":55,"value":1601},"Sometimes you want to expose more than just the app container.",{"type":28,"tag":47,"props":1603,"children":1604},{},[1605,1607,1612],{"type":55,"value":1606},"The current configuration won't route traffic to any other services other than ",{"type":28,"tag":548,"props":1608,"children":1610},{"className":1609},[],[1611],{"type":55,"value":1001},{"type":55,"value":1613},".\nTo still be able to use the default configuration method, we need to re-enable it.",{"type":28,"tag":534,"props":1615,"children":1617},{"code":1616},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`) || Label(`traefik.enable`, `true`)\n",[1618],{"type":28,"tag":548,"props":1619,"children":1620},{"__ignoreMap":7},[1621],{"type":55,"value":1616},{"type":28,"tag":111,"props":1623,"children":1625},{"id":1624},"stack-name-other-than-directory-name",[1626],{"type":55,"value":1627},"Stack name other than directory name",{"type":28,"tag":47,"props":1629,"children":1630},{},[1631,1633,1638],{"type":55,"value":1632},"When deploying the stacks, the name is generated based on directory name where the ",{"type":28,"tag":548,"props":1634,"children":1636},{"className":1635},[],[1637],{"type":55,"value":834},{"type":55,"value":1639}," file is located.\nWe can change the make in several ways, but here is the easiest one:",{"type":28,"tag":534,"props":1641,"children":1645},{"code":1642,"filename":1643,"highlights":1644,"language":544,"meta":7,"className":545,"style":7},"name: whoami\nservices:\n  app:\n    image: traefik/whoami\n","whoami-example/docker-compose.yaml",[554],[1646],{"type":28,"tag":548,"props":1647,"children":1648},{"__ignoreMap":7},[1649,1667,1678,1689],{"type":28,"tag":116,"props":1650,"children":1652},{"class":1651,"line":554},[553,616],[1653,1658,1662],{"type":28,"tag":116,"props":1654,"children":1655},{"style":558},[1656],{"type":55,"value":1657},"name",{"type":28,"tag":116,"props":1659,"children":1660},{"style":564},[1661],{"type":55,"value":593},{"type":28,"tag":116,"props":1663,"children":1664},{"style":596},[1665],{"type":55,"value":1666},"whoami\n",{"type":28,"tag":116,"props":1668,"children":1669},{"class":553,"line":271},[1670,1674],{"type":28,"tag":116,"props":1671,"children":1672},{"style":558},[1673],{"type":55,"value":561},{"type":28,"tag":116,"props":1675,"children":1676},{"style":564},[1677],{"type":55,"value":567},{"type":28,"tag":116,"props":1679,"children":1680},{"class":553,"line":582},[1681,1685],{"type":28,"tag":116,"props":1682,"children":1683},{"style":558},[1684],{"type":55,"value":1041},{"type":28,"tag":116,"props":1686,"children":1687},{"style":564},[1688],{"type":55,"value":567},{"type":28,"tag":116,"props":1690,"children":1691},{"class":553,"line":602},[1692,1696,1700],{"type":28,"tag":116,"props":1693,"children":1694},{"style":558},[1695],{"type":55,"value":588},{"type":28,"tag":116,"props":1697,"children":1698},{"style":564},[1699],{"type":55,"value":593},{"type":28,"tag":116,"props":1701,"children":1702},{"style":596},[1703],{"type":55,"value":599},{"type":28,"tag":1705,"props":1706,"children":1707},"style",{},[1708],{"type":55,"value":1709},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":7,"searchDepth":271,"depth":271,"links":1711},[1712,1713,1716],{"id":762,"depth":271,"text":765},{"id":858,"depth":271,"text":861,"children":1714},[1715],{"id":1478,"depth":582,"text":1481},{"id":1582,"depth":271,"text":1585,"children":1717},[1718,1719],{"id":1593,"depth":582,"text":1596},{"id":1624,"depth":582,"text":1627},{"_path":406,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":407,"description":408,"author":394,"image":395,"releaseDate":409,"blogCategories":1721,"articleTags":1722,"tags":1723,"body":1724,"_type":275,"_id":416,"_source":277,"_file":417,"_stem":418,"_extension":280},[398,399],[399,412,413],[415,23],{"type":25,"children":1725,"toc":6110},[1726,1734,1739,1751,1756,1761,1797,1802,1808,1813,1819,1831,2881,2886,2913,2923,2926,2939,2962,3097,3109,3114,3120,3132,3152,3554,3595,3600,3621,3763,3775,3781,3792,3797,3809,3844,3849,4776,4781,4880,4885,4944,4955,4960,4981,5116,5126,5132,5153,5156,5159,5165,5171,5176,5192,5242,5398,5404,5409,5420,5433,5656,6061,6066,6106],{"type":28,"tag":1727,"props":1728,"children":1733},"img",{"alt":7,"aspect-ratio":1729,"height":1730,"object-fit":1731,"src":1732},"1.78",300,"fill","/blog/shopware-plugin-release.png",[],{"type":28,"tag":47,"props":1735,"children":1736},{},[1737],{"type":55,"value":1738},"There are many ways to install Shopware 6 plugins. You can download them directly in the admin panel or install them with composer.",{"type":28,"tag":47,"props":1740,"children":1741},{},[1742,1744,1750],{"type":55,"value":1743},"There is a detailed comparison in the ",{"type":28,"tag":520,"props":1745,"children":1747},{"href":1746},"https://developer.shopware.com/docs/guides/plugins/plugins/",[1748],{"type":55,"value":1749},"official documentation",{"type":55,"value":794},{"type":28,"tag":47,"props":1752,"children":1753},{},[1754],{"type":55,"value":1755},"As a developer and maintainer of themes, customizations, third part API's, etc., I'm focused on Static Plugins.",{"type":28,"tag":47,"props":1757,"children":1758},{},[1759],{"type":55,"value":1760},"The workflow is simple:",{"type":28,"tag":838,"props":1762,"children":1763},{},[1764,1775,1786],{"type":28,"tag":690,"props":1765,"children":1766},{},[1767,1769],{"type":55,"value":1768},"Create a plugin with ",{"type":28,"tag":548,"props":1770,"children":1772},{"className":1771},[],[1773],{"type":55,"value":1774},"bin/console plugin:create --static",{"type":28,"tag":690,"props":1776,"children":1777},{},[1778,1780],{"type":55,"value":1779},"Require it with ",{"type":28,"tag":520,"props":1781,"children":1783},{"href":1782},"https://developer.shopware.com/docs/guides/plugins/plugins/#static-plugins",[1784],{"type":55,"value":1785},"composer",{"type":28,"tag":690,"props":1787,"children":1788},{},[1789,1791],{"type":55,"value":1790},"Build the project with ",{"type":28,"tag":520,"props":1792,"children":1794},{"href":1793},"https://developer.shopware.com/docs/products/cli/project-commands/build.html#example-docker-image",[1795],{"type":55,"value":1796},"shopware-cli",{"type":28,"tag":47,"props":1798,"children":1799},{},[1800],{"type":55,"value":1801},"When we need the same plugin in more than one shop, we could create the same plugin more than ones,\nbut this wouldn't be great for maintenance.",{"type":28,"tag":79,"props":1803,"children":1805},{"id":1804},"extracting-the-plugin",[1806],{"type":55,"value":1807},"Extracting the plugin",{"type":28,"tag":47,"props":1809,"children":1810},{},[1811],{"type":55,"value":1812},"Let's move the source code of our plugin to a separate repository. To make things easier for now, we make the repository public.",{"type":28,"tag":111,"props":1814,"children":1816},{"id":1815},"download-with-git",[1817],{"type":55,"value":1818},"Download with git",{"type":28,"tag":47,"props":1820,"children":1821},{},[1822,1824,1829],{"type":55,"value":1823},"We just need to tell ",{"type":28,"tag":548,"props":1825,"children":1827},{"className":1826},[],[1828],{"type":55,"value":1785},{"type":55,"value":1830}," where to find our plugin",{"type":28,"tag":534,"props":1832,"children":1841},{"className":1833,"code":1834,"filename":1835,"highlights":1836,"language":384,"meta":7,"style":7},"language-json shiki shiki-themes github-dark github-dark monokai","{\n  \"name\": \"shopware/production\",\n  \"license\": \"MIT\",\n  \"type\": \"project\",\n  \"require\": {\n    \"composer-runtime-api\": \"^2.0\",\n    \"acme/sample-plugin\": \"^1.0\",\n    \"shopware/administration\": \"*\",\n    \"shopware/core\": \"6.6.10.2\",\n    \"shopware/elasticsearch\": \"*\",\n    \"shopware/storefront\": \"*\",\n    \"symfony/flex\": \"~2\"\n  },\n  \"repositories\": [\n    {\n      \"type\": \"path\",\n      \"url\": \"custom/plugins/*\",\n      \"options\": {\n        \"symlink\": true\n      }\n    },\n    {\n      \"type\": \"path\",\n      \"url\": \"custom/plugins/*/packages/*\",\n      \"options\": {\n        \"symlink\": true\n      }\n    },\n    {\n      \"type\": \"path\",\n      \"url\": \"custom/static-plugins/*\",\n      \"options\": {\n        \"symlink\": true\n      }\n    },\n    {\n      \"type\": \"git\",\n      \"url\": \"https://\u003CDOMAIN-NAME>/\u003Cgroup>/\u003Crepo>.git\"\n    }\n  ],\n  \"autoload\": {\n    \"psr-4\": {\n      \"App\\\\\": \"src/\"\n    }\n  },\n  \"prefer-stable\": true,\n  \"config\": {\n    \"allow-plugins\": {\n      \"symfony/flex\": true,\n      \"symfony/runtime\": true\n    },\n    \"optimize-autoloader\": true,\n    \"sort-packages\": true\n  },\n  \"scripts\": {\n    \"auto-scripts\": {\n      \"assets:install\": \"symfony-cmd\"\n    },\n    \"post-install-cmd\": [\n      \"@auto-scripts\"\n    ],\n    \"post-update-cmd\": [\n      \"@auto-scripts\"\n    ]\n  },\n  \"extra\": {\n    \"symfony\": {\n      \"allow-contrib\": true,\n      \"endpoint\": [\n        \"https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json\",\n        \"flex://defaults\"\n      ]\n    }\n  }\n}\n","\u003Cproject-root>/composer.json",[1837,1838,1839,1840],36,37,38,39,[1842],{"type":28,"tag":548,"props":1843,"children":1844},{"__ignoreMap":7},[1845,1853,1877,1898,1919,1932,1953,1974,1995,2016,2036,2056,2073,2081,2094,2102,2123,2144,2156,2174,2182,2190,2197,2216,2236,2247,2262,2269,2276,2284,2304,2325,2337,2353,2361,2369,2377,2398,2415,2424,2433,2446,2459,2488,2496,2504,2525,2538,2551,2572,2589,2597,2618,2635,2643,2656,2669,2687,2695,2708,2717,2726,2739,2747,2756,2764,2777,2790,2811,2824,2837,2846,2855,2863,2872],{"type":28,"tag":116,"props":1846,"children":1847},{"class":553,"line":554},[1848],{"type":28,"tag":116,"props":1849,"children":1850},{"style":564},[1851],{"type":55,"value":1852},"{\n",{"type":28,"tag":116,"props":1854,"children":1855},{"class":553,"line":271},[1856,1862,1866,1872],{"type":28,"tag":116,"props":1857,"children":1859},{"style":1858},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic",[1860],{"type":55,"value":1861},"  \"name\"",{"type":28,"tag":116,"props":1863,"children":1864},{"style":564},[1865],{"type":55,"value":593},{"type":28,"tag":116,"props":1867,"children":1869},{"style":1868},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#CFCFC2",[1870],{"type":55,"value":1871},"\"shopware/production\"",{"type":28,"tag":116,"props":1873,"children":1874},{"style":564},[1875],{"type":55,"value":1876},",\n",{"type":28,"tag":116,"props":1878,"children":1879},{"class":553,"line":582},[1880,1885,1889,1894],{"type":28,"tag":116,"props":1881,"children":1882},{"style":1858},[1883],{"type":55,"value":1884},"  \"license\"",{"type":28,"tag":116,"props":1886,"children":1887},{"style":564},[1888],{"type":55,"value":593},{"type":28,"tag":116,"props":1890,"children":1891},{"style":1868},[1892],{"type":55,"value":1893},"\"MIT\"",{"type":28,"tag":116,"props":1895,"children":1896},{"style":564},[1897],{"type":55,"value":1876},{"type":28,"tag":116,"props":1899,"children":1900},{"class":553,"line":602},[1901,1906,1910,1915],{"type":28,"tag":116,"props":1902,"children":1903},{"style":1858},[1904],{"type":55,"value":1905},"  \"type\"",{"type":28,"tag":116,"props":1907,"children":1908},{"style":564},[1909],{"type":55,"value":593},{"type":28,"tag":116,"props":1911,"children":1912},{"style":1868},[1913],{"type":55,"value":1914},"\"project\"",{"type":28,"tag":116,"props":1916,"children":1917},{"style":564},[1918],{"type":55,"value":1876},{"type":28,"tag":116,"props":1920,"children":1921},{"class":553,"line":539},[1922,1927],{"type":28,"tag":116,"props":1923,"children":1924},{"style":1858},[1925],{"type":55,"value":1926},"  \"require\"",{"type":28,"tag":116,"props":1928,"children":1929},{"style":564},[1930],{"type":55,"value":1931},": {\n",{"type":28,"tag":116,"props":1933,"children":1934},{"class":553,"line":540},[1935,1940,1944,1949],{"type":28,"tag":116,"props":1936,"children":1937},{"style":1858},[1938],{"type":55,"value":1939},"    \"composer-runtime-api\"",{"type":28,"tag":116,"props":1941,"children":1942},{"style":564},[1943],{"type":55,"value":593},{"type":28,"tag":116,"props":1945,"children":1946},{"style":1868},[1947],{"type":55,"value":1948},"\"^2.0\"",{"type":28,"tag":116,"props":1950,"children":1951},{"style":564},[1952],{"type":55,"value":1876},{"type":28,"tag":116,"props":1954,"children":1955},{"class":553,"line":541},[1956,1961,1965,1970],{"type":28,"tag":116,"props":1957,"children":1958},{"style":1858},[1959],{"type":55,"value":1960},"    \"acme/sample-plugin\"",{"type":28,"tag":116,"props":1962,"children":1963},{"style":564},[1964],{"type":55,"value":593},{"type":28,"tag":116,"props":1966,"children":1967},{"style":1868},[1968],{"type":55,"value":1969},"\"^1.0\"",{"type":28,"tag":116,"props":1971,"children":1972},{"style":564},[1973],{"type":55,"value":1876},{"type":28,"tag":116,"props":1975,"children":1976},{"class":553,"line":542},[1977,1982,1986,1991],{"type":28,"tag":116,"props":1978,"children":1979},{"style":1858},[1980],{"type":55,"value":1981},"    \"shopware/administration\"",{"type":28,"tag":116,"props":1983,"children":1984},{"style":564},[1985],{"type":55,"value":593},{"type":28,"tag":116,"props":1987,"children":1988},{"style":1868},[1989],{"type":55,"value":1990},"\"*\"",{"type":28,"tag":116,"props":1992,"children":1993},{"style":564},[1994],{"type":55,"value":1876},{"type":28,"tag":116,"props":1996,"children":1997},{"class":553,"line":543},[1998,2003,2007,2012],{"type":28,"tag":116,"props":1999,"children":2000},{"style":1858},[2001],{"type":55,"value":2002},"    \"shopware/core\"",{"type":28,"tag":116,"props":2004,"children":2005},{"style":564},[2006],{"type":55,"value":593},{"type":28,"tag":116,"props":2008,"children":2009},{"style":1868},[2010],{"type":55,"value":2011},"\"6.6.10.2\"",{"type":28,"tag":116,"props":2013,"children":2014},{"style":564},[2015],{"type":55,"value":1876},{"type":28,"tag":116,"props":2017,"children":2018},{"class":553,"line":1203},[2019,2024,2028,2032],{"type":28,"tag":116,"props":2020,"children":2021},{"style":1858},[2022],{"type":55,"value":2023},"    \"shopware/elasticsearch\"",{"type":28,"tag":116,"props":2025,"children":2026},{"style":564},[2027],{"type":55,"value":593},{"type":28,"tag":116,"props":2029,"children":2030},{"style":1868},[2031],{"type":55,"value":1990},{"type":28,"tag":116,"props":2033,"children":2034},{"style":564},[2035],{"type":55,"value":1876},{"type":28,"tag":116,"props":2037,"children":2038},{"class":553,"line":1216},[2039,2044,2048,2052],{"type":28,"tag":116,"props":2040,"children":2041},{"style":1858},[2042],{"type":55,"value":2043},"    \"shopware/storefront\"",{"type":28,"tag":116,"props":2045,"children":2046},{"style":564},[2047],{"type":55,"value":593},{"type":28,"tag":116,"props":2049,"children":2050},{"style":1868},[2051],{"type":55,"value":1990},{"type":28,"tag":116,"props":2053,"children":2054},{"style":564},[2055],{"type":55,"value":1876},{"type":28,"tag":116,"props":2057,"children":2058},{"class":553,"line":107},[2059,2064,2068],{"type":28,"tag":116,"props":2060,"children":2061},{"style":1858},[2062],{"type":55,"value":2063},"    \"symfony/flex\"",{"type":28,"tag":116,"props":2065,"children":2066},{"style":564},[2067],{"type":55,"value":593},{"type":28,"tag":116,"props":2069,"children":2070},{"style":1868},[2071],{"type":55,"value":2072},"\"~2\"\n",{"type":28,"tag":116,"props":2074,"children":2075},{"class":553,"line":1241},[2076],{"type":28,"tag":116,"props":2077,"children":2078},{"style":564},[2079],{"type":55,"value":2080},"  },\n",{"type":28,"tag":116,"props":2082,"children":2083},{"class":553,"line":1254},[2084,2089],{"type":28,"tag":116,"props":2085,"children":2086},{"style":1858},[2087],{"type":55,"value":2088},"  \"repositories\"",{"type":28,"tag":116,"props":2090,"children":2091},{"style":564},[2092],{"type":55,"value":2093},": [\n",{"type":28,"tag":116,"props":2095,"children":2096},{"class":553,"line":1267},[2097],{"type":28,"tag":116,"props":2098,"children":2099},{"style":564},[2100],{"type":55,"value":2101},"    {\n",{"type":28,"tag":116,"props":2103,"children":2104},{"class":553,"line":1277},[2105,2110,2114,2119],{"type":28,"tag":116,"props":2106,"children":2107},{"style":1858},[2108],{"type":55,"value":2109},"      \"type\"",{"type":28,"tag":116,"props":2111,"children":2112},{"style":564},[2113],{"type":55,"value":593},{"type":28,"tag":116,"props":2115,"children":2116},{"style":1868},[2117],{"type":55,"value":2118},"\"path\"",{"type":28,"tag":116,"props":2120,"children":2121},{"style":564},[2122],{"type":55,"value":1876},{"type":28,"tag":116,"props":2124,"children":2125},{"class":553,"line":1290},[2126,2131,2135,2140],{"type":28,"tag":116,"props":2127,"children":2128},{"style":1858},[2129],{"type":55,"value":2130},"      \"url\"",{"type":28,"tag":116,"props":2132,"children":2133},{"style":564},[2134],{"type":55,"value":593},{"type":28,"tag":116,"props":2136,"children":2137},{"style":1868},[2138],{"type":55,"value":2139},"\"custom/plugins/*\"",{"type":28,"tag":116,"props":2141,"children":2142},{"style":564},[2143],{"type":55,"value":1876},{"type":28,"tag":116,"props":2145,"children":2146},{"class":553,"line":1303},[2147,2152],{"type":28,"tag":116,"props":2148,"children":2149},{"style":1858},[2150],{"type":55,"value":2151},"      \"options\"",{"type":28,"tag":116,"props":2153,"children":2154},{"style":564},[2155],{"type":55,"value":1931},{"type":28,"tag":116,"props":2157,"children":2158},{"class":553,"line":1312},[2159,2164,2168],{"type":28,"tag":116,"props":2160,"children":2161},{"style":1858},[2162],{"type":55,"value":2163},"        \"symlink\"",{"type":28,"tag":116,"props":2165,"children":2166},{"style":564},[2167],{"type":55,"value":593},{"type":28,"tag":116,"props":2169,"children":2171},{"style":2170},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF",[2172],{"type":55,"value":2173},"true\n",{"type":28,"tag":116,"props":2175,"children":2176},{"class":553,"line":1325},[2177],{"type":28,"tag":116,"props":2178,"children":2179},{"style":564},[2180],{"type":55,"value":2181},"      }\n",{"type":28,"tag":116,"props":2183,"children":2184},{"class":553,"line":1338},[2185],{"type":28,"tag":116,"props":2186,"children":2187},{"style":564},[2188],{"type":55,"value":2189},"    },\n",{"type":28,"tag":116,"props":2191,"children":2192},{"class":553,"line":1351},[2193],{"type":28,"tag":116,"props":2194,"children":2195},{"style":564},[2196],{"type":55,"value":2101},{"type":28,"tag":116,"props":2198,"children":2199},{"class":553,"line":1359},[2200,2204,2208,2212],{"type":28,"tag":116,"props":2201,"children":2202},{"style":1858},[2203],{"type":55,"value":2109},{"type":28,"tag":116,"props":2205,"children":2206},{"style":564},[2207],{"type":55,"value":593},{"type":28,"tag":116,"props":2209,"children":2210},{"style":1868},[2211],{"type":55,"value":2118},{"type":28,"tag":116,"props":2213,"children":2214},{"style":564},[2215],{"type":55,"value":1876},{"type":28,"tag":116,"props":2217,"children":2218},{"class":553,"line":1372},[2219,2223,2227,2232],{"type":28,"tag":116,"props":2220,"children":2221},{"style":1858},[2222],{"type":55,"value":2130},{"type":28,"tag":116,"props":2224,"children":2225},{"style":564},[2226],{"type":55,"value":593},{"type":28,"tag":116,"props":2228,"children":2229},{"style":1868},[2230],{"type":55,"value":2231},"\"custom/plugins/*/packages/*\"",{"type":28,"tag":116,"props":2233,"children":2234},{"style":564},[2235],{"type":55,"value":1876},{"type":28,"tag":116,"props":2237,"children":2238},{"class":553,"line":1385},[2239,2243],{"type":28,"tag":116,"props":2240,"children":2241},{"style":1858},[2242],{"type":55,"value":2151},{"type":28,"tag":116,"props":2244,"children":2245},{"style":564},[2246],{"type":55,"value":1931},{"type":28,"tag":116,"props":2248,"children":2249},{"class":553,"line":1398},[2250,2254,2258],{"type":28,"tag":116,"props":2251,"children":2252},{"style":1858},[2253],{"type":55,"value":2163},{"type":28,"tag":116,"props":2255,"children":2256},{"style":564},[2257],{"type":55,"value":593},{"type":28,"tag":116,"props":2259,"children":2260},{"style":2170},[2261],{"type":55,"value":2173},{"type":28,"tag":116,"props":2263,"children":2264},{"class":553,"line":1411},[2265],{"type":28,"tag":116,"props":2266,"children":2267},{"style":564},[2268],{"type":55,"value":2181},{"type":28,"tag":116,"props":2270,"children":2271},{"class":553,"line":1424},[2272],{"type":28,"tag":116,"props":2273,"children":2274},{"style":564},[2275],{"type":55,"value":2189},{"type":28,"tag":116,"props":2277,"children":2279},{"class":553,"line":2278},29,[2280],{"type":28,"tag":116,"props":2281,"children":2282},{"style":564},[2283],{"type":55,"value":2101},{"type":28,"tag":116,"props":2285,"children":2287},{"class":553,"line":2286},30,[2288,2292,2296,2300],{"type":28,"tag":116,"props":2289,"children":2290},{"style":1858},[2291],{"type":55,"value":2109},{"type":28,"tag":116,"props":2293,"children":2294},{"style":564},[2295],{"type":55,"value":593},{"type":28,"tag":116,"props":2297,"children":2298},{"style":1868},[2299],{"type":55,"value":2118},{"type":28,"tag":116,"props":2301,"children":2302},{"style":564},[2303],{"type":55,"value":1876},{"type":28,"tag":116,"props":2305,"children":2307},{"class":553,"line":2306},31,[2308,2312,2316,2321],{"type":28,"tag":116,"props":2309,"children":2310},{"style":1858},[2311],{"type":55,"value":2130},{"type":28,"tag":116,"props":2313,"children":2314},{"style":564},[2315],{"type":55,"value":593},{"type":28,"tag":116,"props":2317,"children":2318},{"style":1868},[2319],{"type":55,"value":2320},"\"custom/static-plugins/*\"",{"type":28,"tag":116,"props":2322,"children":2323},{"style":564},[2324],{"type":55,"value":1876},{"type":28,"tag":116,"props":2326,"children":2328},{"class":553,"line":2327},32,[2329,2333],{"type":28,"tag":116,"props":2330,"children":2331},{"style":1858},[2332],{"type":55,"value":2151},{"type":28,"tag":116,"props":2334,"children":2335},{"style":564},[2336],{"type":55,"value":1931},{"type":28,"tag":116,"props":2338,"children":2340},{"class":553,"line":2339},33,[2341,2345,2349],{"type":28,"tag":116,"props":2342,"children":2343},{"style":1858},[2344],{"type":55,"value":2163},{"type":28,"tag":116,"props":2346,"children":2347},{"style":564},[2348],{"type":55,"value":593},{"type":28,"tag":116,"props":2350,"children":2351},{"style":2170},[2352],{"type":55,"value":2173},{"type":28,"tag":116,"props":2354,"children":2356},{"class":553,"line":2355},34,[2357],{"type":28,"tag":116,"props":2358,"children":2359},{"style":564},[2360],{"type":55,"value":2181},{"type":28,"tag":116,"props":2362,"children":2364},{"class":553,"line":2363},35,[2365],{"type":28,"tag":116,"props":2366,"children":2367},{"style":564},[2368],{"type":55,"value":2189},{"type":28,"tag":116,"props":2370,"children":2372},{"class":2371,"line":1837},[553,616],[2373],{"type":28,"tag":116,"props":2374,"children":2375},{"style":564},[2376],{"type":55,"value":2101},{"type":28,"tag":116,"props":2378,"children":2380},{"class":2379,"line":1838},[553,616],[2381,2385,2389,2394],{"type":28,"tag":116,"props":2382,"children":2383},{"style":1858},[2384],{"type":55,"value":2109},{"type":28,"tag":116,"props":2386,"children":2387},{"style":564},[2388],{"type":55,"value":593},{"type":28,"tag":116,"props":2390,"children":2391},{"style":1868},[2392],{"type":55,"value":2393},"\"git\"",{"type":28,"tag":116,"props":2395,"children":2396},{"style":564},[2397],{"type":55,"value":1876},{"type":28,"tag":116,"props":2399,"children":2401},{"class":2400,"line":1839},[553,616],[2402,2406,2410],{"type":28,"tag":116,"props":2403,"children":2404},{"style":1858},[2405],{"type":55,"value":2130},{"type":28,"tag":116,"props":2407,"children":2408},{"style":564},[2409],{"type":55,"value":593},{"type":28,"tag":116,"props":2411,"children":2412},{"style":1868},[2413],{"type":55,"value":2414},"\"https://\u003CDOMAIN-NAME>/\u003Cgroup>/\u003Crepo>.git\"\n",{"type":28,"tag":116,"props":2416,"children":2418},{"class":2417,"line":1840},[553,616],[2419],{"type":28,"tag":116,"props":2420,"children":2421},{"style":564},[2422],{"type":55,"value":2423},"    }\n",{"type":28,"tag":116,"props":2425,"children":2427},{"class":553,"line":2426},40,[2428],{"type":28,"tag":116,"props":2429,"children":2430},{"style":564},[2431],{"type":55,"value":2432},"  ],\n",{"type":28,"tag":116,"props":2434,"children":2436},{"class":553,"line":2435},41,[2437,2442],{"type":28,"tag":116,"props":2438,"children":2439},{"style":1858},[2440],{"type":55,"value":2441},"  \"autoload\"",{"type":28,"tag":116,"props":2443,"children":2444},{"style":564},[2445],{"type":55,"value":1931},{"type":28,"tag":116,"props":2447,"children":2449},{"class":553,"line":2448},42,[2450,2455],{"type":28,"tag":116,"props":2451,"children":2452},{"style":1858},[2453],{"type":55,"value":2454},"    \"psr-4\"",{"type":28,"tag":116,"props":2456,"children":2457},{"style":564},[2458],{"type":55,"value":1931},{"type":28,"tag":116,"props":2460,"children":2462},{"class":553,"line":2461},43,[2463,2468,2474,2479,2483],{"type":28,"tag":116,"props":2464,"children":2465},{"style":1858},[2466],{"type":55,"value":2467},"      \"App",{"type":28,"tag":116,"props":2469,"children":2471},{"style":2470},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#AE81FF;--shiki-sepia-font-style:italic",[2472],{"type":55,"value":2473},"\\\\",{"type":28,"tag":116,"props":2475,"children":2476},{"style":1858},[2477],{"type":55,"value":2478},"\"",{"type":28,"tag":116,"props":2480,"children":2481},{"style":564},[2482],{"type":55,"value":593},{"type":28,"tag":116,"props":2484,"children":2485},{"style":1868},[2486],{"type":55,"value":2487},"\"src/\"\n",{"type":28,"tag":116,"props":2489,"children":2491},{"class":553,"line":2490},44,[2492],{"type":28,"tag":116,"props":2493,"children":2494},{"style":564},[2495],{"type":55,"value":2423},{"type":28,"tag":116,"props":2497,"children":2499},{"class":553,"line":2498},45,[2500],{"type":28,"tag":116,"props":2501,"children":2502},{"style":564},[2503],{"type":55,"value":2080},{"type":28,"tag":116,"props":2505,"children":2507},{"class":553,"line":2506},46,[2508,2513,2517,2521],{"type":28,"tag":116,"props":2509,"children":2510},{"style":1858},[2511],{"type":55,"value":2512},"  \"prefer-stable\"",{"type":28,"tag":116,"props":2514,"children":2515},{"style":564},[2516],{"type":55,"value":593},{"type":28,"tag":116,"props":2518,"children":2519},{"style":2170},[2520],{"type":55,"value":102},{"type":28,"tag":116,"props":2522,"children":2523},{"style":564},[2524],{"type":55,"value":1876},{"type":28,"tag":116,"props":2526,"children":2528},{"class":553,"line":2527},47,[2529,2534],{"type":28,"tag":116,"props":2530,"children":2531},{"style":1858},[2532],{"type":55,"value":2533},"  \"config\"",{"type":28,"tag":116,"props":2535,"children":2536},{"style":564},[2537],{"type":55,"value":1931},{"type":28,"tag":116,"props":2539,"children":2541},{"class":553,"line":2540},48,[2542,2547],{"type":28,"tag":116,"props":2543,"children":2544},{"style":1858},[2545],{"type":55,"value":2546},"    \"allow-plugins\"",{"type":28,"tag":116,"props":2548,"children":2549},{"style":564},[2550],{"type":55,"value":1931},{"type":28,"tag":116,"props":2552,"children":2554},{"class":553,"line":2553},49,[2555,2560,2564,2568],{"type":28,"tag":116,"props":2556,"children":2557},{"style":1858},[2558],{"type":55,"value":2559},"      \"symfony/flex\"",{"type":28,"tag":116,"props":2561,"children":2562},{"style":564},[2563],{"type":55,"value":593},{"type":28,"tag":116,"props":2565,"children":2566},{"style":2170},[2567],{"type":55,"value":102},{"type":28,"tag":116,"props":2569,"children":2570},{"style":564},[2571],{"type":55,"value":1876},{"type":28,"tag":116,"props":2573,"children":2575},{"class":553,"line":2574},50,[2576,2581,2585],{"type":28,"tag":116,"props":2577,"children":2578},{"style":1858},[2579],{"type":55,"value":2580},"      \"symfony/runtime\"",{"type":28,"tag":116,"props":2582,"children":2583},{"style":564},[2584],{"type":55,"value":593},{"type":28,"tag":116,"props":2586,"children":2587},{"style":2170},[2588],{"type":55,"value":2173},{"type":28,"tag":116,"props":2590,"children":2592},{"class":553,"line":2591},51,[2593],{"type":28,"tag":116,"props":2594,"children":2595},{"style":564},[2596],{"type":55,"value":2189},{"type":28,"tag":116,"props":2598,"children":2600},{"class":553,"line":2599},52,[2601,2606,2610,2614],{"type":28,"tag":116,"props":2602,"children":2603},{"style":1858},[2604],{"type":55,"value":2605},"    \"optimize-autoloader\"",{"type":28,"tag":116,"props":2607,"children":2608},{"style":564},[2609],{"type":55,"value":593},{"type":28,"tag":116,"props":2611,"children":2612},{"style":2170},[2613],{"type":55,"value":102},{"type":28,"tag":116,"props":2615,"children":2616},{"style":564},[2617],{"type":55,"value":1876},{"type":28,"tag":116,"props":2619,"children":2621},{"class":553,"line":2620},53,[2622,2627,2631],{"type":28,"tag":116,"props":2623,"children":2624},{"style":1858},[2625],{"type":55,"value":2626},"    \"sort-packages\"",{"type":28,"tag":116,"props":2628,"children":2629},{"style":564},[2630],{"type":55,"value":593},{"type":28,"tag":116,"props":2632,"children":2633},{"style":2170},[2634],{"type":55,"value":2173},{"type":28,"tag":116,"props":2636,"children":2638},{"class":553,"line":2637},54,[2639],{"type":28,"tag":116,"props":2640,"children":2641},{"style":564},[2642],{"type":55,"value":2080},{"type":28,"tag":116,"props":2644,"children":2646},{"class":553,"line":2645},55,[2647,2652],{"type":28,"tag":116,"props":2648,"children":2649},{"style":1858},[2650],{"type":55,"value":2651},"  \"scripts\"",{"type":28,"tag":116,"props":2653,"children":2654},{"style":564},[2655],{"type":55,"value":1931},{"type":28,"tag":116,"props":2657,"children":2659},{"class":553,"line":2658},56,[2660,2665],{"type":28,"tag":116,"props":2661,"children":2662},{"style":1858},[2663],{"type":55,"value":2664},"    \"auto-scripts\"",{"type":28,"tag":116,"props":2666,"children":2667},{"style":564},[2668],{"type":55,"value":1931},{"type":28,"tag":116,"props":2670,"children":2672},{"class":553,"line":2671},57,[2673,2678,2682],{"type":28,"tag":116,"props":2674,"children":2675},{"style":1858},[2676],{"type":55,"value":2677},"      \"assets:install\"",{"type":28,"tag":116,"props":2679,"children":2680},{"style":564},[2681],{"type":55,"value":593},{"type":28,"tag":116,"props":2683,"children":2684},{"style":1868},[2685],{"type":55,"value":2686},"\"symfony-cmd\"\n",{"type":28,"tag":116,"props":2688,"children":2690},{"class":553,"line":2689},58,[2691],{"type":28,"tag":116,"props":2692,"children":2693},{"style":564},[2694],{"type":55,"value":2189},{"type":28,"tag":116,"props":2696,"children":2698},{"class":553,"line":2697},59,[2699,2704],{"type":28,"tag":116,"props":2700,"children":2701},{"style":1858},[2702],{"type":55,"value":2703},"    \"post-install-cmd\"",{"type":28,"tag":116,"props":2705,"children":2706},{"style":564},[2707],{"type":55,"value":2093},{"type":28,"tag":116,"props":2709,"children":2711},{"class":553,"line":2710},60,[2712],{"type":28,"tag":116,"props":2713,"children":2714},{"style":1868},[2715],{"type":55,"value":2716},"      \"@auto-scripts\"\n",{"type":28,"tag":116,"props":2718,"children":2720},{"class":553,"line":2719},61,[2721],{"type":28,"tag":116,"props":2722,"children":2723},{"style":564},[2724],{"type":55,"value":2725},"    ],\n",{"type":28,"tag":116,"props":2727,"children":2729},{"class":553,"line":2728},62,[2730,2735],{"type":28,"tag":116,"props":2731,"children":2732},{"style":1858},[2733],{"type":55,"value":2734},"    \"post-update-cmd\"",{"type":28,"tag":116,"props":2736,"children":2737},{"style":564},[2738],{"type":55,"value":2093},{"type":28,"tag":116,"props":2740,"children":2742},{"class":553,"line":2741},63,[2743],{"type":28,"tag":116,"props":2744,"children":2745},{"style":1868},[2746],{"type":55,"value":2716},{"type":28,"tag":116,"props":2748,"children":2750},{"class":553,"line":2749},64,[2751],{"type":28,"tag":116,"props":2752,"children":2753},{"style":564},[2754],{"type":55,"value":2755},"    ]\n",{"type":28,"tag":116,"props":2757,"children":2759},{"class":553,"line":2758},65,[2760],{"type":28,"tag":116,"props":2761,"children":2762},{"style":564},[2763],{"type":55,"value":2080},{"type":28,"tag":116,"props":2765,"children":2767},{"class":553,"line":2766},66,[2768,2773],{"type":28,"tag":116,"props":2769,"children":2770},{"style":1858},[2771],{"type":55,"value":2772},"  \"extra\"",{"type":28,"tag":116,"props":2774,"children":2775},{"style":564},[2776],{"type":55,"value":1931},{"type":28,"tag":116,"props":2778,"children":2780},{"class":553,"line":2779},67,[2781,2786],{"type":28,"tag":116,"props":2782,"children":2783},{"style":1858},[2784],{"type":55,"value":2785},"    \"symfony\"",{"type":28,"tag":116,"props":2787,"children":2788},{"style":564},[2789],{"type":55,"value":1931},{"type":28,"tag":116,"props":2791,"children":2793},{"class":553,"line":2792},68,[2794,2799,2803,2807],{"type":28,"tag":116,"props":2795,"children":2796},{"style":1858},[2797],{"type":55,"value":2798},"      \"allow-contrib\"",{"type":28,"tag":116,"props":2800,"children":2801},{"style":564},[2802],{"type":55,"value":593},{"type":28,"tag":116,"props":2804,"children":2805},{"style":2170},[2806],{"type":55,"value":102},{"type":28,"tag":116,"props":2808,"children":2809},{"style":564},[2810],{"type":55,"value":1876},{"type":28,"tag":116,"props":2812,"children":2814},{"class":553,"line":2813},69,[2815,2820],{"type":28,"tag":116,"props":2816,"children":2817},{"style":1858},[2818],{"type":55,"value":2819},"      \"endpoint\"",{"type":28,"tag":116,"props":2821,"children":2822},{"style":564},[2823],{"type":55,"value":2093},{"type":28,"tag":116,"props":2825,"children":2827},{"class":553,"line":2826},70,[2828,2833],{"type":28,"tag":116,"props":2829,"children":2830},{"style":1868},[2831],{"type":55,"value":2832},"        \"https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json\"",{"type":28,"tag":116,"props":2834,"children":2835},{"style":564},[2836],{"type":55,"value":1876},{"type":28,"tag":116,"props":2838,"children":2840},{"class":553,"line":2839},71,[2841],{"type":28,"tag":116,"props":2842,"children":2843},{"style":1868},[2844],{"type":55,"value":2845},"        \"flex://defaults\"\n",{"type":28,"tag":116,"props":2847,"children":2849},{"class":553,"line":2848},72,[2850],{"type":28,"tag":116,"props":2851,"children":2852},{"style":564},[2853],{"type":55,"value":2854},"      ]\n",{"type":28,"tag":116,"props":2856,"children":2858},{"class":553,"line":2857},73,[2859],{"type":28,"tag":116,"props":2860,"children":2861},{"style":564},[2862],{"type":55,"value":2423},{"type":28,"tag":116,"props":2864,"children":2866},{"class":553,"line":2865},74,[2867],{"type":28,"tag":116,"props":2868,"children":2869},{"style":564},[2870],{"type":55,"value":2871},"  }\n",{"type":28,"tag":116,"props":2873,"children":2875},{"class":553,"line":2874},75,[2876],{"type":28,"tag":116,"props":2877,"children":2878},{"style":564},[2879],{"type":55,"value":2880},"}\n",{"type":28,"tag":47,"props":2882,"children":2883},{},[2884],{"type":55,"value":2885},"and require it with",{"type":28,"tag":534,"props":2887,"children":2891},{"className":2888,"code":2889,"language":2890,"meta":7,"style":7},"language-shell shiki shiki-themes github-dark github-dark monokai","composer req acme/sample-plugin\n","shell",[2892],{"type":28,"tag":548,"props":2893,"children":2894},{"__ignoreMap":7},[2895],{"type":28,"tag":116,"props":2896,"children":2897},{"class":553,"line":554},[2898,2903,2908],{"type":28,"tag":116,"props":2899,"children":2901},{"style":2900},"--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E",[2902],{"type":55,"value":1785},{"type":28,"tag":116,"props":2904,"children":2905},{"style":596},[2906],{"type":55,"value":2907}," req",{"type":28,"tag":116,"props":2909,"children":2910},{"style":596},[2911],{"type":55,"value":2912}," acme/sample-plugin\n",{"type":28,"tag":2914,"props":2915,"children":2917},"v-alert",{"type":2916},"error",[2918],{"type":28,"tag":47,"props":2919,"children":2920},{},[2921],{"type":55,"value":2922},"Could not find a version of package acme/sample-plugin matching your minimum-stability (stable).\nRequire it with an explicit version constraint allowing its desired stability.",{"type":28,"tag":1542,"props":2924,"children":2925},{},[],{"type":28,"tag":47,"props":2927,"children":2928},{},[2929,2931,2937],{"type":55,"value":2930},"Yes... this is the downside. We need to use ",{"type":28,"tag":548,"props":2932,"children":2934},{"className":2933},[],[2935],{"type":55,"value":2936},"dev-master",{"type":55,"value":2938}," as a version",{"type":28,"tag":534,"props":2940,"children":2942},{"className":2888,"code":2941,"language":2890,"meta":7,"style":7},"composer req acme/sample-plugin:dev-master\n",[2943],{"type":28,"tag":548,"props":2944,"children":2945},{"__ignoreMap":7},[2946],{"type":28,"tag":116,"props":2947,"children":2948},{"class":553,"line":554},[2949,2953,2957],{"type":28,"tag":116,"props":2950,"children":2951},{"style":2900},[2952],{"type":55,"value":1785},{"type":28,"tag":116,"props":2954,"children":2955},{"style":596},[2956],{"type":55,"value":2907},{"type":28,"tag":116,"props":2958,"children":2959},{"style":596},[2960],{"type":55,"value":2961}," acme/sample-plugin:dev-master\n",{"type":28,"tag":534,"props":2963,"children":2967},{"className":2964,"code":2965,"language":2966,"meta":7,"style":7},"language-output shiki shiki-themes github-dark github-dark monokai","./composer.json has been updated\nRunning composer update acme/sample-plugin\nLoading composer repositories with package information                                                                \nUpdating dependencies                                 \nLock file operations: 1 install, 0 updates, 0 removals\n  - Locking acme/sample-plugin (dev-master 294414d)\nWriting lock file\nInstalling dependencies from lock file (including require-dev)\nPackage operations: 1 install, 0 updates, 0 removals\n  - Syncing acme/sample-plugin (dev-master 294414d) into cache\n  - Installing acme/sample-plugin (dev-master 294414d): Cloning 294414deb2 from cache\nGenerating optimized autoload files\n\nRun composer recipes at any time to see the status of your Symfony recipes.\n\nExecuting script assets:install [OK]\n","output",[2968],{"type":28,"tag":548,"props":2969,"children":2970},{"__ignoreMap":7},[2971,2979,2987,2995,3003,3011,3019,3027,3035,3043,3051,3059,3067,3074,3082,3089],{"type":28,"tag":116,"props":2972,"children":2973},{"class":553,"line":554},[2974],{"type":28,"tag":116,"props":2975,"children":2976},{},[2977],{"type":55,"value":2978},"./composer.json has been updated\n",{"type":28,"tag":116,"props":2980,"children":2981},{"class":553,"line":271},[2982],{"type":28,"tag":116,"props":2983,"children":2984},{},[2985],{"type":55,"value":2986},"Running composer update acme/sample-plugin\n",{"type":28,"tag":116,"props":2988,"children":2989},{"class":553,"line":582},[2990],{"type":28,"tag":116,"props":2991,"children":2992},{},[2993],{"type":55,"value":2994},"Loading composer repositories with package information                                                                \n",{"type":28,"tag":116,"props":2996,"children":2997},{"class":553,"line":602},[2998],{"type":28,"tag":116,"props":2999,"children":3000},{},[3001],{"type":55,"value":3002},"Updating dependencies                                 \n",{"type":28,"tag":116,"props":3004,"children":3005},{"class":553,"line":539},[3006],{"type":28,"tag":116,"props":3007,"children":3008},{},[3009],{"type":55,"value":3010},"Lock file operations: 1 install, 0 updates, 0 removals\n",{"type":28,"tag":116,"props":3012,"children":3013},{"class":553,"line":540},[3014],{"type":28,"tag":116,"props":3015,"children":3016},{},[3017],{"type":55,"value":3018},"  - Locking acme/sample-plugin (dev-master 294414d)\n",{"type":28,"tag":116,"props":3020,"children":3021},{"class":553,"line":541},[3022],{"type":28,"tag":116,"props":3023,"children":3024},{},[3025],{"type":55,"value":3026},"Writing lock file\n",{"type":28,"tag":116,"props":3028,"children":3029},{"class":553,"line":542},[3030],{"type":28,"tag":116,"props":3031,"children":3032},{},[3033],{"type":55,"value":3034},"Installing dependencies from lock file (including require-dev)\n",{"type":28,"tag":116,"props":3036,"children":3037},{"class":553,"line":543},[3038],{"type":28,"tag":116,"props":3039,"children":3040},{},[3041],{"type":55,"value":3042},"Package operations: 1 install, 0 updates, 0 removals\n",{"type":28,"tag":116,"props":3044,"children":3045},{"class":553,"line":1203},[3046],{"type":28,"tag":116,"props":3047,"children":3048},{},[3049],{"type":55,"value":3050},"  - Syncing acme/sample-plugin (dev-master 294414d) into cache\n",{"type":28,"tag":116,"props":3052,"children":3053},{"class":553,"line":1216},[3054],{"type":28,"tag":116,"props":3055,"children":3056},{},[3057],{"type":55,"value":3058},"  - Installing acme/sample-plugin (dev-master 294414d): Cloning 294414deb2 from cache\n",{"type":28,"tag":116,"props":3060,"children":3061},{"class":553,"line":107},[3062],{"type":28,"tag":116,"props":3063,"children":3064},{},[3065],{"type":55,"value":3066},"Generating optimized autoload files\n",{"type":28,"tag":116,"props":3068,"children":3069},{"class":553,"line":1241},[3070],{"type":28,"tag":116,"props":3071,"children":3072},{"emptyLinePlaceholder":1271},[3073],{"type":55,"value":1274},{"type":28,"tag":116,"props":3075,"children":3076},{"class":553,"line":1254},[3077],{"type":28,"tag":116,"props":3078,"children":3079},{},[3080],{"type":55,"value":3081},"Run composer recipes at any time to see the status of your Symfony recipes.\n",{"type":28,"tag":116,"props":3083,"children":3084},{"class":553,"line":1267},[3085],{"type":28,"tag":116,"props":3086,"children":3087},{"emptyLinePlaceholder":1271},[3088],{"type":55,"value":1274},{"type":28,"tag":116,"props":3090,"children":3091},{"class":553,"line":1277},[3092],{"type":28,"tag":116,"props":3093,"children":3094},{},[3095],{"type":55,"value":3096},"Executing script assets:install [OK]\n",{"type":28,"tag":47,"props":3098,"children":3099},{},[3100,3102,3107],{"type":55,"value":3101},"Composer will use ",{"type":28,"tag":548,"props":3103,"children":3105},{"className":3104},[],[3106],{"type":55,"value":784},{"type":55,"value":3108}," to clone our repo and use the default branch and the commit hash to track the release.",{"type":28,"tag":47,"props":3110,"children":3111},{},[3112],{"type":55,"value":3113},"This works, but we can do better.",{"type":28,"tag":111,"props":3115,"children":3117},{"id":3116},"git-tags",[3118],{"type":55,"value":3119},"Git tags",{"type":28,"tag":47,"props":3121,"children":3122},{},[3123,3125,3131],{"type":55,"value":3124},"Let's tag our plugin with ",{"type":28,"tag":548,"props":3126,"children":3128},{"className":3127},[],[3129],{"type":55,"value":3130},"v1.0.0",{"type":55,"value":794},{"type":28,"tag":47,"props":3133,"children":3134},{},[3135,3137,3143,3145,3151],{"type":55,"value":3136},"Make sure to set the ",{"type":28,"tag":548,"props":3138,"children":3140},{"className":3139},[],[3141],{"type":55,"value":3142},"version",{"type":55,"value":3144}," in ",{"type":28,"tag":548,"props":3146,"children":3148},{"className":3147},[],[3149],{"type":55,"value":3150},"composer.json",{"type":55,"value":794},{"type":28,"tag":534,"props":3153,"children":3157},{"className":1833,"code":3154,"filename":3155,"highlights":3156,"language":384,"meta":7,"style":7},"{\n    \"name\": \"acme/sample-plugin\",\n    \"description\": \"acme/sample-plugin\",\n    \"type\": \"shopware-platform-plugin\",\n    \"version\": \"1.0.0\",\n    \"license\": \"MIT\",\n    \"require\": {\n        \"shopware/core\": \"~6.6.0\"\n    },\n    \"extra\": {\n        \"shopware-plugin-class\": \"Acme\\\\SamplePlugin\",\n        \"label\": {\n            \"de-DE\": \"Skeleton plugin\",\n            \"en-GB\": \"Skeleton plugin\"\n        }\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Acme\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Acme\\\\Tests\\\\\": \"tests/\"\n        }\n    }\n}\n\n","\u003Cplugin-root>/composer.json",[539],[3158],{"type":28,"tag":548,"props":3159,"children":3160},{"__ignoreMap":7},[3161,3168,3189,3209,3230,3252,3272,3284,3301,3308,3320,3350,3362,3383,3400,3408,3415,3427,3439,3463,3470,3477,3489,3500,3533,3540,3547],{"type":28,"tag":116,"props":3162,"children":3163},{"class":553,"line":554},[3164],{"type":28,"tag":116,"props":3165,"children":3166},{"style":564},[3167],{"type":55,"value":1852},{"type":28,"tag":116,"props":3169,"children":3170},{"class":553,"line":271},[3171,3176,3180,3185],{"type":28,"tag":116,"props":3172,"children":3173},{"style":1858},[3174],{"type":55,"value":3175},"    \"name\"",{"type":28,"tag":116,"props":3177,"children":3178},{"style":564},[3179],{"type":55,"value":593},{"type":28,"tag":116,"props":3181,"children":3182},{"style":1868},[3183],{"type":55,"value":3184},"\"acme/sample-plugin\"",{"type":28,"tag":116,"props":3186,"children":3187},{"style":564},[3188],{"type":55,"value":1876},{"type":28,"tag":116,"props":3190,"children":3191},{"class":553,"line":582},[3192,3197,3201,3205],{"type":28,"tag":116,"props":3193,"children":3194},{"style":1858},[3195],{"type":55,"value":3196},"    \"description\"",{"type":28,"tag":116,"props":3198,"children":3199},{"style":564},[3200],{"type":55,"value":593},{"type":28,"tag":116,"props":3202,"children":3203},{"style":1868},[3204],{"type":55,"value":3184},{"type":28,"tag":116,"props":3206,"children":3207},{"style":564},[3208],{"type":55,"value":1876},{"type":28,"tag":116,"props":3210,"children":3211},{"class":553,"line":602},[3212,3217,3221,3226],{"type":28,"tag":116,"props":3213,"children":3214},{"style":1858},[3215],{"type":55,"value":3216},"    \"type\"",{"type":28,"tag":116,"props":3218,"children":3219},{"style":564},[3220],{"type":55,"value":593},{"type":28,"tag":116,"props":3222,"children":3223},{"style":1868},[3224],{"type":55,"value":3225},"\"shopware-platform-plugin\"",{"type":28,"tag":116,"props":3227,"children":3228},{"style":564},[3229],{"type":55,"value":1876},{"type":28,"tag":116,"props":3231,"children":3233},{"class":3232,"line":539},[553,616],[3234,3239,3243,3248],{"type":28,"tag":116,"props":3235,"children":3236},{"style":1858},[3237],{"type":55,"value":3238},"    \"version\"",{"type":28,"tag":116,"props":3240,"children":3241},{"style":564},[3242],{"type":55,"value":593},{"type":28,"tag":116,"props":3244,"children":3245},{"style":1868},[3246],{"type":55,"value":3247},"\"1.0.0\"",{"type":28,"tag":116,"props":3249,"children":3250},{"style":564},[3251],{"type":55,"value":1876},{"type":28,"tag":116,"props":3253,"children":3254},{"class":553,"line":540},[3255,3260,3264,3268],{"type":28,"tag":116,"props":3256,"children":3257},{"style":1858},[3258],{"type":55,"value":3259},"    \"license\"",{"type":28,"tag":116,"props":3261,"children":3262},{"style":564},[3263],{"type":55,"value":593},{"type":28,"tag":116,"props":3265,"children":3266},{"style":1868},[3267],{"type":55,"value":1893},{"type":28,"tag":116,"props":3269,"children":3270},{"style":564},[3271],{"type":55,"value":1876},{"type":28,"tag":116,"props":3273,"children":3274},{"class":553,"line":541},[3275,3280],{"type":28,"tag":116,"props":3276,"children":3277},{"style":1858},[3278],{"type":55,"value":3279},"    \"require\"",{"type":28,"tag":116,"props":3281,"children":3282},{"style":564},[3283],{"type":55,"value":1931},{"type":28,"tag":116,"props":3285,"children":3286},{"class":553,"line":542},[3287,3292,3296],{"type":28,"tag":116,"props":3288,"children":3289},{"style":1858},[3290],{"type":55,"value":3291},"        \"shopware/core\"",{"type":28,"tag":116,"props":3293,"children":3294},{"style":564},[3295],{"type":55,"value":593},{"type":28,"tag":116,"props":3297,"children":3298},{"style":1868},[3299],{"type":55,"value":3300},"\"~6.6.0\"\n",{"type":28,"tag":116,"props":3302,"children":3303},{"class":553,"line":543},[3304],{"type":28,"tag":116,"props":3305,"children":3306},{"style":564},[3307],{"type":55,"value":2189},{"type":28,"tag":116,"props":3309,"children":3310},{"class":553,"line":1203},[3311,3316],{"type":28,"tag":116,"props":3312,"children":3313},{"style":1858},[3314],{"type":55,"value":3315},"    \"extra\"",{"type":28,"tag":116,"props":3317,"children":3318},{"style":564},[3319],{"type":55,"value":1931},{"type":28,"tag":116,"props":3321,"children":3322},{"class":553,"line":1216},[3323,3328,3332,3337,3341,3346],{"type":28,"tag":116,"props":3324,"children":3325},{"style":1858},[3326],{"type":55,"value":3327},"        \"shopware-plugin-class\"",{"type":28,"tag":116,"props":3329,"children":3330},{"style":564},[3331],{"type":55,"value":593},{"type":28,"tag":116,"props":3333,"children":3334},{"style":1868},[3335],{"type":55,"value":3336},"\"Acme",{"type":28,"tag":116,"props":3338,"children":3339},{"style":2170},[3340],{"type":55,"value":2473},{"type":28,"tag":116,"props":3342,"children":3343},{"style":1868},[3344],{"type":55,"value":3345},"SamplePlugin\"",{"type":28,"tag":116,"props":3347,"children":3348},{"style":564},[3349],{"type":55,"value":1876},{"type":28,"tag":116,"props":3351,"children":3352},{"class":553,"line":107},[3353,3358],{"type":28,"tag":116,"props":3354,"children":3355},{"style":1858},[3356],{"type":55,"value":3357},"        \"label\"",{"type":28,"tag":116,"props":3359,"children":3360},{"style":564},[3361],{"type":55,"value":1931},{"type":28,"tag":116,"props":3363,"children":3364},{"class":553,"line":1241},[3365,3370,3374,3379],{"type":28,"tag":116,"props":3366,"children":3367},{"style":1858},[3368],{"type":55,"value":3369},"            \"de-DE\"",{"type":28,"tag":116,"props":3371,"children":3372},{"style":564},[3373],{"type":55,"value":593},{"type":28,"tag":116,"props":3375,"children":3376},{"style":1868},[3377],{"type":55,"value":3378},"\"Skeleton plugin\"",{"type":28,"tag":116,"props":3380,"children":3381},{"style":564},[3382],{"type":55,"value":1876},{"type":28,"tag":116,"props":3384,"children":3385},{"class":553,"line":1254},[3386,3391,3395],{"type":28,"tag":116,"props":3387,"children":3388},{"style":1858},[3389],{"type":55,"value":3390},"            \"en-GB\"",{"type":28,"tag":116,"props":3392,"children":3393},{"style":564},[3394],{"type":55,"value":593},{"type":28,"tag":116,"props":3396,"children":3397},{"style":1868},[3398],{"type":55,"value":3399},"\"Skeleton plugin\"\n",{"type":28,"tag":116,"props":3401,"children":3402},{"class":553,"line":1267},[3403],{"type":28,"tag":116,"props":3404,"children":3405},{"style":564},[3406],{"type":55,"value":3407},"        }\n",{"type":28,"tag":116,"props":3409,"children":3410},{"class":553,"line":1277},[3411],{"type":28,"tag":116,"props":3412,"children":3413},{"style":564},[3414],{"type":55,"value":2189},{"type":28,"tag":116,"props":3416,"children":3417},{"class":553,"line":1290},[3418,3423],{"type":28,"tag":116,"props":3419,"children":3420},{"style":1858},[3421],{"type":55,"value":3422},"    \"autoload\"",{"type":28,"tag":116,"props":3424,"children":3425},{"style":564},[3426],{"type":55,"value":1931},{"type":28,"tag":116,"props":3428,"children":3429},{"class":553,"line":1303},[3430,3435],{"type":28,"tag":116,"props":3431,"children":3432},{"style":1858},[3433],{"type":55,"value":3434},"        \"psr-4\"",{"type":28,"tag":116,"props":3436,"children":3437},{"style":564},[3438],{"type":55,"value":1931},{"type":28,"tag":116,"props":3440,"children":3441},{"class":553,"line":1312},[3442,3447,3451,3455,3459],{"type":28,"tag":116,"props":3443,"children":3444},{"style":1858},[3445],{"type":55,"value":3446},"            \"Acme",{"type":28,"tag":116,"props":3448,"children":3449},{"style":2470},[3450],{"type":55,"value":2473},{"type":28,"tag":116,"props":3452,"children":3453},{"style":1858},[3454],{"type":55,"value":2478},{"type":28,"tag":116,"props":3456,"children":3457},{"style":564},[3458],{"type":55,"value":593},{"type":28,"tag":116,"props":3460,"children":3461},{"style":1868},[3462],{"type":55,"value":2487},{"type":28,"tag":116,"props":3464,"children":3465},{"class":553,"line":1325},[3466],{"type":28,"tag":116,"props":3467,"children":3468},{"style":564},[3469],{"type":55,"value":3407},{"type":28,"tag":116,"props":3471,"children":3472},{"class":553,"line":1338},[3473],{"type":28,"tag":116,"props":3474,"children":3475},{"style":564},[3476],{"type":55,"value":2189},{"type":28,"tag":116,"props":3478,"children":3479},{"class":553,"line":1351},[3480,3485],{"type":28,"tag":116,"props":3481,"children":3482},{"style":1858},[3483],{"type":55,"value":3484},"    \"autoload-dev\"",{"type":28,"tag":116,"props":3486,"children":3487},{"style":564},[3488],{"type":55,"value":1931},{"type":28,"tag":116,"props":3490,"children":3491},{"class":553,"line":1359},[3492,3496],{"type":28,"tag":116,"props":3493,"children":3494},{"style":1858},[3495],{"type":55,"value":3434},{"type":28,"tag":116,"props":3497,"children":3498},{"style":564},[3499],{"type":55,"value":1931},{"type":28,"tag":116,"props":3501,"children":3502},{"class":553,"line":1372},[3503,3507,3511,3516,3520,3524,3528],{"type":28,"tag":116,"props":3504,"children":3505},{"style":1858},[3506],{"type":55,"value":3446},{"type":28,"tag":116,"props":3508,"children":3509},{"style":2470},[3510],{"type":55,"value":2473},{"type":28,"tag":116,"props":3512,"children":3513},{"style":1858},[3514],{"type":55,"value":3515},"Tests",{"type":28,"tag":116,"props":3517,"children":3518},{"style":2470},[3519],{"type":55,"value":2473},{"type":28,"tag":116,"props":3521,"children":3522},{"style":1858},[3523],{"type":55,"value":2478},{"type":28,"tag":116,"props":3525,"children":3526},{"style":564},[3527],{"type":55,"value":593},{"type":28,"tag":116,"props":3529,"children":3530},{"style":1868},[3531],{"type":55,"value":3532},"\"tests/\"\n",{"type":28,"tag":116,"props":3534,"children":3535},{"class":553,"line":1385},[3536],{"type":28,"tag":116,"props":3537,"children":3538},{"style":564},[3539],{"type":55,"value":3407},{"type":28,"tag":116,"props":3541,"children":3542},{"class":553,"line":1398},[3543],{"type":28,"tag":116,"props":3544,"children":3545},{"style":564},[3546],{"type":55,"value":2423},{"type":28,"tag":116,"props":3548,"children":3549},{"class":553,"line":1411},[3550],{"type":28,"tag":116,"props":3551,"children":3552},{"style":564},[3553],{"type":55,"value":2880},{"type":28,"tag":534,"props":3555,"children":3557},{"className":2888,"code":3556,"language":2890,"meta":7,"style":7},"git tag v1.0.0\ngit push --tags\n",[3558],{"type":28,"tag":548,"props":3559,"children":3560},{"__ignoreMap":7},[3561,3578],{"type":28,"tag":116,"props":3562,"children":3563},{"class":553,"line":554},[3564,3568,3573],{"type":28,"tag":116,"props":3565,"children":3566},{"style":2900},[3567],{"type":55,"value":784},{"type":28,"tag":116,"props":3569,"children":3570},{"style":596},[3571],{"type":55,"value":3572}," tag",{"type":28,"tag":116,"props":3574,"children":3575},{"style":596},[3576],{"type":55,"value":3577}," v1.0.0\n",{"type":28,"tag":116,"props":3579,"children":3580},{"class":553,"line":271},[3581,3585,3590],{"type":28,"tag":116,"props":3582,"children":3583},{"style":2900},[3584],{"type":55,"value":784},{"type":28,"tag":116,"props":3586,"children":3587},{"style":596},[3588],{"type":55,"value":3589}," push",{"type":28,"tag":116,"props":3591,"children":3592},{"style":2170},[3593],{"type":55,"value":3594}," --tags\n",{"type":28,"tag":47,"props":3596,"children":3597},{},[3598],{"type":55,"value":3599},"Now this will work:",{"type":28,"tag":534,"props":3601,"children":3602},{"className":2888,"code":2889,"language":2890,"meta":7,"style":7},[3603],{"type":28,"tag":548,"props":3604,"children":3605},{"__ignoreMap":7},[3606],{"type":28,"tag":116,"props":3607,"children":3608},{"class":553,"line":554},[3609,3613,3617],{"type":28,"tag":116,"props":3610,"children":3611},{"style":2900},[3612],{"type":55,"value":1785},{"type":28,"tag":116,"props":3614,"children":3615},{"style":596},[3616],{"type":55,"value":2907},{"type":28,"tag":116,"props":3618,"children":3619},{"style":596},[3620],{"type":55,"value":2912},{"type":28,"tag":534,"props":3622,"children":3626},{"className":3623,"code":3624,"language":3625,"meta":7,"style":7},"language-terminaloutput shiki shiki-themes github-dark github-dark monokai","./composer.json has been updated                                                                                                            \nRunning composer update acme/sample-plugin\nLoading composer repositories with package information\nUpdating dependencies\nLock file operations: 1 install, 0 updates, 0 removals\n  - Locking acme/sample-plugin (1.0.0)\nWriting lock file\nInstalling dependencies from lock file (including require-dev)\nPackage operations: 1 install, 0 updates, 0 removals\n  - Syncing acme/sample-plugin (1.0.0) into cache\n  - Installing acme/sample-plugin (1.0.0): Cloning 294414deb2 from cache\nGenerating optimized autoload files\n\nRun composer recipes at any time to see the status of your Symfony recipes.\n\nExecuting script assets:install [OK]\n\nUsing version ^1.0 for acme/sample-plugin\n","terminaloutput",[3627],{"type":28,"tag":548,"props":3628,"children":3629},{"__ignoreMap":7},[3630,3638,3645,3653,3661,3668,3676,3683,3690,3697,3705,3713,3720,3727,3734,3741,3748,3755],{"type":28,"tag":116,"props":3631,"children":3632},{"class":553,"line":554},[3633],{"type":28,"tag":116,"props":3634,"children":3635},{},[3636],{"type":55,"value":3637},"./composer.json has been updated                                                                                                            \n",{"type":28,"tag":116,"props":3639,"children":3640},{"class":553,"line":271},[3641],{"type":28,"tag":116,"props":3642,"children":3643},{},[3644],{"type":55,"value":2986},{"type":28,"tag":116,"props":3646,"children":3647},{"class":553,"line":582},[3648],{"type":28,"tag":116,"props":3649,"children":3650},{},[3651],{"type":55,"value":3652},"Loading composer repositories with package information\n",{"type":28,"tag":116,"props":3654,"children":3655},{"class":553,"line":602},[3656],{"type":28,"tag":116,"props":3657,"children":3658},{},[3659],{"type":55,"value":3660},"Updating dependencies\n",{"type":28,"tag":116,"props":3662,"children":3663},{"class":553,"line":539},[3664],{"type":28,"tag":116,"props":3665,"children":3666},{},[3667],{"type":55,"value":3010},{"type":28,"tag":116,"props":3669,"children":3670},{"class":553,"line":540},[3671],{"type":28,"tag":116,"props":3672,"children":3673},{},[3674],{"type":55,"value":3675},"  - Locking acme/sample-plugin (1.0.0)\n",{"type":28,"tag":116,"props":3677,"children":3678},{"class":553,"line":541},[3679],{"type":28,"tag":116,"props":3680,"children":3681},{},[3682],{"type":55,"value":3026},{"type":28,"tag":116,"props":3684,"children":3685},{"class":553,"line":542},[3686],{"type":28,"tag":116,"props":3687,"children":3688},{},[3689],{"type":55,"value":3034},{"type":28,"tag":116,"props":3691,"children":3692},{"class":553,"line":543},[3693],{"type":28,"tag":116,"props":3694,"children":3695},{},[3696],{"type":55,"value":3042},{"type":28,"tag":116,"props":3698,"children":3699},{"class":553,"line":1203},[3700],{"type":28,"tag":116,"props":3701,"children":3702},{},[3703],{"type":55,"value":3704},"  - Syncing acme/sample-plugin (1.0.0) into cache\n",{"type":28,"tag":116,"props":3706,"children":3707},{"class":553,"line":1216},[3708],{"type":28,"tag":116,"props":3709,"children":3710},{},[3711],{"type":55,"value":3712},"  - Installing acme/sample-plugin (1.0.0): Cloning 294414deb2 from cache\n",{"type":28,"tag":116,"props":3714,"children":3715},{"class":553,"line":107},[3716],{"type":28,"tag":116,"props":3717,"children":3718},{},[3719],{"type":55,"value":3066},{"type":28,"tag":116,"props":3721,"children":3722},{"class":553,"line":1241},[3723],{"type":28,"tag":116,"props":3724,"children":3725},{"emptyLinePlaceholder":1271},[3726],{"type":55,"value":1274},{"type":28,"tag":116,"props":3728,"children":3729},{"class":553,"line":1254},[3730],{"type":28,"tag":116,"props":3731,"children":3732},{},[3733],{"type":55,"value":3081},{"type":28,"tag":116,"props":3735,"children":3736},{"class":553,"line":1267},[3737],{"type":28,"tag":116,"props":3738,"children":3739},{"emptyLinePlaceholder":1271},[3740],{"type":55,"value":1274},{"type":28,"tag":116,"props":3742,"children":3743},{"class":553,"line":1277},[3744],{"type":28,"tag":116,"props":3745,"children":3746},{},[3747],{"type":55,"value":3096},{"type":28,"tag":116,"props":3749,"children":3750},{"class":553,"line":1290},[3751],{"type":28,"tag":116,"props":3752,"children":3753},{"emptyLinePlaceholder":1271},[3754],{"type":55,"value":1274},{"type":28,"tag":116,"props":3756,"children":3757},{"class":553,"line":1303},[3758],{"type":28,"tag":116,"props":3759,"children":3760},{},[3761],{"type":55,"value":3762},"Using version ^1.0 for acme/sample-plugin\n",{"type":28,"tag":47,"props":3764,"children":3765},{},[3766,3768,3773],{"type":55,"value":3767},"This is better, but we are still using ",{"type":28,"tag":548,"props":3769,"children":3771},{"className":3770},[],[3772],{"type":55,"value":784},{"type":55,"value":3774}," to fetch the plugin. We can do better.",{"type":28,"tag":111,"props":3776,"children":3778},{"id":3777},"gitlab-package-registry",[3779],{"type":55,"value":3780},"GitLab Package registry",{"type":28,"tag":47,"props":3782,"children":3783},{},[3784,3786,3791],{"type":55,"value":3785},"Here is where the GitLab part starts. For more details refer to the ",{"type":28,"tag":520,"props":3787,"children":3789},{"href":3788},"https://docs.gitlab.com/18.3/user/packages/composer_repository/",[3790],{"type":55,"value":1749},{"type":55,"value":794},{"type":28,"tag":47,"props":3793,"children":3794},{},[3795],{"type":55,"value":3796},"At this point, it doesn't matter if our project in public or not, because we will need to authenticate with the package registry anyway.",{"type":28,"tag":47,"props":3798,"children":3799},{},[3800,3802,3807],{"type":55,"value":3801},"Let's release our ",{"type":28,"tag":548,"props":3803,"children":3805},{"className":3804},[],[3806],{"type":55,"value":3130},{"type":55,"value":3808}," tag as a composer package.",{"type":28,"tag":534,"props":3810,"children":3812},{"className":2888,"code":3811,"language":2890,"meta":7,"style":7},"curl --fail-with-body --data tag=v1.0.0 \"https://__token__:\u003Cpersonal-access-token>@\u003CDOMAIN-NAME>/api/v4/projects/\u003Cproject_id>/packages/composer\"\n",[3813],{"type":28,"tag":548,"props":3814,"children":3815},{"__ignoreMap":7},[3816],{"type":28,"tag":116,"props":3817,"children":3818},{"class":553,"line":554},[3819,3824,3829,3834,3839],{"type":28,"tag":116,"props":3820,"children":3821},{"style":2900},[3822],{"type":55,"value":3823},"curl",{"type":28,"tag":116,"props":3825,"children":3826},{"style":2170},[3827],{"type":55,"value":3828}," --fail-with-body",{"type":28,"tag":116,"props":3830,"children":3831},{"style":2170},[3832],{"type":55,"value":3833}," --data",{"type":28,"tag":116,"props":3835,"children":3836},{"style":596},[3837],{"type":55,"value":3838}," tag=v1.0.0",{"type":28,"tag":116,"props":3840,"children":3841},{"style":596},[3842],{"type":55,"value":3843}," \"https://__token__:\u003Cpersonal-access-token>@\u003CDOMAIN-NAME>/api/v4/projects/\u003Cproject_id>/packages/composer\"\n",{"type":28,"tag":47,"props":3845,"children":3846},{},[3847],{"type":55,"value":3848},"Now we need to update the repository information:",{"type":28,"tag":534,"props":3850,"children":3853},{"className":1833,"code":3851,"filename":1835,"highlights":3852,"language":384,"meta":7,"style":7},"{\n  \"name\": \"shopware/production\",\n  \"license\": \"MIT\",\n  \"type\": \"project\",\n  \"require\": {\n    \"composer-runtime-api\": \"^2.0\",\n    \"acme/sample-plugin\": \"^1.0\",\n    \"shopware/administration\": \"*\",\n    \"shopware/core\": \"6.6.10.2\",\n    \"shopware/elasticsearch\": \"*\",\n    \"shopware/storefront\": \"*\",\n    \"symfony/flex\": \"~2\"\n  },\n  \"repositories\": [\n    {\n      \"type\": \"path\",\n      \"url\": \"custom/plugins/*\",\n      \"options\": {\n        \"symlink\": true\n      }\n    },\n    {\n      \"type\": \"path\",\n      \"url\": \"custom/plugins/*/packages/*\",\n      \"options\": {\n        \"symlink\": true\n      }\n    },\n    {\n      \"type\": \"path\",\n      \"url\": \"custom/static-plugins/*\",\n      \"options\": {\n        \"symlink\": true\n      }\n    },\n    {\n      \"type\": \"composer\",\n      \"url\": \"https://\u003CDOMAIN-NAME>/api/v4/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\"\n    }\n  ],\n  \"autoload\": {\n    \"psr-4\": {\n      \"App\\\\\": \"src/\"\n    }\n  },\n  \"prefer-stable\": true,\n  \"config\": {\n    \"allow-plugins\": {\n      \"symfony/flex\": true,\n      \"symfony/runtime\": true\n    },\n    \"optimize-autoloader\": true,\n    \"sort-packages\": true\n  },\n  \"scripts\": {\n    \"auto-scripts\": {\n      \"assets:install\": \"symfony-cmd\"\n    },\n    \"post-install-cmd\": [\n      \"@auto-scripts\"\n    ],\n    \"post-update-cmd\": [\n      \"@auto-scripts\"\n    ]\n  },\n  \"extra\": {\n    \"symfony\": {\n      \"allow-contrib\": true,\n      \"endpoint\": [\n        \"https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json\",\n        \"flex://defaults\"\n      ]\n    }\n  }\n}\n",[1837,1838,1839,1840],[3854],{"type":28,"tag":548,"props":3855,"children":3856},{"__ignoreMap":7},[3857,3864,3883,3902,3921,3932,3951,3970,3989,4008,4027,4046,4061,4068,4079,4086,4105,4124,4135,4150,4157,4164,4171,4190,4209,4220,4235,4242,4249,4256,4275,4294,4305,4320,4327,4334,4342,4363,4380,4388,4395,4406,4417,4440,4447,4454,4473,4484,4495,4514,4529,4536,4555,4570,4577,4588,4599,4614,4621,4632,4639,4646,4657,4664,4671,4678,4689,4700,4719,4730,4741,4748,4755,4762,4769],{"type":28,"tag":116,"props":3858,"children":3859},{"class":553,"line":554},[3860],{"type":28,"tag":116,"props":3861,"children":3862},{"style":564},[3863],{"type":55,"value":1852},{"type":28,"tag":116,"props":3865,"children":3866},{"class":553,"line":271},[3867,3871,3875,3879],{"type":28,"tag":116,"props":3868,"children":3869},{"style":1858},[3870],{"type":55,"value":1861},{"type":28,"tag":116,"props":3872,"children":3873},{"style":564},[3874],{"type":55,"value":593},{"type":28,"tag":116,"props":3876,"children":3877},{"style":1868},[3878],{"type":55,"value":1871},{"type":28,"tag":116,"props":3880,"children":3881},{"style":564},[3882],{"type":55,"value":1876},{"type":28,"tag":116,"props":3884,"children":3885},{"class":553,"line":582},[3886,3890,3894,3898],{"type":28,"tag":116,"props":3887,"children":3888},{"style":1858},[3889],{"type":55,"value":1884},{"type":28,"tag":116,"props":3891,"children":3892},{"style":564},[3893],{"type":55,"value":593},{"type":28,"tag":116,"props":3895,"children":3896},{"style":1868},[3897],{"type":55,"value":1893},{"type":28,"tag":116,"props":3899,"children":3900},{"style":564},[3901],{"type":55,"value":1876},{"type":28,"tag":116,"props":3903,"children":3904},{"class":553,"line":602},[3905,3909,3913,3917],{"type":28,"tag":116,"props":3906,"children":3907},{"style":1858},[3908],{"type":55,"value":1905},{"type":28,"tag":116,"props":3910,"children":3911},{"style":564},[3912],{"type":55,"value":593},{"type":28,"tag":116,"props":3914,"children":3915},{"style":1868},[3916],{"type":55,"value":1914},{"type":28,"tag":116,"props":3918,"children":3919},{"style":564},[3920],{"type":55,"value":1876},{"type":28,"tag":116,"props":3922,"children":3923},{"class":553,"line":539},[3924,3928],{"type":28,"tag":116,"props":3925,"children":3926},{"style":1858},[3927],{"type":55,"value":1926},{"type":28,"tag":116,"props":3929,"children":3930},{"style":564},[3931],{"type":55,"value":1931},{"type":28,"tag":116,"props":3933,"children":3934},{"class":553,"line":540},[3935,3939,3943,3947],{"type":28,"tag":116,"props":3936,"children":3937},{"style":1858},[3938],{"type":55,"value":1939},{"type":28,"tag":116,"props":3940,"children":3941},{"style":564},[3942],{"type":55,"value":593},{"type":28,"tag":116,"props":3944,"children":3945},{"style":1868},[3946],{"type":55,"value":1948},{"type":28,"tag":116,"props":3948,"children":3949},{"style":564},[3950],{"type":55,"value":1876},{"type":28,"tag":116,"props":3952,"children":3953},{"class":553,"line":541},[3954,3958,3962,3966],{"type":28,"tag":116,"props":3955,"children":3956},{"style":1858},[3957],{"type":55,"value":1960},{"type":28,"tag":116,"props":3959,"children":3960},{"style":564},[3961],{"type":55,"value":593},{"type":28,"tag":116,"props":3963,"children":3964},{"style":1868},[3965],{"type":55,"value":1969},{"type":28,"tag":116,"props":3967,"children":3968},{"style":564},[3969],{"type":55,"value":1876},{"type":28,"tag":116,"props":3971,"children":3972},{"class":553,"line":542},[3973,3977,3981,3985],{"type":28,"tag":116,"props":3974,"children":3975},{"style":1858},[3976],{"type":55,"value":1981},{"type":28,"tag":116,"props":3978,"children":3979},{"style":564},[3980],{"type":55,"value":593},{"type":28,"tag":116,"props":3982,"children":3983},{"style":1868},[3984],{"type":55,"value":1990},{"type":28,"tag":116,"props":3986,"children":3987},{"style":564},[3988],{"type":55,"value":1876},{"type":28,"tag":116,"props":3990,"children":3991},{"class":553,"line":543},[3992,3996,4000,4004],{"type":28,"tag":116,"props":3993,"children":3994},{"style":1858},[3995],{"type":55,"value":2002},{"type":28,"tag":116,"props":3997,"children":3998},{"style":564},[3999],{"type":55,"value":593},{"type":28,"tag":116,"props":4001,"children":4002},{"style":1868},[4003],{"type":55,"value":2011},{"type":28,"tag":116,"props":4005,"children":4006},{"style":564},[4007],{"type":55,"value":1876},{"type":28,"tag":116,"props":4009,"children":4010},{"class":553,"line":1203},[4011,4015,4019,4023],{"type":28,"tag":116,"props":4012,"children":4013},{"style":1858},[4014],{"type":55,"value":2023},{"type":28,"tag":116,"props":4016,"children":4017},{"style":564},[4018],{"type":55,"value":593},{"type":28,"tag":116,"props":4020,"children":4021},{"style":1868},[4022],{"type":55,"value":1990},{"type":28,"tag":116,"props":4024,"children":4025},{"style":564},[4026],{"type":55,"value":1876},{"type":28,"tag":116,"props":4028,"children":4029},{"class":553,"line":1216},[4030,4034,4038,4042],{"type":28,"tag":116,"props":4031,"children":4032},{"style":1858},[4033],{"type":55,"value":2043},{"type":28,"tag":116,"props":4035,"children":4036},{"style":564},[4037],{"type":55,"value":593},{"type":28,"tag":116,"props":4039,"children":4040},{"style":1868},[4041],{"type":55,"value":1990},{"type":28,"tag":116,"props":4043,"children":4044},{"style":564},[4045],{"type":55,"value":1876},{"type":28,"tag":116,"props":4047,"children":4048},{"class":553,"line":107},[4049,4053,4057],{"type":28,"tag":116,"props":4050,"children":4051},{"style":1858},[4052],{"type":55,"value":2063},{"type":28,"tag":116,"props":4054,"children":4055},{"style":564},[4056],{"type":55,"value":593},{"type":28,"tag":116,"props":4058,"children":4059},{"style":1868},[4060],{"type":55,"value":2072},{"type":28,"tag":116,"props":4062,"children":4063},{"class":553,"line":1241},[4064],{"type":28,"tag":116,"props":4065,"children":4066},{"style":564},[4067],{"type":55,"value":2080},{"type":28,"tag":116,"props":4069,"children":4070},{"class":553,"line":1254},[4071,4075],{"type":28,"tag":116,"props":4072,"children":4073},{"style":1858},[4074],{"type":55,"value":2088},{"type":28,"tag":116,"props":4076,"children":4077},{"style":564},[4078],{"type":55,"value":2093},{"type":28,"tag":116,"props":4080,"children":4081},{"class":553,"line":1267},[4082],{"type":28,"tag":116,"props":4083,"children":4084},{"style":564},[4085],{"type":55,"value":2101},{"type":28,"tag":116,"props":4087,"children":4088},{"class":553,"line":1277},[4089,4093,4097,4101],{"type":28,"tag":116,"props":4090,"children":4091},{"style":1858},[4092],{"type":55,"value":2109},{"type":28,"tag":116,"props":4094,"children":4095},{"style":564},[4096],{"type":55,"value":593},{"type":28,"tag":116,"props":4098,"children":4099},{"style":1868},[4100],{"type":55,"value":2118},{"type":28,"tag":116,"props":4102,"children":4103},{"style":564},[4104],{"type":55,"value":1876},{"type":28,"tag":116,"props":4106,"children":4107},{"class":553,"line":1290},[4108,4112,4116,4120],{"type":28,"tag":116,"props":4109,"children":4110},{"style":1858},[4111],{"type":55,"value":2130},{"type":28,"tag":116,"props":4113,"children":4114},{"style":564},[4115],{"type":55,"value":593},{"type":28,"tag":116,"props":4117,"children":4118},{"style":1868},[4119],{"type":55,"value":2139},{"type":28,"tag":116,"props":4121,"children":4122},{"style":564},[4123],{"type":55,"value":1876},{"type":28,"tag":116,"props":4125,"children":4126},{"class":553,"line":1303},[4127,4131],{"type":28,"tag":116,"props":4128,"children":4129},{"style":1858},[4130],{"type":55,"value":2151},{"type":28,"tag":116,"props":4132,"children":4133},{"style":564},[4134],{"type":55,"value":1931},{"type":28,"tag":116,"props":4136,"children":4137},{"class":553,"line":1312},[4138,4142,4146],{"type":28,"tag":116,"props":4139,"children":4140},{"style":1858},[4141],{"type":55,"value":2163},{"type":28,"tag":116,"props":4143,"children":4144},{"style":564},[4145],{"type":55,"value":593},{"type":28,"tag":116,"props":4147,"children":4148},{"style":2170},[4149],{"type":55,"value":2173},{"type":28,"tag":116,"props":4151,"children":4152},{"class":553,"line":1325},[4153],{"type":28,"tag":116,"props":4154,"children":4155},{"style":564},[4156],{"type":55,"value":2181},{"type":28,"tag":116,"props":4158,"children":4159},{"class":553,"line":1338},[4160],{"type":28,"tag":116,"props":4161,"children":4162},{"style":564},[4163],{"type":55,"value":2189},{"type":28,"tag":116,"props":4165,"children":4166},{"class":553,"line":1351},[4167],{"type":28,"tag":116,"props":4168,"children":4169},{"style":564},[4170],{"type":55,"value":2101},{"type":28,"tag":116,"props":4172,"children":4173},{"class":553,"line":1359},[4174,4178,4182,4186],{"type":28,"tag":116,"props":4175,"children":4176},{"style":1858},[4177],{"type":55,"value":2109},{"type":28,"tag":116,"props":4179,"children":4180},{"style":564},[4181],{"type":55,"value":593},{"type":28,"tag":116,"props":4183,"children":4184},{"style":1868},[4185],{"type":55,"value":2118},{"type":28,"tag":116,"props":4187,"children":4188},{"style":564},[4189],{"type":55,"value":1876},{"type":28,"tag":116,"props":4191,"children":4192},{"class":553,"line":1372},[4193,4197,4201,4205],{"type":28,"tag":116,"props":4194,"children":4195},{"style":1858},[4196],{"type":55,"value":2130},{"type":28,"tag":116,"props":4198,"children":4199},{"style":564},[4200],{"type":55,"value":593},{"type":28,"tag":116,"props":4202,"children":4203},{"style":1868},[4204],{"type":55,"value":2231},{"type":28,"tag":116,"props":4206,"children":4207},{"style":564},[4208],{"type":55,"value":1876},{"type":28,"tag":116,"props":4210,"children":4211},{"class":553,"line":1385},[4212,4216],{"type":28,"tag":116,"props":4213,"children":4214},{"style":1858},[4215],{"type":55,"value":2151},{"type":28,"tag":116,"props":4217,"children":4218},{"style":564},[4219],{"type":55,"value":1931},{"type":28,"tag":116,"props":4221,"children":4222},{"class":553,"line":1398},[4223,4227,4231],{"type":28,"tag":116,"props":4224,"children":4225},{"style":1858},[4226],{"type":55,"value":2163},{"type":28,"tag":116,"props":4228,"children":4229},{"style":564},[4230],{"type":55,"value":593},{"type":28,"tag":116,"props":4232,"children":4233},{"style":2170},[4234],{"type":55,"value":2173},{"type":28,"tag":116,"props":4236,"children":4237},{"class":553,"line":1411},[4238],{"type":28,"tag":116,"props":4239,"children":4240},{"style":564},[4241],{"type":55,"value":2181},{"type":28,"tag":116,"props":4243,"children":4244},{"class":553,"line":1424},[4245],{"type":28,"tag":116,"props":4246,"children":4247},{"style":564},[4248],{"type":55,"value":2189},{"type":28,"tag":116,"props":4250,"children":4251},{"class":553,"line":2278},[4252],{"type":28,"tag":116,"props":4253,"children":4254},{"style":564},[4255],{"type":55,"value":2101},{"type":28,"tag":116,"props":4257,"children":4258},{"class":553,"line":2286},[4259,4263,4267,4271],{"type":28,"tag":116,"props":4260,"children":4261},{"style":1858},[4262],{"type":55,"value":2109},{"type":28,"tag":116,"props":4264,"children":4265},{"style":564},[4266],{"type":55,"value":593},{"type":28,"tag":116,"props":4268,"children":4269},{"style":1868},[4270],{"type":55,"value":2118},{"type":28,"tag":116,"props":4272,"children":4273},{"style":564},[4274],{"type":55,"value":1876},{"type":28,"tag":116,"props":4276,"children":4277},{"class":553,"line":2306},[4278,4282,4286,4290],{"type":28,"tag":116,"props":4279,"children":4280},{"style":1858},[4281],{"type":55,"value":2130},{"type":28,"tag":116,"props":4283,"children":4284},{"style":564},[4285],{"type":55,"value":593},{"type":28,"tag":116,"props":4287,"children":4288},{"style":1868},[4289],{"type":55,"value":2320},{"type":28,"tag":116,"props":4291,"children":4292},{"style":564},[4293],{"type":55,"value":1876},{"type":28,"tag":116,"props":4295,"children":4296},{"class":553,"line":2327},[4297,4301],{"type":28,"tag":116,"props":4298,"children":4299},{"style":1858},[4300],{"type":55,"value":2151},{"type":28,"tag":116,"props":4302,"children":4303},{"style":564},[4304],{"type":55,"value":1931},{"type":28,"tag":116,"props":4306,"children":4307},{"class":553,"line":2339},[4308,4312,4316],{"type":28,"tag":116,"props":4309,"children":4310},{"style":1858},[4311],{"type":55,"value":2163},{"type":28,"tag":116,"props":4313,"children":4314},{"style":564},[4315],{"type":55,"value":593},{"type":28,"tag":116,"props":4317,"children":4318},{"style":2170},[4319],{"type":55,"value":2173},{"type":28,"tag":116,"props":4321,"children":4322},{"class":553,"line":2355},[4323],{"type":28,"tag":116,"props":4324,"children":4325},{"style":564},[4326],{"type":55,"value":2181},{"type":28,"tag":116,"props":4328,"children":4329},{"class":553,"line":2363},[4330],{"type":28,"tag":116,"props":4331,"children":4332},{"style":564},[4333],{"type":55,"value":2189},{"type":28,"tag":116,"props":4335,"children":4337},{"class":4336,"line":1837},[553,616],[4338],{"type":28,"tag":116,"props":4339,"children":4340},{"style":564},[4341],{"type":55,"value":2101},{"type":28,"tag":116,"props":4343,"children":4345},{"class":4344,"line":1838},[553,616],[4346,4350,4354,4359],{"type":28,"tag":116,"props":4347,"children":4348},{"style":1858},[4349],{"type":55,"value":2109},{"type":28,"tag":116,"props":4351,"children":4352},{"style":564},[4353],{"type":55,"value":593},{"type":28,"tag":116,"props":4355,"children":4356},{"style":1868},[4357],{"type":55,"value":4358},"\"composer\"",{"type":28,"tag":116,"props":4360,"children":4361},{"style":564},[4362],{"type":55,"value":1876},{"type":28,"tag":116,"props":4364,"children":4366},{"class":4365,"line":1839},[553,616],[4367,4371,4375],{"type":28,"tag":116,"props":4368,"children":4369},{"style":1858},[4370],{"type":55,"value":2130},{"type":28,"tag":116,"props":4372,"children":4373},{"style":564},[4374],{"type":55,"value":593},{"type":28,"tag":116,"props":4376,"children":4377},{"style":1868},[4378],{"type":55,"value":4379},"\"https://\u003CDOMAIN-NAME>/api/v4/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\"\n",{"type":28,"tag":116,"props":4381,"children":4383},{"class":4382,"line":1840},[553,616],[4384],{"type":28,"tag":116,"props":4385,"children":4386},{"style":564},[4387],{"type":55,"value":2423},{"type":28,"tag":116,"props":4389,"children":4390},{"class":553,"line":2426},[4391],{"type":28,"tag":116,"props":4392,"children":4393},{"style":564},[4394],{"type":55,"value":2432},{"type":28,"tag":116,"props":4396,"children":4397},{"class":553,"line":2435},[4398,4402],{"type":28,"tag":116,"props":4399,"children":4400},{"style":1858},[4401],{"type":55,"value":2441},{"type":28,"tag":116,"props":4403,"children":4404},{"style":564},[4405],{"type":55,"value":1931},{"type":28,"tag":116,"props":4407,"children":4408},{"class":553,"line":2448},[4409,4413],{"type":28,"tag":116,"props":4410,"children":4411},{"style":1858},[4412],{"type":55,"value":2454},{"type":28,"tag":116,"props":4414,"children":4415},{"style":564},[4416],{"type":55,"value":1931},{"type":28,"tag":116,"props":4418,"children":4419},{"class":553,"line":2461},[4420,4424,4428,4432,4436],{"type":28,"tag":116,"props":4421,"children":4422},{"style":1858},[4423],{"type":55,"value":2467},{"type":28,"tag":116,"props":4425,"children":4426},{"style":2470},[4427],{"type":55,"value":2473},{"type":28,"tag":116,"props":4429,"children":4430},{"style":1858},[4431],{"type":55,"value":2478},{"type":28,"tag":116,"props":4433,"children":4434},{"style":564},[4435],{"type":55,"value":593},{"type":28,"tag":116,"props":4437,"children":4438},{"style":1868},[4439],{"type":55,"value":2487},{"type":28,"tag":116,"props":4441,"children":4442},{"class":553,"line":2490},[4443],{"type":28,"tag":116,"props":4444,"children":4445},{"style":564},[4446],{"type":55,"value":2423},{"type":28,"tag":116,"props":4448,"children":4449},{"class":553,"line":2498},[4450],{"type":28,"tag":116,"props":4451,"children":4452},{"style":564},[4453],{"type":55,"value":2080},{"type":28,"tag":116,"props":4455,"children":4456},{"class":553,"line":2506},[4457,4461,4465,4469],{"type":28,"tag":116,"props":4458,"children":4459},{"style":1858},[4460],{"type":55,"value":2512},{"type":28,"tag":116,"props":4462,"children":4463},{"style":564},[4464],{"type":55,"value":593},{"type":28,"tag":116,"props":4466,"children":4467},{"style":2170},[4468],{"type":55,"value":102},{"type":28,"tag":116,"props":4470,"children":4471},{"style":564},[4472],{"type":55,"value":1876},{"type":28,"tag":116,"props":4474,"children":4475},{"class":553,"line":2527},[4476,4480],{"type":28,"tag":116,"props":4477,"children":4478},{"style":1858},[4479],{"type":55,"value":2533},{"type":28,"tag":116,"props":4481,"children":4482},{"style":564},[4483],{"type":55,"value":1931},{"type":28,"tag":116,"props":4485,"children":4486},{"class":553,"line":2540},[4487,4491],{"type":28,"tag":116,"props":4488,"children":4489},{"style":1858},[4490],{"type":55,"value":2546},{"type":28,"tag":116,"props":4492,"children":4493},{"style":564},[4494],{"type":55,"value":1931},{"type":28,"tag":116,"props":4496,"children":4497},{"class":553,"line":2553},[4498,4502,4506,4510],{"type":28,"tag":116,"props":4499,"children":4500},{"style":1858},[4501],{"type":55,"value":2559},{"type":28,"tag":116,"props":4503,"children":4504},{"style":564},[4505],{"type":55,"value":593},{"type":28,"tag":116,"props":4507,"children":4508},{"style":2170},[4509],{"type":55,"value":102},{"type":28,"tag":116,"props":4511,"children":4512},{"style":564},[4513],{"type":55,"value":1876},{"type":28,"tag":116,"props":4515,"children":4516},{"class":553,"line":2574},[4517,4521,4525],{"type":28,"tag":116,"props":4518,"children":4519},{"style":1858},[4520],{"type":55,"value":2580},{"type":28,"tag":116,"props":4522,"children":4523},{"style":564},[4524],{"type":55,"value":593},{"type":28,"tag":116,"props":4526,"children":4527},{"style":2170},[4528],{"type":55,"value":2173},{"type":28,"tag":116,"props":4530,"children":4531},{"class":553,"line":2591},[4532],{"type":28,"tag":116,"props":4533,"children":4534},{"style":564},[4535],{"type":55,"value":2189},{"type":28,"tag":116,"props":4537,"children":4538},{"class":553,"line":2599},[4539,4543,4547,4551],{"type":28,"tag":116,"props":4540,"children":4541},{"style":1858},[4542],{"type":55,"value":2605},{"type":28,"tag":116,"props":4544,"children":4545},{"style":564},[4546],{"type":55,"value":593},{"type":28,"tag":116,"props":4548,"children":4549},{"style":2170},[4550],{"type":55,"value":102},{"type":28,"tag":116,"props":4552,"children":4553},{"style":564},[4554],{"type":55,"value":1876},{"type":28,"tag":116,"props":4556,"children":4557},{"class":553,"line":2620},[4558,4562,4566],{"type":28,"tag":116,"props":4559,"children":4560},{"style":1858},[4561],{"type":55,"value":2626},{"type":28,"tag":116,"props":4563,"children":4564},{"style":564},[4565],{"type":55,"value":593},{"type":28,"tag":116,"props":4567,"children":4568},{"style":2170},[4569],{"type":55,"value":2173},{"type":28,"tag":116,"props":4571,"children":4572},{"class":553,"line":2637},[4573],{"type":28,"tag":116,"props":4574,"children":4575},{"style":564},[4576],{"type":55,"value":2080},{"type":28,"tag":116,"props":4578,"children":4579},{"class":553,"line":2645},[4580,4584],{"type":28,"tag":116,"props":4581,"children":4582},{"style":1858},[4583],{"type":55,"value":2651},{"type":28,"tag":116,"props":4585,"children":4586},{"style":564},[4587],{"type":55,"value":1931},{"type":28,"tag":116,"props":4589,"children":4590},{"class":553,"line":2658},[4591,4595],{"type":28,"tag":116,"props":4592,"children":4593},{"style":1858},[4594],{"type":55,"value":2664},{"type":28,"tag":116,"props":4596,"children":4597},{"style":564},[4598],{"type":55,"value":1931},{"type":28,"tag":116,"props":4600,"children":4601},{"class":553,"line":2671},[4602,4606,4610],{"type":28,"tag":116,"props":4603,"children":4604},{"style":1858},[4605],{"type":55,"value":2677},{"type":28,"tag":116,"props":4607,"children":4608},{"style":564},[4609],{"type":55,"value":593},{"type":28,"tag":116,"props":4611,"children":4612},{"style":1868},[4613],{"type":55,"value":2686},{"type":28,"tag":116,"props":4615,"children":4616},{"class":553,"line":2689},[4617],{"type":28,"tag":116,"props":4618,"children":4619},{"style":564},[4620],{"type":55,"value":2189},{"type":28,"tag":116,"props":4622,"children":4623},{"class":553,"line":2697},[4624,4628],{"type":28,"tag":116,"props":4625,"children":4626},{"style":1858},[4627],{"type":55,"value":2703},{"type":28,"tag":116,"props":4629,"children":4630},{"style":564},[4631],{"type":55,"value":2093},{"type":28,"tag":116,"props":4633,"children":4634},{"class":553,"line":2710},[4635],{"type":28,"tag":116,"props":4636,"children":4637},{"style":1868},[4638],{"type":55,"value":2716},{"type":28,"tag":116,"props":4640,"children":4641},{"class":553,"line":2719},[4642],{"type":28,"tag":116,"props":4643,"children":4644},{"style":564},[4645],{"type":55,"value":2725},{"type":28,"tag":116,"props":4647,"children":4648},{"class":553,"line":2728},[4649,4653],{"type":28,"tag":116,"props":4650,"children":4651},{"style":1858},[4652],{"type":55,"value":2734},{"type":28,"tag":116,"props":4654,"children":4655},{"style":564},[4656],{"type":55,"value":2093},{"type":28,"tag":116,"props":4658,"children":4659},{"class":553,"line":2741},[4660],{"type":28,"tag":116,"props":4661,"children":4662},{"style":1868},[4663],{"type":55,"value":2716},{"type":28,"tag":116,"props":4665,"children":4666},{"class":553,"line":2749},[4667],{"type":28,"tag":116,"props":4668,"children":4669},{"style":564},[4670],{"type":55,"value":2755},{"type":28,"tag":116,"props":4672,"children":4673},{"class":553,"line":2758},[4674],{"type":28,"tag":116,"props":4675,"children":4676},{"style":564},[4677],{"type":55,"value":2080},{"type":28,"tag":116,"props":4679,"children":4680},{"class":553,"line":2766},[4681,4685],{"type":28,"tag":116,"props":4682,"children":4683},{"style":1858},[4684],{"type":55,"value":2772},{"type":28,"tag":116,"props":4686,"children":4687},{"style":564},[4688],{"type":55,"value":1931},{"type":28,"tag":116,"props":4690,"children":4691},{"class":553,"line":2779},[4692,4696],{"type":28,"tag":116,"props":4693,"children":4694},{"style":1858},[4695],{"type":55,"value":2785},{"type":28,"tag":116,"props":4697,"children":4698},{"style":564},[4699],{"type":55,"value":1931},{"type":28,"tag":116,"props":4701,"children":4702},{"class":553,"line":2792},[4703,4707,4711,4715],{"type":28,"tag":116,"props":4704,"children":4705},{"style":1858},[4706],{"type":55,"value":2798},{"type":28,"tag":116,"props":4708,"children":4709},{"style":564},[4710],{"type":55,"value":593},{"type":28,"tag":116,"props":4712,"children":4713},{"style":2170},[4714],{"type":55,"value":102},{"type":28,"tag":116,"props":4716,"children":4717},{"style":564},[4718],{"type":55,"value":1876},{"type":28,"tag":116,"props":4720,"children":4721},{"class":553,"line":2813},[4722,4726],{"type":28,"tag":116,"props":4723,"children":4724},{"style":1858},[4725],{"type":55,"value":2819},{"type":28,"tag":116,"props":4727,"children":4728},{"style":564},[4729],{"type":55,"value":2093},{"type":28,"tag":116,"props":4731,"children":4732},{"class":553,"line":2826},[4733,4737],{"type":28,"tag":116,"props":4734,"children":4735},{"style":1868},[4736],{"type":55,"value":2832},{"type":28,"tag":116,"props":4738,"children":4739},{"style":564},[4740],{"type":55,"value":1876},{"type":28,"tag":116,"props":4742,"children":4743},{"class":553,"line":2839},[4744],{"type":28,"tag":116,"props":4745,"children":4746},{"style":1868},[4747],{"type":55,"value":2845},{"type":28,"tag":116,"props":4749,"children":4750},{"class":553,"line":2848},[4751],{"type":28,"tag":116,"props":4752,"children":4753},{"style":564},[4754],{"type":55,"value":2854},{"type":28,"tag":116,"props":4756,"children":4757},{"class":553,"line":2857},[4758],{"type":28,"tag":116,"props":4759,"children":4760},{"style":564},[4761],{"type":55,"value":2423},{"type":28,"tag":116,"props":4763,"children":4764},{"class":553,"line":2865},[4765],{"type":28,"tag":116,"props":4766,"children":4767},{"style":564},[4768],{"type":55,"value":2871},{"type":28,"tag":116,"props":4770,"children":4771},{"class":553,"line":2874},[4772],{"type":28,"tag":116,"props":4773,"children":4774},{"style":564},[4775],{"type":55,"value":2880},{"type":28,"tag":47,"props":4777,"children":4778},{},[4779],{"type":55,"value":4780},"or by using the CLI:",{"type":28,"tag":534,"props":4782,"children":4784},{"className":2888,"code":4783,"language":2890,"meta":7,"style":7},"composer config repositories.\u003Cgroup_id> composer https://\u003CDOMAIN-NAME>/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\n",[4785],{"type":28,"tag":548,"props":4786,"children":4787},{"__ignoreMap":7},[4788],{"type":28,"tag":116,"props":4789,"children":4790},{"class":553,"line":554},[4791,4795,4800,4805,4811,4816,4821,4826,4831,4836,4840,4845,4850,4854,4859,4863,4867,4871,4875],{"type":28,"tag":116,"props":4792,"children":4793},{"style":2900},[4794],{"type":55,"value":1785},{"type":28,"tag":116,"props":4796,"children":4797},{"style":596},[4798],{"type":55,"value":4799}," config",{"type":28,"tag":116,"props":4801,"children":4802},{"style":596},[4803],{"type":55,"value":4804}," repositories.",{"type":28,"tag":116,"props":4806,"children":4808},{"style":4807},"--shiki-default:#F97583;--shiki-dark:#F97583;--shiki-sepia:#F92672",[4809],{"type":55,"value":4810},"\u003C",{"type":28,"tag":116,"props":4812,"children":4813},{"style":596},[4814],{"type":55,"value":4815},"group_i",{"type":28,"tag":116,"props":4817,"children":4818},{"style":564},[4819],{"type":55,"value":4820},"d",{"type":28,"tag":116,"props":4822,"children":4823},{"style":4807},[4824],{"type":55,"value":4825},">",{"type":28,"tag":116,"props":4827,"children":4828},{"style":596},[4829],{"type":55,"value":4830}," composer",{"type":28,"tag":116,"props":4832,"children":4833},{"style":596},[4834],{"type":55,"value":4835}," https://",{"type":28,"tag":116,"props":4837,"children":4838},{"style":4807},[4839],{"type":55,"value":4810},{"type":28,"tag":116,"props":4841,"children":4842},{"style":596},[4843],{"type":55,"value":4844},"DOMAIN-NAM",{"type":28,"tag":116,"props":4846,"children":4847},{"style":564},[4848],{"type":55,"value":4849},"E",{"type":28,"tag":116,"props":4851,"children":4852},{"style":4807},[4853],{"type":55,"value":4825},{"type":28,"tag":116,"props":4855,"children":4856},{"style":596},[4857],{"type":55,"value":4858},"/api/v4/group/",{"type":28,"tag":116,"props":4860,"children":4861},{"style":4807},[4862],{"type":55,"value":4810},{"type":28,"tag":116,"props":4864,"children":4865},{"style":596},[4866],{"type":55,"value":4815},{"type":28,"tag":116,"props":4868,"children":4869},{"style":564},[4870],{"type":55,"value":4820},{"type":28,"tag":116,"props":4872,"children":4873},{"style":4807},[4874],{"type":55,"value":4825},{"type":28,"tag":116,"props":4876,"children":4877},{"style":596},[4878],{"type":55,"value":4879},"/-/packages/composer/packages.json\n",{"type":28,"tag":47,"props":4881,"children":4882},{},[4883],{"type":55,"value":4884},"And setup GitLab credentials:",{"type":28,"tag":534,"props":4886,"children":4888},{"className":2888,"code":4887,"language":2890,"meta":7,"style":7},"composer config gitlab-token.\u003CDOMAIN-NAME> \u003Cpersonal_access_token>\n",[4889],{"type":28,"tag":548,"props":4890,"children":4891},{"__ignoreMap":7},[4892],{"type":28,"tag":116,"props":4893,"children":4894},{"class":553,"line":554},[4895,4899,4903,4908,4912,4916,4920,4924,4929,4934,4939],{"type":28,"tag":116,"props":4896,"children":4897},{"style":2900},[4898],{"type":55,"value":1785},{"type":28,"tag":116,"props":4900,"children":4901},{"style":596},[4902],{"type":55,"value":4799},{"type":28,"tag":116,"props":4904,"children":4905},{"style":596},[4906],{"type":55,"value":4907}," gitlab-token.",{"type":28,"tag":116,"props":4909,"children":4910},{"style":4807},[4911],{"type":55,"value":4810},{"type":28,"tag":116,"props":4913,"children":4914},{"style":596},[4915],{"type":55,"value":4844},{"type":28,"tag":116,"props":4917,"children":4918},{"style":564},[4919],{"type":55,"value":4849},{"type":28,"tag":116,"props":4921,"children":4922},{"style":4807},[4923],{"type":55,"value":4825},{"type":28,"tag":116,"props":4925,"children":4926},{"style":4807},[4927],{"type":55,"value":4928}," \u003C",{"type":28,"tag":116,"props":4930,"children":4931},{"style":596},[4932],{"type":55,"value":4933},"personal_access_toke",{"type":28,"tag":116,"props":4935,"children":4936},{"style":564},[4937],{"type":55,"value":4938},"n",{"type":28,"tag":116,"props":4940,"children":4941},{"style":4807},[4942],{"type":55,"value":4943},">\n",{"type":28,"tag":47,"props":4945,"children":4946},{},[4947,4949,4954],{"type":55,"value":4948},"You can read more about this process in the ",{"type":28,"tag":520,"props":4950,"children":4952},{"href":4951},"https://docs.gitlab.com/user/packages/composer_repository/#install-a-composer-package",[4953],{"type":55,"value":1749},{"type":55,"value":794},{"type":28,"tag":47,"props":4956,"children":4957},{},[4958],{"type":55,"value":4959},"Now we require our package us usual:",{"type":28,"tag":534,"props":4961,"children":4962},{"className":2888,"code":2889,"language":2890,"meta":7,"style":7},[4963],{"type":28,"tag":548,"props":4964,"children":4965},{"__ignoreMap":7},[4966],{"type":28,"tag":116,"props":4967,"children":4968},{"class":553,"line":554},[4969,4973,4977],{"type":28,"tag":116,"props":4970,"children":4971},{"style":2900},[4972],{"type":55,"value":1785},{"type":28,"tag":116,"props":4974,"children":4975},{"style":596},[4976],{"type":55,"value":2907},{"type":28,"tag":116,"props":4978,"children":4979},{"style":596},[4980],{"type":55,"value":2912},{"type":28,"tag":534,"props":4982,"children":4984},{"className":3623,"code":4983,"language":3625,"meta":7,"style":7},"./composer.json has been updated\nRunning composer update acme/sample-plugin\nLoading composer repositories with package information\nUpdating dependencies\nLock file operations: 1 install, 0 updates, 0 removals\n  - Locking acme/sample-plugin (1.0.0)\nWriting lock file\nInstalling dependencies from lock file (including require-dev)\nPackage operations: 1 install, 0 updates, 0 removals\n  - Downloading acme/sample-plugin (1.0.0)\n  - Installing acme/sample-plugin (1.0.0): Extracting archive\nGenerating optimized autoload files\n\nRun composer recipes at any time to see the status of your Symfony recipes.\n\nExecuting script assets:install [OK]\n\nUsing version ^1.0 for acme/sample-plugin\n",[4985],{"type":28,"tag":548,"props":4986,"children":4987},{"__ignoreMap":7},[4988,4995,5002,5009,5016,5023,5030,5037,5044,5051,5059,5067,5074,5081,5088,5095,5102,5109],{"type":28,"tag":116,"props":4989,"children":4990},{"class":553,"line":554},[4991],{"type":28,"tag":116,"props":4992,"children":4993},{},[4994],{"type":55,"value":2978},{"type":28,"tag":116,"props":4996,"children":4997},{"class":553,"line":271},[4998],{"type":28,"tag":116,"props":4999,"children":5000},{},[5001],{"type":55,"value":2986},{"type":28,"tag":116,"props":5003,"children":5004},{"class":553,"line":582},[5005],{"type":28,"tag":116,"props":5006,"children":5007},{},[5008],{"type":55,"value":3652},{"type":28,"tag":116,"props":5010,"children":5011},{"class":553,"line":602},[5012],{"type":28,"tag":116,"props":5013,"children":5014},{},[5015],{"type":55,"value":3660},{"type":28,"tag":116,"props":5017,"children":5018},{"class":553,"line":539},[5019],{"type":28,"tag":116,"props":5020,"children":5021},{},[5022],{"type":55,"value":3010},{"type":28,"tag":116,"props":5024,"children":5025},{"class":553,"line":540},[5026],{"type":28,"tag":116,"props":5027,"children":5028},{},[5029],{"type":55,"value":3675},{"type":28,"tag":116,"props":5031,"children":5032},{"class":553,"line":541},[5033],{"type":28,"tag":116,"props":5034,"children":5035},{},[5036],{"type":55,"value":3026},{"type":28,"tag":116,"props":5038,"children":5039},{"class":553,"line":542},[5040],{"type":28,"tag":116,"props":5041,"children":5042},{},[5043],{"type":55,"value":3034},{"type":28,"tag":116,"props":5045,"children":5046},{"class":553,"line":543},[5047],{"type":28,"tag":116,"props":5048,"children":5049},{},[5050],{"type":55,"value":3042},{"type":28,"tag":116,"props":5052,"children":5053},{"class":553,"line":1203},[5054],{"type":28,"tag":116,"props":5055,"children":5056},{},[5057],{"type":55,"value":5058},"  - Downloading acme/sample-plugin (1.0.0)\n",{"type":28,"tag":116,"props":5060,"children":5061},{"class":553,"line":1216},[5062],{"type":28,"tag":116,"props":5063,"children":5064},{},[5065],{"type":55,"value":5066},"  - Installing acme/sample-plugin (1.0.0): Extracting archive\n",{"type":28,"tag":116,"props":5068,"children":5069},{"class":553,"line":107},[5070],{"type":28,"tag":116,"props":5071,"children":5072},{},[5073],{"type":55,"value":3066},{"type":28,"tag":116,"props":5075,"children":5076},{"class":553,"line":1241},[5077],{"type":28,"tag":116,"props":5078,"children":5079},{"emptyLinePlaceholder":1271},[5080],{"type":55,"value":1274},{"type":28,"tag":116,"props":5082,"children":5083},{"class":553,"line":1254},[5084],{"type":28,"tag":116,"props":5085,"children":5086},{},[5087],{"type":55,"value":3081},{"type":28,"tag":116,"props":5089,"children":5090},{"class":553,"line":1267},[5091],{"type":28,"tag":116,"props":5092,"children":5093},{"emptyLinePlaceholder":1271},[5094],{"type":55,"value":1274},{"type":28,"tag":116,"props":5096,"children":5097},{"class":553,"line":1277},[5098],{"type":28,"tag":116,"props":5099,"children":5100},{},[5101],{"type":55,"value":3096},{"type":28,"tag":116,"props":5103,"children":5104},{"class":553,"line":1290},[5105],{"type":28,"tag":116,"props":5106,"children":5107},{"emptyLinePlaceholder":1271},[5108],{"type":55,"value":1274},{"type":28,"tag":116,"props":5110,"children":5111},{"class":553,"line":1303},[5112],{"type":28,"tag":116,"props":5113,"children":5114},{},[5115],{"type":55,"value":3762},{"type":28,"tag":47,"props":5117,"children":5118},{},[5119],{"type":28,"tag":116,"props":5120,"children":5123},{"className":5121},[5122],"text-h2",[5124],{"type":55,"value":5125},"Awesome. Direct package download!",{"type":28,"tag":111,"props":5127,"children":5129},{"id":5128},"why-bother",[5130],{"type":55,"value":5131},"Why bother?",{"type":28,"tag":47,"props":5133,"children":5134},{},[5135,5137,5143,5145,5151],{"type":55,"value":5136},"This is an excellent question. The main reason is package caching. When running in a ",{"type":28,"tag":548,"props":5138,"children":5140},{"className":5139},[],[5141],{"type":55,"value":5142},"CI/CD",{"type":55,"value":5144}," environment or ",{"type":28,"tag":548,"props":5146,"children":5148},{"className":5147},[],[5149],{"type":55,"value":5150},"docker build",{"type":55,"value":5152},",\ncaching packages can give you a massive performance boost.",{"type":28,"tag":1542,"props":5154,"children":5155},{},[],{"type":28,"tag":1062,"props":5157,"children":5158},{},[],{"type":28,"tag":79,"props":5160,"children":5162},{"id":5161},"release-pipeline",[5163],{"type":55,"value":5164},"Release pipeline",{"type":28,"tag":111,"props":5166,"children":5168},{"id":5167},"with-manual-tagging",[5169],{"type":55,"value":5170},"With manual tagging",{"type":28,"tag":47,"props":5172,"children":5173},{},[5174],{"type":55,"value":5175},"This is a simple pipeline when you need to manually create and push a git tag.",{"type":28,"tag":47,"props":5177,"children":5178},{},[5179,5181,5186,5187],{"type":55,"value":5180},"Make sure to always update the ",{"type":28,"tag":548,"props":5182,"children":5184},{"className":5183},[],[5185],{"type":55,"value":3142},{"type":55,"value":3144},{"type":28,"tag":548,"props":5188,"children":5190},{"className":5189},[],[5191],{"type":55,"value":3150},{"type":28,"tag":534,"props":5193,"children":5195},{"className":2888,"code":5194,"language":2890,"meta":7,"style":7},"git tag \u003Cversion>\ngit push --tags\n",[5196],{"type":28,"tag":548,"props":5197,"children":5198},{"__ignoreMap":7},[5199,5227],{"type":28,"tag":116,"props":5200,"children":5201},{"class":553,"line":554},[5202,5206,5210,5214,5219,5223],{"type":28,"tag":116,"props":5203,"children":5204},{"style":2900},[5205],{"type":55,"value":784},{"type":28,"tag":116,"props":5207,"children":5208},{"style":596},[5209],{"type":55,"value":3572},{"type":28,"tag":116,"props":5211,"children":5212},{"style":4807},[5213],{"type":55,"value":4928},{"type":28,"tag":116,"props":5215,"children":5216},{"style":596},[5217],{"type":55,"value":5218},"versio",{"type":28,"tag":116,"props":5220,"children":5221},{"style":564},[5222],{"type":55,"value":4938},{"type":28,"tag":116,"props":5224,"children":5225},{"style":4807},[5226],{"type":55,"value":4943},{"type":28,"tag":116,"props":5228,"children":5229},{"class":553,"line":271},[5230,5234,5238],{"type":28,"tag":116,"props":5231,"children":5232},{"style":2900},[5233],{"type":55,"value":784},{"type":28,"tag":116,"props":5235,"children":5236},{"style":596},[5237],{"type":55,"value":3589},{"type":28,"tag":116,"props":5239,"children":5240},{"style":2170},[5241],{"type":55,"value":3594},{"type":28,"tag":534,"props":5243,"children":5246},{"className":545,"code":5244,"filename":5245,"language":544,"meta":7,"style":7},"stages:\n  - release\n\ndeploy:\n  image: alpine/curl\n  stage: release\n  script:\n    - 'curl --fail-with-body --header \"Job-Token: $CI_JOB_TOKEN\" --data tag=$CI_COMMIT_TAG \"${CI_API_V4_URL}/projects/$CI_PROJECT_ID/packages/composer\"'\n  environment: production\n  rules:\n    if: $CI_COMMIT_TAG\n",".gitlab-ci.yml",[5247],{"type":28,"tag":548,"props":5248,"children":5249},{"__ignoreMap":7},[5250,5262,5275,5282,5294,5311,5327,5339,5352,5369,5381],{"type":28,"tag":116,"props":5251,"children":5252},{"class":553,"line":554},[5253,5258],{"type":28,"tag":116,"props":5254,"children":5255},{"style":558},[5256],{"type":55,"value":5257},"stages",{"type":28,"tag":116,"props":5259,"children":5260},{"style":564},[5261],{"type":55,"value":567},{"type":28,"tag":116,"props":5263,"children":5264},{"class":553,"line":271},[5265,5270],{"type":28,"tag":116,"props":5266,"children":5267},{"style":564},[5268],{"type":55,"value":5269},"  - ",{"type":28,"tag":116,"props":5271,"children":5272},{"style":596},[5273],{"type":55,"value":5274},"release\n",{"type":28,"tag":116,"props":5276,"children":5277},{"class":553,"line":582},[5278],{"type":28,"tag":116,"props":5279,"children":5280},{"emptyLinePlaceholder":1271},[5281],{"type":55,"value":1274},{"type":28,"tag":116,"props":5283,"children":5284},{"class":553,"line":602},[5285,5290],{"type":28,"tag":116,"props":5286,"children":5287},{"style":558},[5288],{"type":55,"value":5289},"deploy",{"type":28,"tag":116,"props":5291,"children":5292},{"style":564},[5293],{"type":55,"value":567},{"type":28,"tag":116,"props":5295,"children":5296},{"class":553,"line":539},[5297,5302,5306],{"type":28,"tag":116,"props":5298,"children":5299},{"style":558},[5300],{"type":55,"value":5301},"  image",{"type":28,"tag":116,"props":5303,"children":5304},{"style":564},[5305],{"type":55,"value":593},{"type":28,"tag":116,"props":5307,"children":5308},{"style":596},[5309],{"type":55,"value":5310},"alpine/curl\n",{"type":28,"tag":116,"props":5312,"children":5313},{"class":553,"line":540},[5314,5319,5323],{"type":28,"tag":116,"props":5315,"children":5316},{"style":558},[5317],{"type":55,"value":5318},"  stage",{"type":28,"tag":116,"props":5320,"children":5321},{"style":564},[5322],{"type":55,"value":593},{"type":28,"tag":116,"props":5324,"children":5325},{"style":596},[5326],{"type":55,"value":5274},{"type":28,"tag":116,"props":5328,"children":5329},{"class":553,"line":541},[5330,5335],{"type":28,"tag":116,"props":5331,"children":5332},{"style":558},[5333],{"type":55,"value":5334},"  script",{"type":28,"tag":116,"props":5336,"children":5337},{"style":564},[5338],{"type":55,"value":567},{"type":28,"tag":116,"props":5340,"children":5341},{"class":553,"line":542},[5342,5347],{"type":28,"tag":116,"props":5343,"children":5344},{"style":564},[5345],{"type":55,"value":5346},"    - ",{"type":28,"tag":116,"props":5348,"children":5349},{"style":596},[5350],{"type":55,"value":5351},"'curl --fail-with-body --header \"Job-Token: $CI_JOB_TOKEN\" --data tag=$CI_COMMIT_TAG \"${CI_API_V4_URL}/projects/$CI_PROJECT_ID/packages/composer\"'\n",{"type":28,"tag":116,"props":5353,"children":5354},{"class":553,"line":543},[5355,5360,5364],{"type":28,"tag":116,"props":5356,"children":5357},{"style":558},[5358],{"type":55,"value":5359},"  environment",{"type":28,"tag":116,"props":5361,"children":5362},{"style":564},[5363],{"type":55,"value":593},{"type":28,"tag":116,"props":5365,"children":5366},{"style":596},[5367],{"type":55,"value":5368},"production\n",{"type":28,"tag":116,"props":5370,"children":5371},{"class":553,"line":1203},[5372,5377],{"type":28,"tag":116,"props":5373,"children":5374},{"style":558},[5375],{"type":55,"value":5376},"  rules",{"type":28,"tag":116,"props":5378,"children":5379},{"style":564},[5380],{"type":55,"value":567},{"type":28,"tag":116,"props":5382,"children":5383},{"class":553,"line":1216},[5384,5389,5393],{"type":28,"tag":116,"props":5385,"children":5386},{"style":558},[5387],{"type":55,"value":5388},"    if",{"type":28,"tag":116,"props":5390,"children":5391},{"style":564},[5392],{"type":55,"value":593},{"type":28,"tag":116,"props":5394,"children":5395},{"style":596},[5396],{"type":55,"value":5397},"$CI_COMMIT_TAG\n",{"type":28,"tag":111,"props":5399,"children":5401},{"id":5400},"with-semantic-release",[5402],{"type":55,"value":5403},"With semantic-release",{"type":28,"tag":47,"props":5405,"children":5406},{},[5407],{"type":55,"value":5408},"It would be a lot easier if we could just push our changes and don't care about versioning and tagging.",{"type":28,"tag":47,"props":5410,"children":5411},{},[5412,5418],{"type":28,"tag":520,"props":5413,"children":5415},{"href":5414},"https://github.com/semantic-release/semantic-release",[5416],{"type":55,"value":5417},"semantic-release",{"type":55,"value":5419}," automates the whole package release workflow.",{"type":28,"tag":47,"props":5421,"children":5422},{},[5423,5425,5431],{"type":55,"value":5424},"Please follow the ",{"type":28,"tag":520,"props":5426,"children":5428},{"href":5427},"https://github.com/semantic-release/gitlab?tab=readme-ov-file#gitlab-authentication",[5429],{"type":55,"value":5430},"GitLab authentication instruction",{"type":55,"value":5432}," before you continue to read.",{"type":28,"tag":534,"props":5434,"children":5437},{"className":545,"code":5435,"filename":5436,"language":544,"meta":7,"style":7},"stages:\n  - release\n\nrelease:\n  stage: release\n  image:\n    name: ghcr.io/voxpupuli/semantic-release:25.0.0-latest\n    entrypoint: [\"\"]\n  interruptible: true\n  script:\n    - /container-entrypoint.sh\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n\n","\u003Cplugin-root>/.gitlab-ci.yml",[5438],{"type":28,"tag":548,"props":5439,"children":5440},{"__ignoreMap":7},[5441,5452,5463,5470,5482,5497,5508,5525,5548,5564,5575,5587,5598,5619,5636],{"type":28,"tag":116,"props":5442,"children":5443},{"class":553,"line":554},[5444,5448],{"type":28,"tag":116,"props":5445,"children":5446},{"style":558},[5447],{"type":55,"value":5257},{"type":28,"tag":116,"props":5449,"children":5450},{"style":564},[5451],{"type":55,"value":567},{"type":28,"tag":116,"props":5453,"children":5454},{"class":553,"line":271},[5455,5459],{"type":28,"tag":116,"props":5456,"children":5457},{"style":564},[5458],{"type":55,"value":5269},{"type":28,"tag":116,"props":5460,"children":5461},{"style":596},[5462],{"type":55,"value":5274},{"type":28,"tag":116,"props":5464,"children":5465},{"class":553,"line":582},[5466],{"type":28,"tag":116,"props":5467,"children":5468},{"emptyLinePlaceholder":1271},[5469],{"type":55,"value":1274},{"type":28,"tag":116,"props":5471,"children":5472},{"class":553,"line":602},[5473,5478],{"type":28,"tag":116,"props":5474,"children":5475},{"style":558},[5476],{"type":55,"value":5477},"release",{"type":28,"tag":116,"props":5479,"children":5480},{"style":564},[5481],{"type":55,"value":567},{"type":28,"tag":116,"props":5483,"children":5484},{"class":553,"line":539},[5485,5489,5493],{"type":28,"tag":116,"props":5486,"children":5487},{"style":558},[5488],{"type":55,"value":5318},{"type":28,"tag":116,"props":5490,"children":5491},{"style":564},[5492],{"type":55,"value":593},{"type":28,"tag":116,"props":5494,"children":5495},{"style":596},[5496],{"type":55,"value":5274},{"type":28,"tag":116,"props":5498,"children":5499},{"class":553,"line":540},[5500,5504],{"type":28,"tag":116,"props":5501,"children":5502},{"style":558},[5503],{"type":55,"value":5301},{"type":28,"tag":116,"props":5505,"children":5506},{"style":564},[5507],{"type":55,"value":567},{"type":28,"tag":116,"props":5509,"children":5510},{"class":553,"line":541},[5511,5516,5520],{"type":28,"tag":116,"props":5512,"children":5513},{"style":558},[5514],{"type":55,"value":5515},"    name",{"type":28,"tag":116,"props":5517,"children":5518},{"style":564},[5519],{"type":55,"value":593},{"type":28,"tag":116,"props":5521,"children":5522},{"style":596},[5523],{"type":55,"value":5524},"ghcr.io/voxpupuli/semantic-release:25.0.0-latest\n",{"type":28,"tag":116,"props":5526,"children":5527},{"class":553,"line":542},[5528,5533,5538,5543],{"type":28,"tag":116,"props":5529,"children":5530},{"style":558},[5531],{"type":55,"value":5532},"    entrypoint",{"type":28,"tag":116,"props":5534,"children":5535},{"style":564},[5536],{"type":55,"value":5537},": [",{"type":28,"tag":116,"props":5539,"children":5540},{"style":596},[5541],{"type":55,"value":5542},"\"\"",{"type":28,"tag":116,"props":5544,"children":5545},{"style":564},[5546],{"type":55,"value":5547},"]\n",{"type":28,"tag":116,"props":5549,"children":5550},{"class":553,"line":543},[5551,5556,5560],{"type":28,"tag":116,"props":5552,"children":5553},{"style":558},[5554],{"type":55,"value":5555},"  interruptible",{"type":28,"tag":116,"props":5557,"children":5558},{"style":564},[5559],{"type":55,"value":593},{"type":28,"tag":116,"props":5561,"children":5562},{"style":2170},[5563],{"type":55,"value":2173},{"type":28,"tag":116,"props":5565,"children":5566},{"class":553,"line":1203},[5567,5571],{"type":28,"tag":116,"props":5568,"children":5569},{"style":558},[5570],{"type":55,"value":5334},{"type":28,"tag":116,"props":5572,"children":5573},{"style":564},[5574],{"type":55,"value":567},{"type":28,"tag":116,"props":5576,"children":5577},{"class":553,"line":1216},[5578,5582],{"type":28,"tag":116,"props":5579,"children":5580},{"style":564},[5581],{"type":55,"value":5346},{"type":28,"tag":116,"props":5583,"children":5584},{"style":596},[5585],{"type":55,"value":5586},"/container-entrypoint.sh\n",{"type":28,"tag":116,"props":5588,"children":5589},{"class":553,"line":107},[5590,5594],{"type":28,"tag":116,"props":5591,"children":5592},{"style":558},[5593],{"type":55,"value":5376},{"type":28,"tag":116,"props":5595,"children":5596},{"style":564},[5597],{"type":55,"value":567},{"type":28,"tag":116,"props":5599,"children":5600},{"class":553,"line":1241},[5601,5605,5610,5614],{"type":28,"tag":116,"props":5602,"children":5603},{"style":564},[5604],{"type":55,"value":5346},{"type":28,"tag":116,"props":5606,"children":5607},{"style":558},[5608],{"type":55,"value":5609},"if",{"type":28,"tag":116,"props":5611,"children":5612},{"style":564},[5613],{"type":55,"value":593},{"type":28,"tag":116,"props":5615,"children":5616},{"style":596},[5617],{"type":55,"value":5618},"$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n",{"type":28,"tag":116,"props":5620,"children":5621},{"class":553,"line":1254},[5622,5627,5631],{"type":28,"tag":116,"props":5623,"children":5624},{"style":558},[5625],{"type":55,"value":5626},"      when",{"type":28,"tag":116,"props":5628,"children":5629},{"style":564},[5630],{"type":55,"value":593},{"type":28,"tag":116,"props":5632,"children":5633},{"style":596},[5634],{"type":55,"value":5635},"never\n",{"type":28,"tag":116,"props":5637,"children":5638},{"class":553,"line":1267},[5639,5643,5647,5651],{"type":28,"tag":116,"props":5640,"children":5641},{"style":564},[5642],{"type":55,"value":5346},{"type":28,"tag":116,"props":5644,"children":5645},{"style":558},[5646],{"type":55,"value":5609},{"type":28,"tag":116,"props":5648,"children":5649},{"style":564},[5650],{"type":55,"value":593},{"type":28,"tag":116,"props":5652,"children":5653},{"style":596},[5654],{"type":55,"value":5655},"$CI_COMMIT_BRANCH\n",{"type":28,"tag":534,"props":5657,"children":5660},{"className":1833,"code":5658,"filename":5659,"language":384,"meta":7,"style":7},"{\n  \"plugins\": [\n    \"@semantic-release/commit-analyzer\",\n    [\n      \"semantic-release-replace-plugin\",\n      {\n        \"replacements\": [\n          {\n            \"files\": [\"composer.json\"],\n            \"from\": \"version\\\": \\\".*\\\"\",\n            \"to\": \"version\\\": \\\"${nextRelease.version}\\\"\"\n          }\n        ]\n      }\n    ],\n    [\n      \"@semantic-release/git\",\n      {\n        \"assets\": [\"composer.json\"],\n        \"message\": \"chore(release): ${nextRelease.version} [skip ci]\\n\\n${nextRelease.notes}\"\n      }\n    ],\n    [\n      \"@semantic-release/exec\",\n      {\n        \"publishCmd\": \"curl --fail-with-body --header \\\"Job-Token: ${process.env.CI_JOB_TOKEN}\\\" --data tag=${nextRelease.gitTag} ${process.env.CI_API_V4_URL}/projects/${process.env.CI_PROJECT_ID}/packages/composer\"\n      }\n    ]\n  ]\n}\n","\u003Cplugin-root>/.releaserc.json",[5661],{"type":28,"tag":548,"props":5662,"children":5663},{"__ignoreMap":7},[5664,5671,5683,5695,5703,5715,5723,5735,5743,5765,5812,5854,5862,5870,5877,5884,5891,5903,5910,5930,5957,5964,5971,5978,5990,5997,6032,6039,6046,6054],{"type":28,"tag":116,"props":5665,"children":5666},{"class":553,"line":554},[5667],{"type":28,"tag":116,"props":5668,"children":5669},{"style":564},[5670],{"type":55,"value":1852},{"type":28,"tag":116,"props":5672,"children":5673},{"class":553,"line":271},[5674,5679],{"type":28,"tag":116,"props":5675,"children":5676},{"style":1858},[5677],{"type":55,"value":5678},"  \"plugins\"",{"type":28,"tag":116,"props":5680,"children":5681},{"style":564},[5682],{"type":55,"value":2093},{"type":28,"tag":116,"props":5684,"children":5685},{"class":553,"line":582},[5686,5691],{"type":28,"tag":116,"props":5687,"children":5688},{"style":1868},[5689],{"type":55,"value":5690},"    \"@semantic-release/commit-analyzer\"",{"type":28,"tag":116,"props":5692,"children":5693},{"style":564},[5694],{"type":55,"value":1876},{"type":28,"tag":116,"props":5696,"children":5697},{"class":553,"line":602},[5698],{"type":28,"tag":116,"props":5699,"children":5700},{"style":564},[5701],{"type":55,"value":5702},"    [\n",{"type":28,"tag":116,"props":5704,"children":5705},{"class":553,"line":539},[5706,5711],{"type":28,"tag":116,"props":5707,"children":5708},{"style":1868},[5709],{"type":55,"value":5710},"      \"semantic-release-replace-plugin\"",{"type":28,"tag":116,"props":5712,"children":5713},{"style":564},[5714],{"type":55,"value":1876},{"type":28,"tag":116,"props":5716,"children":5717},{"class":553,"line":540},[5718],{"type":28,"tag":116,"props":5719,"children":5720},{"style":564},[5721],{"type":55,"value":5722},"      {\n",{"type":28,"tag":116,"props":5724,"children":5725},{"class":553,"line":541},[5726,5731],{"type":28,"tag":116,"props":5727,"children":5728},{"style":1858},[5729],{"type":55,"value":5730},"        \"replacements\"",{"type":28,"tag":116,"props":5732,"children":5733},{"style":564},[5734],{"type":55,"value":2093},{"type":28,"tag":116,"props":5736,"children":5737},{"class":553,"line":542},[5738],{"type":28,"tag":116,"props":5739,"children":5740},{"style":564},[5741],{"type":55,"value":5742},"          {\n",{"type":28,"tag":116,"props":5744,"children":5745},{"class":553,"line":543},[5746,5751,5755,5760],{"type":28,"tag":116,"props":5747,"children":5748},{"style":1858},[5749],{"type":55,"value":5750},"            \"files\"",{"type":28,"tag":116,"props":5752,"children":5753},{"style":564},[5754],{"type":55,"value":5537},{"type":28,"tag":116,"props":5756,"children":5757},{"style":1868},[5758],{"type":55,"value":5759},"\"composer.json\"",{"type":28,"tag":116,"props":5761,"children":5762},{"style":564},[5763],{"type":55,"value":5764},"],\n",{"type":28,"tag":116,"props":5766,"children":5767},{"class":553,"line":1203},[5768,5773,5777,5782,5787,5791,5795,5800,5804,5808],{"type":28,"tag":116,"props":5769,"children":5770},{"style":1858},[5771],{"type":55,"value":5772},"            \"from\"",{"type":28,"tag":116,"props":5774,"children":5775},{"style":564},[5776],{"type":55,"value":593},{"type":28,"tag":116,"props":5778,"children":5779},{"style":1868},[5780],{"type":55,"value":5781},"\"version",{"type":28,"tag":116,"props":5783,"children":5784},{"style":2170},[5785],{"type":55,"value":5786},"\\\"",{"type":28,"tag":116,"props":5788,"children":5789},{"style":1868},[5790],{"type":55,"value":593},{"type":28,"tag":116,"props":5792,"children":5793},{"style":2170},[5794],{"type":55,"value":5786},{"type":28,"tag":116,"props":5796,"children":5797},{"style":1868},[5798],{"type":55,"value":5799},".*",{"type":28,"tag":116,"props":5801,"children":5802},{"style":2170},[5803],{"type":55,"value":5786},{"type":28,"tag":116,"props":5805,"children":5806},{"style":1868},[5807],{"type":55,"value":2478},{"type":28,"tag":116,"props":5809,"children":5810},{"style":564},[5811],{"type":55,"value":1876},{"type":28,"tag":116,"props":5813,"children":5814},{"class":553,"line":1216},[5815,5820,5824,5828,5832,5836,5840,5845,5849],{"type":28,"tag":116,"props":5816,"children":5817},{"style":1858},[5818],{"type":55,"value":5819},"            \"to\"",{"type":28,"tag":116,"props":5821,"children":5822},{"style":564},[5823],{"type":55,"value":593},{"type":28,"tag":116,"props":5825,"children":5826},{"style":1868},[5827],{"type":55,"value":5781},{"type":28,"tag":116,"props":5829,"children":5830},{"style":2170},[5831],{"type":55,"value":5786},{"type":28,"tag":116,"props":5833,"children":5834},{"style":1868},[5835],{"type":55,"value":593},{"type":28,"tag":116,"props":5837,"children":5838},{"style":2170},[5839],{"type":55,"value":5786},{"type":28,"tag":116,"props":5841,"children":5842},{"style":1868},[5843],{"type":55,"value":5844},"${nextRelease.version}",{"type":28,"tag":116,"props":5846,"children":5847},{"style":2170},[5848],{"type":55,"value":5786},{"type":28,"tag":116,"props":5850,"children":5851},{"style":1868},[5852],{"type":55,"value":5853},"\"\n",{"type":28,"tag":116,"props":5855,"children":5856},{"class":553,"line":107},[5857],{"type":28,"tag":116,"props":5858,"children":5859},{"style":564},[5860],{"type":55,"value":5861},"          }\n",{"type":28,"tag":116,"props":5863,"children":5864},{"class":553,"line":1241},[5865],{"type":28,"tag":116,"props":5866,"children":5867},{"style":564},[5868],{"type":55,"value":5869},"        ]\n",{"type":28,"tag":116,"props":5871,"children":5872},{"class":553,"line":1254},[5873],{"type":28,"tag":116,"props":5874,"children":5875},{"style":564},[5876],{"type":55,"value":2181},{"type":28,"tag":116,"props":5878,"children":5879},{"class":553,"line":1267},[5880],{"type":28,"tag":116,"props":5881,"children":5882},{"style":564},[5883],{"type":55,"value":2725},{"type":28,"tag":116,"props":5885,"children":5886},{"class":553,"line":1277},[5887],{"type":28,"tag":116,"props":5888,"children":5889},{"style":564},[5890],{"type":55,"value":5702},{"type":28,"tag":116,"props":5892,"children":5893},{"class":553,"line":1290},[5894,5899],{"type":28,"tag":116,"props":5895,"children":5896},{"style":1868},[5897],{"type":55,"value":5898},"      \"@semantic-release/git\"",{"type":28,"tag":116,"props":5900,"children":5901},{"style":564},[5902],{"type":55,"value":1876},{"type":28,"tag":116,"props":5904,"children":5905},{"class":553,"line":1303},[5906],{"type":28,"tag":116,"props":5907,"children":5908},{"style":564},[5909],{"type":55,"value":5722},{"type":28,"tag":116,"props":5911,"children":5912},{"class":553,"line":1312},[5913,5918,5922,5926],{"type":28,"tag":116,"props":5914,"children":5915},{"style":1858},[5916],{"type":55,"value":5917},"        \"assets\"",{"type":28,"tag":116,"props":5919,"children":5920},{"style":564},[5921],{"type":55,"value":5537},{"type":28,"tag":116,"props":5923,"children":5924},{"style":1868},[5925],{"type":55,"value":5759},{"type":28,"tag":116,"props":5927,"children":5928},{"style":564},[5929],{"type":55,"value":5764},{"type":28,"tag":116,"props":5931,"children":5932},{"class":553,"line":1325},[5933,5938,5942,5947,5952],{"type":28,"tag":116,"props":5934,"children":5935},{"style":1858},[5936],{"type":55,"value":5937},"        \"message\"",{"type":28,"tag":116,"props":5939,"children":5940},{"style":564},[5941],{"type":55,"value":593},{"type":28,"tag":116,"props":5943,"children":5944},{"style":1868},[5945],{"type":55,"value":5946},"\"chore(release): ${nextRelease.version} [skip ci]",{"type":28,"tag":116,"props":5948,"children":5949},{"style":2170},[5950],{"type":55,"value":5951},"\\n\\n",{"type":28,"tag":116,"props":5953,"children":5954},{"style":1868},[5955],{"type":55,"value":5956},"${nextRelease.notes}\"\n",{"type":28,"tag":116,"props":5958,"children":5959},{"class":553,"line":1338},[5960],{"type":28,"tag":116,"props":5961,"children":5962},{"style":564},[5963],{"type":55,"value":2181},{"type":28,"tag":116,"props":5965,"children":5966},{"class":553,"line":1351},[5967],{"type":28,"tag":116,"props":5968,"children":5969},{"style":564},[5970],{"type":55,"value":2725},{"type":28,"tag":116,"props":5972,"children":5973},{"class":553,"line":1359},[5974],{"type":28,"tag":116,"props":5975,"children":5976},{"style":564},[5977],{"type":55,"value":5702},{"type":28,"tag":116,"props":5979,"children":5980},{"class":553,"line":1372},[5981,5986],{"type":28,"tag":116,"props":5982,"children":5983},{"style":1868},[5984],{"type":55,"value":5985},"      \"@semantic-release/exec\"",{"type":28,"tag":116,"props":5987,"children":5988},{"style":564},[5989],{"type":55,"value":1876},{"type":28,"tag":116,"props":5991,"children":5992},{"class":553,"line":1385},[5993],{"type":28,"tag":116,"props":5994,"children":5995},{"style":564},[5996],{"type":55,"value":5722},{"type":28,"tag":116,"props":5998,"children":5999},{"class":553,"line":1398},[6000,6005,6009,6014,6018,6023,6027],{"type":28,"tag":116,"props":6001,"children":6002},{"style":1858},[6003],{"type":55,"value":6004},"        \"publishCmd\"",{"type":28,"tag":116,"props":6006,"children":6007},{"style":564},[6008],{"type":55,"value":593},{"type":28,"tag":116,"props":6010,"children":6011},{"style":1868},[6012],{"type":55,"value":6013},"\"curl --fail-with-body --header ",{"type":28,"tag":116,"props":6015,"children":6016},{"style":2170},[6017],{"type":55,"value":5786},{"type":28,"tag":116,"props":6019,"children":6020},{"style":1868},[6021],{"type":55,"value":6022},"Job-Token: ${process.env.CI_JOB_TOKEN}",{"type":28,"tag":116,"props":6024,"children":6025},{"style":2170},[6026],{"type":55,"value":5786},{"type":28,"tag":116,"props":6028,"children":6029},{"style":1868},[6030],{"type":55,"value":6031}," --data tag=${nextRelease.gitTag} ${process.env.CI_API_V4_URL}/projects/${process.env.CI_PROJECT_ID}/packages/composer\"\n",{"type":28,"tag":116,"props":6033,"children":6034},{"class":553,"line":1411},[6035],{"type":28,"tag":116,"props":6036,"children":6037},{"style":564},[6038],{"type":55,"value":2181},{"type":28,"tag":116,"props":6040,"children":6041},{"class":553,"line":1424},[6042],{"type":28,"tag":116,"props":6043,"children":6044},{"style":564},[6045],{"type":55,"value":2755},{"type":28,"tag":116,"props":6047,"children":6048},{"class":553,"line":2278},[6049],{"type":28,"tag":116,"props":6050,"children":6051},{"style":564},[6052],{"type":55,"value":6053},"  ]\n",{"type":28,"tag":116,"props":6055,"children":6056},{"class":553,"line":2286},[6057],{"type":28,"tag":116,"props":6058,"children":6059},{"style":564},[6060],{"type":55,"value":2880},{"type":28,"tag":47,"props":6062,"children":6063},{},[6064],{"type":55,"value":6065},"This will:",{"type":28,"tag":838,"props":6067,"children":6068},{},[6069,6074,6084,6096,6101],{"type":28,"tag":690,"props":6070,"children":6071},{},[6072],{"type":55,"value":6073},"Analise the commits from the last release to decide if a new version should be released",{"type":28,"tag":690,"props":6075,"children":6076},{},[6077,6079],{"type":55,"value":6078},"Update the version in ",{"type":28,"tag":548,"props":6080,"children":6082},{"className":6081},[],[6083],{"type":55,"value":3150},{"type":28,"tag":690,"props":6085,"children":6086},{},[6087,6089,6094],{"type":55,"value":6088},"Commit the ",{"type":28,"tag":548,"props":6090,"children":6092},{"className":6091},[],[6093],{"type":55,"value":3150},{"type":55,"value":6095}," back into the repo",{"type":28,"tag":690,"props":6097,"children":6098},{},[6099],{"type":55,"value":6100},"Create a tag",{"type":28,"tag":690,"props":6102,"children":6103},{},[6104],{"type":55,"value":6105},"Release a composer package from this tag",{"type":28,"tag":1705,"props":6107,"children":6108},{},[6109],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":6111},[6112,6118],{"id":1804,"depth":271,"text":1807,"children":6113},[6114,6115,6116,6117],{"id":1815,"depth":582,"text":1818},{"id":3116,"depth":582,"text":3119},{"id":3777,"depth":582,"text":3780},{"id":5128,"depth":582,"text":5131},{"id":5161,"depth":271,"text":5164,"children":6119},[6120,6121],{"id":5167,"depth":582,"text":5170},{"id":5400,"depth":582,"text":5403},{"_path":420,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":421,"description":422,"author":394,"image":395,"releaseDate":409,"blogCategories":6123,"articleTags":6124,"tags":6125,"body":6126,"_type":275,"_id":426,"_source":277,"_file":427,"_stem":428,"_extension":280},[398,399],[399,412,413],[415,23],{"type":25,"children":6127,"toc":7199},[6128,6132,6143,6155,6161,6166,6195,6200,6205,6223,6235,6240,6261,6267,6287,6606,6617,6622,7164,7173,7177,7195],{"type":28,"tag":1727,"props":6129,"children":6131},{"alt":7,"aspect-ratio":1729,"height":1730,"object-fit":1731,"src":6130},"/blog/shopware-plugin-build+release.png",[],{"type":28,"tag":47,"props":6133,"children":6134},{},[6135,6136,6141],{"type":55,"value":770},{"type":28,"tag":520,"props":6137,"children":6138},{"href":406},[6139],{"type":55,"value":6140},"previous post",{"type":55,"value":6142}," I described how to distribute a Shopware 6 plugin over GitLab Package registry.",{"type":28,"tag":47,"props":6144,"children":6145},{},[6146,6148,6153],{"type":55,"value":6147},"When building our project using ",{"type":28,"tag":520,"props":6149,"children":6151},{"href":6150},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html#building-an-extension",[6152],{"type":55,"value":1796},{"type":55,"value":6154},",\nthe tool will look over all plugins and check if they need to be built and do so if needed. This is an unnecessary step.",{"type":28,"tag":79,"props":6156,"children":6158},{"id":6157},"building-manually",[6159],{"type":55,"value":6160},"Building manually",{"type":28,"tag":47,"props":6162,"children":6163},{},[6164],{"type":55,"value":6165},"Building a plugin is as simple as running:",{"type":28,"tag":534,"props":6167,"children":6169},{"className":2888,"code":6168,"language":2890,"meta":7,"style":7},"shopware-cli extension build .\n",[6170],{"type":28,"tag":548,"props":6171,"children":6172},{"__ignoreMap":7},[6173],{"type":28,"tag":116,"props":6174,"children":6175},{"class":553,"line":554},[6176,6180,6185,6190],{"type":28,"tag":116,"props":6177,"children":6178},{"style":2900},[6179],{"type":55,"value":1796},{"type":28,"tag":116,"props":6181,"children":6182},{"style":596},[6183],{"type":55,"value":6184}," extension",{"type":28,"tag":116,"props":6186,"children":6187},{"style":596},[6188],{"type":55,"value":6189}," build",{"type":28,"tag":116,"props":6191,"children":6192},{"style":596},[6193],{"type":55,"value":6194}," .\n",{"type":28,"tag":47,"props":6196,"children":6197},{},[6198],{"type":55,"value":6199},"In the plugin root directory.",{"type":28,"tag":47,"props":6201,"children":6202},{},[6203],{"type":55,"value":6204},"There are some tweaks you can make, like:",{"type":28,"tag":686,"props":6206,"children":6207},{},[6208,6213,6218],{"type":28,"tag":690,"props":6209,"children":6210},{},[6211],{"type":55,"value":6212},"constrain a shopware version",{"type":28,"tag":690,"props":6214,"children":6215},{},[6216],{"type":55,"value":6217},"specify extra bundles",{"type":28,"tag":690,"props":6219,"children":6220},{},[6221],{"type":55,"value":6222},"use esbuild",{"type":28,"tag":47,"props":6224,"children":6225},{},[6226,6228,6233],{"type":55,"value":6227},"Please refer to the ",{"type":28,"tag":520,"props":6229,"children":6231},{"href":6230},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html",[6232],{"type":55,"value":1749},{"type":55,"value":6234}," for detailed configuration.",{"type":28,"tag":47,"props":6236,"children":6237},{},[6238],{"type":55,"value":6239},"The build process will create the following directories containing the compiled files:",{"type":28,"tag":686,"props":6241,"children":6242},{},[6243,6252],{"type":28,"tag":690,"props":6244,"children":6245},{},[6246],{"type":28,"tag":548,"props":6247,"children":6249},{"className":6248},[],[6250],{"type":55,"value":6251},"src/Resources/app/storefront/dist/",{"type":28,"tag":690,"props":6253,"children":6254},{},[6255],{"type":28,"tag":548,"props":6256,"children":6258},{"className":6257},[],[6259],{"type":55,"value":6260},"src/Resources/public/static/",{"type":28,"tag":79,"props":6262,"children":6264},{"id":6263},"build-pipeline",[6265],{"type":55,"value":6266},"Build pipeline",{"type":28,"tag":47,"props":6268,"children":6269},{},[6270,6272,6277,6279,6285],{"type":55,"value":6271},"We use the official ",{"type":28,"tag":548,"props":6273,"children":6275},{"className":6274},[],[6276],{"type":55,"value":1796},{"type":55,"value":6278}," docker image. To speed up the process, we take advantage of the ",{"type":28,"tag":548,"props":6280,"children":6282},{"className":6281},[],[6283],{"type":55,"value":6284},"CI",{"type":55,"value":6286}," caching system.",{"type":28,"tag":534,"props":6288,"children":6291},{"className":545,"code":6289,"filename":5436,"highlights":6290,"language":544,"meta":7,"style":7},"stages:\n  - build\n\nbuild:\n  image:\n    name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n    entrypoint: [\"\"]\n  stage: build\n  variables:\n    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer\n    npm_config_cache: ${CI_PROJECT_DIR}/.npm\n  script:\n    - shopware-cli extension build .\n  cache:\n    - key: $CI_JOB_NAME\n      paths:\n        - $COMPOSER_CACHE_DIR\n        - $npm_config_cache\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n",[540,1254,1267,1277,1290,1303],[6292],{"type":28,"tag":548,"props":6293,"children":6294},{"__ignoreMap":7},[6295,6306,6318,6325,6337,6348,6365,6384,6399,6411,6428,6445,6456,6467,6480,6502,6515,6529,6542,6553,6572,6587],{"type":28,"tag":116,"props":6296,"children":6297},{"class":553,"line":554},[6298,6302],{"type":28,"tag":116,"props":6299,"children":6300},{"style":558},[6301],{"type":55,"value":5257},{"type":28,"tag":116,"props":6303,"children":6304},{"style":564},[6305],{"type":55,"value":567},{"type":28,"tag":116,"props":6307,"children":6308},{"class":553,"line":271},[6309,6313],{"type":28,"tag":116,"props":6310,"children":6311},{"style":564},[6312],{"type":55,"value":5269},{"type":28,"tag":116,"props":6314,"children":6315},{"style":596},[6316],{"type":55,"value":6317},"build\n",{"type":28,"tag":116,"props":6319,"children":6320},{"class":553,"line":582},[6321],{"type":28,"tag":116,"props":6322,"children":6323},{"emptyLinePlaceholder":1271},[6324],{"type":55,"value":1274},{"type":28,"tag":116,"props":6326,"children":6327},{"class":553,"line":602},[6328,6333],{"type":28,"tag":116,"props":6329,"children":6330},{"style":558},[6331],{"type":55,"value":6332},"build",{"type":28,"tag":116,"props":6334,"children":6335},{"style":564},[6336],{"type":55,"value":567},{"type":28,"tag":116,"props":6338,"children":6339},{"class":553,"line":539},[6340,6344],{"type":28,"tag":116,"props":6341,"children":6342},{"style":558},[6343],{"type":55,"value":5301},{"type":28,"tag":116,"props":6345,"children":6346},{"style":564},[6347],{"type":55,"value":567},{"type":28,"tag":116,"props":6349,"children":6351},{"class":6350,"line":540},[553,616],[6352,6356,6360],{"type":28,"tag":116,"props":6353,"children":6354},{"style":558},[6355],{"type":55,"value":5515},{"type":28,"tag":116,"props":6357,"children":6358},{"style":564},[6359],{"type":55,"value":593},{"type":28,"tag":116,"props":6361,"children":6362},{"style":596},[6363],{"type":55,"value":6364},"ghcr.io/shopware/shopware-cli:latest-php-8.2\n",{"type":28,"tag":116,"props":6366,"children":6367},{"class":553,"line":541},[6368,6372,6376,6380],{"type":28,"tag":116,"props":6369,"children":6370},{"style":558},[6371],{"type":55,"value":5532},{"type":28,"tag":116,"props":6373,"children":6374},{"style":564},[6375],{"type":55,"value":5537},{"type":28,"tag":116,"props":6377,"children":6378},{"style":596},[6379],{"type":55,"value":5542},{"type":28,"tag":116,"props":6381,"children":6382},{"style":564},[6383],{"type":55,"value":5547},{"type":28,"tag":116,"props":6385,"children":6386},{"class":553,"line":542},[6387,6391,6395],{"type":28,"tag":116,"props":6388,"children":6389},{"style":558},[6390],{"type":55,"value":5318},{"type":28,"tag":116,"props":6392,"children":6393},{"style":564},[6394],{"type":55,"value":593},{"type":28,"tag":116,"props":6396,"children":6397},{"style":596},[6398],{"type":55,"value":6317},{"type":28,"tag":116,"props":6400,"children":6401},{"class":553,"line":543},[6402,6407],{"type":28,"tag":116,"props":6403,"children":6404},{"style":558},[6405],{"type":55,"value":6406},"  variables",{"type":28,"tag":116,"props":6408,"children":6409},{"style":564},[6410],{"type":55,"value":567},{"type":28,"tag":116,"props":6412,"children":6413},{"class":553,"line":1203},[6414,6419,6423],{"type":28,"tag":116,"props":6415,"children":6416},{"style":558},[6417],{"type":55,"value":6418},"    COMPOSER_CACHE_DIR",{"type":28,"tag":116,"props":6420,"children":6421},{"style":564},[6422],{"type":55,"value":593},{"type":28,"tag":116,"props":6424,"children":6425},{"style":596},[6426],{"type":55,"value":6427},"${CI_PROJECT_DIR}/.composer\n",{"type":28,"tag":116,"props":6429,"children":6430},{"class":553,"line":1216},[6431,6436,6440],{"type":28,"tag":116,"props":6432,"children":6433},{"style":558},[6434],{"type":55,"value":6435},"    npm_config_cache",{"type":28,"tag":116,"props":6437,"children":6438},{"style":564},[6439],{"type":55,"value":593},{"type":28,"tag":116,"props":6441,"children":6442},{"style":596},[6443],{"type":55,"value":6444},"${CI_PROJECT_DIR}/.npm\n",{"type":28,"tag":116,"props":6446,"children":6447},{"class":553,"line":107},[6448,6452],{"type":28,"tag":116,"props":6449,"children":6450},{"style":558},[6451],{"type":55,"value":5334},{"type":28,"tag":116,"props":6453,"children":6454},{"style":564},[6455],{"type":55,"value":567},{"type":28,"tag":116,"props":6457,"children":6458},{"class":553,"line":1241},[6459,6463],{"type":28,"tag":116,"props":6460,"children":6461},{"style":564},[6462],{"type":55,"value":5346},{"type":28,"tag":116,"props":6464,"children":6465},{"style":596},[6466],{"type":55,"value":6168},{"type":28,"tag":116,"props":6468,"children":6470},{"class":6469,"line":1254},[553,616],[6471,6476],{"type":28,"tag":116,"props":6472,"children":6473},{"style":558},[6474],{"type":55,"value":6475},"  cache",{"type":28,"tag":116,"props":6477,"children":6478},{"style":564},[6479],{"type":55,"value":567},{"type":28,"tag":116,"props":6481,"children":6483},{"class":6482,"line":1267},[553,616],[6484,6488,6493,6497],{"type":28,"tag":116,"props":6485,"children":6486},{"style":564},[6487],{"type":55,"value":5346},{"type":28,"tag":116,"props":6489,"children":6490},{"style":558},[6491],{"type":55,"value":6492},"key",{"type":28,"tag":116,"props":6494,"children":6495},{"style":564},[6496],{"type":55,"value":593},{"type":28,"tag":116,"props":6498,"children":6499},{"style":596},[6500],{"type":55,"value":6501},"$CI_JOB_NAME\n",{"type":28,"tag":116,"props":6503,"children":6505},{"class":6504,"line":1277},[553,616],[6506,6511],{"type":28,"tag":116,"props":6507,"children":6508},{"style":558},[6509],{"type":55,"value":6510},"      paths",{"type":28,"tag":116,"props":6512,"children":6513},{"style":564},[6514],{"type":55,"value":567},{"type":28,"tag":116,"props":6516,"children":6518},{"class":6517,"line":1290},[553,616],[6519,6524],{"type":28,"tag":116,"props":6520,"children":6521},{"style":564},[6522],{"type":55,"value":6523},"        - ",{"type":28,"tag":116,"props":6525,"children":6526},{"style":596},[6527],{"type":55,"value":6528},"$COMPOSER_CACHE_DIR\n",{"type":28,"tag":116,"props":6530,"children":6532},{"class":6531,"line":1303},[553,616],[6533,6537],{"type":28,"tag":116,"props":6534,"children":6535},{"style":564},[6536],{"type":55,"value":6523},{"type":28,"tag":116,"props":6538,"children":6539},{"style":596},[6540],{"type":55,"value":6541},"$npm_config_cache\n",{"type":28,"tag":116,"props":6543,"children":6544},{"class":553,"line":1312},[6545,6549],{"type":28,"tag":116,"props":6546,"children":6547},{"style":558},[6548],{"type":55,"value":5376},{"type":28,"tag":116,"props":6550,"children":6551},{"style":564},[6552],{"type":55,"value":567},{"type":28,"tag":116,"props":6554,"children":6555},{"class":553,"line":1325},[6556,6560,6564,6568],{"type":28,"tag":116,"props":6557,"children":6558},{"style":564},[6559],{"type":55,"value":5346},{"type":28,"tag":116,"props":6561,"children":6562},{"style":558},[6563],{"type":55,"value":5609},{"type":28,"tag":116,"props":6565,"children":6566},{"style":564},[6567],{"type":55,"value":593},{"type":28,"tag":116,"props":6569,"children":6570},{"style":596},[6571],{"type":55,"value":5618},{"type":28,"tag":116,"props":6573,"children":6574},{"class":553,"line":1338},[6575,6579,6583],{"type":28,"tag":116,"props":6576,"children":6577},{"style":558},[6578],{"type":55,"value":5626},{"type":28,"tag":116,"props":6580,"children":6581},{"style":564},[6582],{"type":55,"value":593},{"type":28,"tag":116,"props":6584,"children":6585},{"style":596},[6586],{"type":55,"value":5635},{"type":28,"tag":116,"props":6588,"children":6589},{"class":553,"line":1351},[6590,6594,6598,6602],{"type":28,"tag":116,"props":6591,"children":6592},{"style":564},[6593],{"type":55,"value":5346},{"type":28,"tag":116,"props":6595,"children":6596},{"style":558},[6597],{"type":55,"value":5609},{"type":28,"tag":116,"props":6599,"children":6600},{"style":564},[6601],{"type":55,"value":593},{"type":28,"tag":116,"props":6603,"children":6604},{"style":596},[6605],{"type":55,"value":5655},{"type":28,"tag":47,"props":6607,"children":6608},{},[6609,6611,6616],{"type":55,"value":6610},"Let's combine it with our release pipeline from the ",{"type":28,"tag":520,"props":6612,"children":6614},{"href":6613},"/en/blog/shopware-plugin-gitlab-pipeline-release#with-semantic-release",[6615],{"type":55,"value":6140},{"type":55,"value":794},{"type":28,"tag":47,"props":6618,"children":6619},{},[6620],{"type":55,"value":6621},"It's important to pass the built artifacts over to the next job.",{"type":28,"tag":534,"props":6623,"children":6626},{"className":545,"code":6624,"filename":5436,"highlights":6625,"language":544,"meta":7,"style":7},"stages:\n  - release\n  - build\n\nbuild:\n  image:\n    name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n    entrypoint: [\"\"]\n  stage: build\n  variables:\n    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer\n    npm_config_cache: ${CI_PROJECT_DIR}/.npm\n  script:\n    - shopware-cli extension build .\n  cache:\n    - key: $CI_JOB_NAME\n      paths:\n        - $COMPOSER_CACHE_DIR\n        - $npm_config_cache\n  artifacts:\n    paths:\n      - src/Resources/public\n      - src/Storefront/Resources/public\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n\nrelease:\n  stage: release\n  image:\n    name: ghcr.io/voxpupuli/semantic-release:latest\n    entrypoint: [\"\"]\n  interruptible: true\n  script:\n    - /docker-entrypoint.sh\n  rules:\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n",[1325,1338,1351,1359],[6627],{"type":28,"tag":548,"props":6628,"children":6629},{"__ignoreMap":7},[6630,6641,6652,6663,6670,6681,6692,6707,6726,6741,6752,6767,6782,6793,6804,6815,6834,6845,6856,6867,6880,6893,6906,6919,6930,6949,6964,6983,6990,7001,7016,7027,7043,7062,7077,7088,7100,7111,7130,7145],{"type":28,"tag":116,"props":6631,"children":6632},{"class":553,"line":554},[6633,6637],{"type":28,"tag":116,"props":6634,"children":6635},{"style":558},[6636],{"type":55,"value":5257},{"type":28,"tag":116,"props":6638,"children":6639},{"style":564},[6640],{"type":55,"value":567},{"type":28,"tag":116,"props":6642,"children":6643},{"class":553,"line":271},[6644,6648],{"type":28,"tag":116,"props":6645,"children":6646},{"style":564},[6647],{"type":55,"value":5269},{"type":28,"tag":116,"props":6649,"children":6650},{"style":596},[6651],{"type":55,"value":5274},{"type":28,"tag":116,"props":6653,"children":6654},{"class":553,"line":582},[6655,6659],{"type":28,"tag":116,"props":6656,"children":6657},{"style":564},[6658],{"type":55,"value":5269},{"type":28,"tag":116,"props":6660,"children":6661},{"style":596},[6662],{"type":55,"value":6317},{"type":28,"tag":116,"props":6664,"children":6665},{"class":553,"line":602},[6666],{"type":28,"tag":116,"props":6667,"children":6668},{"emptyLinePlaceholder":1271},[6669],{"type":55,"value":1274},{"type":28,"tag":116,"props":6671,"children":6672},{"class":553,"line":539},[6673,6677],{"type":28,"tag":116,"props":6674,"children":6675},{"style":558},[6676],{"type":55,"value":6332},{"type":28,"tag":116,"props":6678,"children":6679},{"style":564},[6680],{"type":55,"value":567},{"type":28,"tag":116,"props":6682,"children":6683},{"class":553,"line":540},[6684,6688],{"type":28,"tag":116,"props":6685,"children":6686},{"style":558},[6687],{"type":55,"value":5301},{"type":28,"tag":116,"props":6689,"children":6690},{"style":564},[6691],{"type":55,"value":567},{"type":28,"tag":116,"props":6693,"children":6694},{"class":553,"line":541},[6695,6699,6703],{"type":28,"tag":116,"props":6696,"children":6697},{"style":558},[6698],{"type":55,"value":5515},{"type":28,"tag":116,"props":6700,"children":6701},{"style":564},[6702],{"type":55,"value":593},{"type":28,"tag":116,"props":6704,"children":6705},{"style":596},[6706],{"type":55,"value":6364},{"type":28,"tag":116,"props":6708,"children":6709},{"class":553,"line":542},[6710,6714,6718,6722],{"type":28,"tag":116,"props":6711,"children":6712},{"style":558},[6713],{"type":55,"value":5532},{"type":28,"tag":116,"props":6715,"children":6716},{"style":564},[6717],{"type":55,"value":5537},{"type":28,"tag":116,"props":6719,"children":6720},{"style":596},[6721],{"type":55,"value":5542},{"type":28,"tag":116,"props":6723,"children":6724},{"style":564},[6725],{"type":55,"value":5547},{"type":28,"tag":116,"props":6727,"children":6728},{"class":553,"line":543},[6729,6733,6737],{"type":28,"tag":116,"props":6730,"children":6731},{"style":558},[6732],{"type":55,"value":5318},{"type":28,"tag":116,"props":6734,"children":6735},{"style":564},[6736],{"type":55,"value":593},{"type":28,"tag":116,"props":6738,"children":6739},{"style":596},[6740],{"type":55,"value":6317},{"type":28,"tag":116,"props":6742,"children":6743},{"class":553,"line":1203},[6744,6748],{"type":28,"tag":116,"props":6745,"children":6746},{"style":558},[6747],{"type":55,"value":6406},{"type":28,"tag":116,"props":6749,"children":6750},{"style":564},[6751],{"type":55,"value":567},{"type":28,"tag":116,"props":6753,"children":6754},{"class":553,"line":1216},[6755,6759,6763],{"type":28,"tag":116,"props":6756,"children":6757},{"style":558},[6758],{"type":55,"value":6418},{"type":28,"tag":116,"props":6760,"children":6761},{"style":564},[6762],{"type":55,"value":593},{"type":28,"tag":116,"props":6764,"children":6765},{"style":596},[6766],{"type":55,"value":6427},{"type":28,"tag":116,"props":6768,"children":6769},{"class":553,"line":107},[6770,6774,6778],{"type":28,"tag":116,"props":6771,"children":6772},{"style":558},[6773],{"type":55,"value":6435},{"type":28,"tag":116,"props":6775,"children":6776},{"style":564},[6777],{"type":55,"value":593},{"type":28,"tag":116,"props":6779,"children":6780},{"style":596},[6781],{"type":55,"value":6444},{"type":28,"tag":116,"props":6783,"children":6784},{"class":553,"line":1241},[6785,6789],{"type":28,"tag":116,"props":6786,"children":6787},{"style":558},[6788],{"type":55,"value":5334},{"type":28,"tag":116,"props":6790,"children":6791},{"style":564},[6792],{"type":55,"value":567},{"type":28,"tag":116,"props":6794,"children":6795},{"class":553,"line":1254},[6796,6800],{"type":28,"tag":116,"props":6797,"children":6798},{"style":564},[6799],{"type":55,"value":5346},{"type":28,"tag":116,"props":6801,"children":6802},{"style":596},[6803],{"type":55,"value":6168},{"type":28,"tag":116,"props":6805,"children":6806},{"class":553,"line":1267},[6807,6811],{"type":28,"tag":116,"props":6808,"children":6809},{"style":558},[6810],{"type":55,"value":6475},{"type":28,"tag":116,"props":6812,"children":6813},{"style":564},[6814],{"type":55,"value":567},{"type":28,"tag":116,"props":6816,"children":6817},{"class":553,"line":1277},[6818,6822,6826,6830],{"type":28,"tag":116,"props":6819,"children":6820},{"style":564},[6821],{"type":55,"value":5346},{"type":28,"tag":116,"props":6823,"children":6824},{"style":558},[6825],{"type":55,"value":6492},{"type":28,"tag":116,"props":6827,"children":6828},{"style":564},[6829],{"type":55,"value":593},{"type":28,"tag":116,"props":6831,"children":6832},{"style":596},[6833],{"type":55,"value":6501},{"type":28,"tag":116,"props":6835,"children":6836},{"class":553,"line":1290},[6837,6841],{"type":28,"tag":116,"props":6838,"children":6839},{"style":558},[6840],{"type":55,"value":6510},{"type":28,"tag":116,"props":6842,"children":6843},{"style":564},[6844],{"type":55,"value":567},{"type":28,"tag":116,"props":6846,"children":6847},{"class":553,"line":1303},[6848,6852],{"type":28,"tag":116,"props":6849,"children":6850},{"style":564},[6851],{"type":55,"value":6523},{"type":28,"tag":116,"props":6853,"children":6854},{"style":596},[6855],{"type":55,"value":6528},{"type":28,"tag":116,"props":6857,"children":6858},{"class":553,"line":1312},[6859,6863],{"type":28,"tag":116,"props":6860,"children":6861},{"style":564},[6862],{"type":55,"value":6523},{"type":28,"tag":116,"props":6864,"children":6865},{"style":596},[6866],{"type":55,"value":6541},{"type":28,"tag":116,"props":6868,"children":6870},{"class":6869,"line":1325},[553,616],[6871,6876],{"type":28,"tag":116,"props":6872,"children":6873},{"style":558},[6874],{"type":55,"value":6875},"  artifacts",{"type":28,"tag":116,"props":6877,"children":6878},{"style":564},[6879],{"type":55,"value":567},{"type":28,"tag":116,"props":6881,"children":6883},{"class":6882,"line":1338},[553,616],[6884,6889],{"type":28,"tag":116,"props":6885,"children":6886},{"style":558},[6887],{"type":55,"value":6888},"    paths",{"type":28,"tag":116,"props":6890,"children":6891},{"style":564},[6892],{"type":55,"value":567},{"type":28,"tag":116,"props":6894,"children":6896},{"class":6895,"line":1351},[553,616],[6897,6901],{"type":28,"tag":116,"props":6898,"children":6899},{"style":564},[6900],{"type":55,"value":622},{"type":28,"tag":116,"props":6902,"children":6903},{"style":596},[6904],{"type":55,"value":6905},"src/Resources/public\n",{"type":28,"tag":116,"props":6907,"children":6909},{"class":6908,"line":1359},[553,616],[6910,6914],{"type":28,"tag":116,"props":6911,"children":6912},{"style":564},[6913],{"type":55,"value":622},{"type":28,"tag":116,"props":6915,"children":6916},{"style":596},[6917],{"type":55,"value":6918},"src/Storefront/Resources/public\n",{"type":28,"tag":116,"props":6920,"children":6921},{"class":553,"line":1372},[6922,6926],{"type":28,"tag":116,"props":6923,"children":6924},{"style":558},[6925],{"type":55,"value":5376},{"type":28,"tag":116,"props":6927,"children":6928},{"style":564},[6929],{"type":55,"value":567},{"type":28,"tag":116,"props":6931,"children":6932},{"class":553,"line":1385},[6933,6937,6941,6945],{"type":28,"tag":116,"props":6934,"children":6935},{"style":564},[6936],{"type":55,"value":5346},{"type":28,"tag":116,"props":6938,"children":6939},{"style":558},[6940],{"type":55,"value":5609},{"type":28,"tag":116,"props":6942,"children":6943},{"style":564},[6944],{"type":55,"value":593},{"type":28,"tag":116,"props":6946,"children":6947},{"style":596},[6948],{"type":55,"value":5618},{"type":28,"tag":116,"props":6950,"children":6951},{"class":553,"line":1398},[6952,6956,6960],{"type":28,"tag":116,"props":6953,"children":6954},{"style":558},[6955],{"type":55,"value":5626},{"type":28,"tag":116,"props":6957,"children":6958},{"style":564},[6959],{"type":55,"value":593},{"type":28,"tag":116,"props":6961,"children":6962},{"style":596},[6963],{"type":55,"value":5635},{"type":28,"tag":116,"props":6965,"children":6966},{"class":553,"line":1411},[6967,6971,6975,6979],{"type":28,"tag":116,"props":6968,"children":6969},{"style":564},[6970],{"type":55,"value":5346},{"type":28,"tag":116,"props":6972,"children":6973},{"style":558},[6974],{"type":55,"value":5609},{"type":28,"tag":116,"props":6976,"children":6977},{"style":564},[6978],{"type":55,"value":593},{"type":28,"tag":116,"props":6980,"children":6981},{"style":596},[6982],{"type":55,"value":5655},{"type":28,"tag":116,"props":6984,"children":6985},{"class":553,"line":1424},[6986],{"type":28,"tag":116,"props":6987,"children":6988},{"emptyLinePlaceholder":1271},[6989],{"type":55,"value":1274},{"type":28,"tag":116,"props":6991,"children":6992},{"class":553,"line":2278},[6993,6997],{"type":28,"tag":116,"props":6994,"children":6995},{"style":558},[6996],{"type":55,"value":5477},{"type":28,"tag":116,"props":6998,"children":6999},{"style":564},[7000],{"type":55,"value":567},{"type":28,"tag":116,"props":7002,"children":7003},{"class":553,"line":2286},[7004,7008,7012],{"type":28,"tag":116,"props":7005,"children":7006},{"style":558},[7007],{"type":55,"value":5318},{"type":28,"tag":116,"props":7009,"children":7010},{"style":564},[7011],{"type":55,"value":593},{"type":28,"tag":116,"props":7013,"children":7014},{"style":596},[7015],{"type":55,"value":5274},{"type":28,"tag":116,"props":7017,"children":7018},{"class":553,"line":2306},[7019,7023],{"type":28,"tag":116,"props":7020,"children":7021},{"style":558},[7022],{"type":55,"value":5301},{"type":28,"tag":116,"props":7024,"children":7025},{"style":564},[7026],{"type":55,"value":567},{"type":28,"tag":116,"props":7028,"children":7029},{"class":553,"line":2327},[7030,7034,7038],{"type":28,"tag":116,"props":7031,"children":7032},{"style":558},[7033],{"type":55,"value":5515},{"type":28,"tag":116,"props":7035,"children":7036},{"style":564},[7037],{"type":55,"value":593},{"type":28,"tag":116,"props":7039,"children":7040},{"style":596},[7041],{"type":55,"value":7042},"ghcr.io/voxpupuli/semantic-release:latest\n",{"type":28,"tag":116,"props":7044,"children":7045},{"class":553,"line":2339},[7046,7050,7054,7058],{"type":28,"tag":116,"props":7047,"children":7048},{"style":558},[7049],{"type":55,"value":5532},{"type":28,"tag":116,"props":7051,"children":7052},{"style":564},[7053],{"type":55,"value":5537},{"type":28,"tag":116,"props":7055,"children":7056},{"style":596},[7057],{"type":55,"value":5542},{"type":28,"tag":116,"props":7059,"children":7060},{"style":564},[7061],{"type":55,"value":5547},{"type":28,"tag":116,"props":7063,"children":7064},{"class":553,"line":2355},[7065,7069,7073],{"type":28,"tag":116,"props":7066,"children":7067},{"style":558},[7068],{"type":55,"value":5555},{"type":28,"tag":116,"props":7070,"children":7071},{"style":564},[7072],{"type":55,"value":593},{"type":28,"tag":116,"props":7074,"children":7075},{"style":2170},[7076],{"type":55,"value":2173},{"type":28,"tag":116,"props":7078,"children":7079},{"class":553,"line":2363},[7080,7084],{"type":28,"tag":116,"props":7081,"children":7082},{"style":558},[7083],{"type":55,"value":5334},{"type":28,"tag":116,"props":7085,"children":7086},{"style":564},[7087],{"type":55,"value":567},{"type":28,"tag":116,"props":7089,"children":7090},{"class":553,"line":1837},[7091,7095],{"type":28,"tag":116,"props":7092,"children":7093},{"style":564},[7094],{"type":55,"value":5346},{"type":28,"tag":116,"props":7096,"children":7097},{"style":596},[7098],{"type":55,"value":7099},"/docker-entrypoint.sh\n",{"type":28,"tag":116,"props":7101,"children":7102},{"class":553,"line":1838},[7103,7107],{"type":28,"tag":116,"props":7104,"children":7105},{"style":558},[7106],{"type":55,"value":5376},{"type":28,"tag":116,"props":7108,"children":7109},{"style":564},[7110],{"type":55,"value":567},{"type":28,"tag":116,"props":7112,"children":7113},{"class":553,"line":1839},[7114,7118,7122,7126],{"type":28,"tag":116,"props":7115,"children":7116},{"style":564},[7117],{"type":55,"value":5346},{"type":28,"tag":116,"props":7119,"children":7120},{"style":558},[7121],{"type":55,"value":5609},{"type":28,"tag":116,"props":7123,"children":7124},{"style":564},[7125],{"type":55,"value":593},{"type":28,"tag":116,"props":7127,"children":7128},{"style":596},[7129],{"type":55,"value":5618},{"type":28,"tag":116,"props":7131,"children":7132},{"class":553,"line":1840},[7133,7137,7141],{"type":28,"tag":116,"props":7134,"children":7135},{"style":558},[7136],{"type":55,"value":5626},{"type":28,"tag":116,"props":7138,"children":7139},{"style":564},[7140],{"type":55,"value":593},{"type":28,"tag":116,"props":7142,"children":7143},{"style":596},[7144],{"type":55,"value":5635},{"type":28,"tag":116,"props":7146,"children":7147},{"class":553,"line":2426},[7148,7152,7156,7160],{"type":28,"tag":116,"props":7149,"children":7150},{"style":564},[7151],{"type":55,"value":5346},{"type":28,"tag":116,"props":7153,"children":7154},{"style":558},[7155],{"type":55,"value":5609},{"type":28,"tag":116,"props":7157,"children":7158},{"style":564},[7159],{"type":55,"value":593},{"type":28,"tag":116,"props":7161,"children":7162},{"style":596},[7163],{"type":55,"value":5655},{"type":28,"tag":47,"props":7165,"children":7166},{},[7167],{"type":28,"tag":116,"props":7168,"children":7170},{"className":7169},[5122],[7171],{"type":55,"value":7172},"That's it!",{"type":28,"tag":47,"props":7174,"children":7175},{},[7176],{"type":55,"value":6065},{"type":28,"tag":838,"props":7178,"children":7179},{},[7180,7185,7190],{"type":28,"tag":690,"props":7181,"children":7182},{},[7183],{"type":55,"value":7184},"Build all the assets",{"type":28,"tag":690,"props":7186,"children":7187},{},[7188],{"type":55,"value":7189},"Pass them to the second job",{"type":28,"tag":690,"props":7191,"children":7192},{},[7193],{"type":55,"value":7194},"Run the release process as described previously",{"type":28,"tag":1705,"props":7196,"children":7197},{},[7198],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":7200},[7201,7202],{"id":6157,"depth":271,"text":6160},{"id":6263,"depth":271,"text":6266},{"_path":430,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":431,"description":432,"author":394,"image":395,"releaseDate":409,"blogCategories":7204,"articleTags":7205,"tags":7206,"body":7207,"_type":275,"_id":436,"_source":277,"_file":437,"_stem":438,"_extension":280},[398,399],[399,412,413],[415,23],{"type":25,"children":7208,"toc":9473},[7209,7213,7218,7269,7275,7287,7298,7340,7353,7361,7372,7378,7383,7653,7658,7663,7668,7673,7684,7689,7714,7720,7732,8500,8504,8532,8537,8543,8548,9469],{"type":28,"tag":1727,"props":7210,"children":7212},{"alt":7,"aspect-ratio":1729,"height":1730,"object-fit":1731,"src":7211},"/blog/shopware-plugin-test.png",[],{"type":28,"tag":47,"props":7214,"children":7215},{},[7216],{"type":55,"value":7217},"When it comes to testing a Shopware 6 plugin, there are two types of test that can be performed:",{"type":28,"tag":838,"props":7219,"children":7220},{},[7221,7257],{"type":28,"tag":690,"props":7222,"children":7223},{},[7224,7226,7232,7234],{"type":55,"value":7225},"Testing the code itself (",{"type":28,"tag":520,"props":7227,"children":7229},{"href":7228},"https://developer.shopware.com/docs/guides/plugins/plugins/testing/",[7230],{"type":55,"value":7231},"more in the official documentation",{"type":55,"value":7233},")\n",{"type":28,"tag":838,"props":7235,"children":7236},{},[7237,7242,7247,7252],{"type":28,"tag":690,"props":7238,"children":7239},{},[7240],{"type":55,"value":7241},"PHP unit test",{"type":28,"tag":690,"props":7243,"children":7244},{},[7245],{"type":55,"value":7246},"Jest unit tests in Shopware's storefront",{"type":28,"tag":690,"props":7248,"children":7249},{},[7250],{"type":55,"value":7251},"Jest unit tests in Shopware's administration",{"type":28,"tag":690,"props":7253,"children":7254},{},[7255],{"type":55,"value":7256},"End-to-End (E2E) Testing",{"type":28,"tag":690,"props":7258,"children":7259},{},[7260,7262,7267],{"type":55,"value":7261},"Ensuring high code quality (",{"type":28,"tag":520,"props":7263,"children":7265},{"href":7264},"https://developer.shopware.com/docs/products/cli/validation.html",[7266],{"type":55,"value":7231},{"type":55,"value":7268},")",{"type":28,"tag":79,"props":7270,"children":7272},{"id":7271},"code-quality",[7273],{"type":55,"value":7274},"Code quality",{"type":28,"tag":47,"props":7276,"children":7277},{},[7278,7280,7285],{"type":55,"value":7279},"Let's start with code quality because it's easier to run it outside a ",{"type":28,"tag":548,"props":7281,"children":7283},{"className":7282},[],[7284],{"type":55,"value":5142},{"type":55,"value":7286}," environment.",{"type":28,"tag":47,"props":7288,"children":7289},{},[7290,7292,7297],{"type":55,"value":7291},"We will again use the ",{"type":28,"tag":548,"props":7293,"children":7295},{"className":7294},[],[7296],{"type":55,"value":1796},{"type":55,"value":794},{"type":28,"tag":534,"props":7299,"children":7301},{"code":7300,"language":2890,"meta":7,"className":2888,"style":7},"shopware-cli extension validate --full --reporter summary .\n",[7302],{"type":28,"tag":548,"props":7303,"children":7304},{"__ignoreMap":7},[7305],{"type":28,"tag":116,"props":7306,"children":7307},{"class":553,"line":554},[7308,7312,7316,7321,7326,7331,7336],{"type":28,"tag":116,"props":7309,"children":7310},{"style":2900},[7311],{"type":55,"value":1796},{"type":28,"tag":116,"props":7313,"children":7314},{"style":596},[7315],{"type":55,"value":6184},{"type":28,"tag":116,"props":7317,"children":7318},{"style":596},[7319],{"type":55,"value":7320}," validate",{"type":28,"tag":116,"props":7322,"children":7323},{"style":2170},[7324],{"type":55,"value":7325}," --full",{"type":28,"tag":116,"props":7327,"children":7328},{"style":2170},[7329],{"type":55,"value":7330}," --reporter",{"type":28,"tag":116,"props":7332,"children":7333},{"style":596},[7334],{"type":55,"value":7335}," summary",{"type":28,"tag":116,"props":7337,"children":7338},{"style":596},[7339],{"type":55,"value":6194},{"type":28,"tag":47,"props":7341,"children":7342},{},[7343,7345,7351],{"type":55,"value":7344},"This will run all the tests described ",{"type":28,"tag":520,"props":7346,"children":7348},{"href":7347},"https://developer.shopware.com/docs/products/cli/validation.html#running-all-validation-tools",[7349],{"type":55,"value":7350},"here",{"type":55,"value":7352},"\nand hopefully produce an output like this:",{"type":28,"tag":534,"props":7354,"children":7356},{"code":7355},"✖ 0 problems (0 errors, 0 warnings)\n",[7357],{"type":28,"tag":548,"props":7358,"children":7359},{"__ignoreMap":7},[7360],{"type":55,"value":7355},{"type":28,"tag":47,"props":7362,"children":7363},{},[7364,7366,7371],{"type":55,"value":7365},"If there are any errors, refer to the Shopware documentation how to fix them and rerun only the failed tests like described ",{"type":28,"tag":520,"props":7367,"children":7369},{"href":7368},"https://developer.shopware.com/docs/products/cli/validation.html#running-specific-tools",[7370],{"type":55,"value":7350},{"type":55,"value":794},{"type":28,"tag":111,"props":7373,"children":7375},{"id":7374},"code-quality-pipeline",[7376],{"type":55,"value":7377},"Code quality pipeline",{"type":28,"tag":47,"props":7379,"children":7380},{},[7381],{"type":55,"value":7382},"Now we will run it in GitLab.",{"type":28,"tag":534,"props":7384,"children":7387},{"code":7385,"filename":5436,"highlights":7386,"language":544,"meta":7,"className":545,"style":7},"stages:\n  - test\n\ncode-quality:\n   image:\n      name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n      entrypoint: [\"\"]\n   stage: test\n   script:\n      - shopware-cli extension validate --full . | tee report.json\n   artifacts:\n      reports:\n         codequality: report.json\n   rules:\n      - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n      - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n        when: never\n      - if: $CI_COMMIT_BRANCH\n",[540,1254,1267,1277,1290,1303],[7388],{"type":28,"tag":548,"props":7389,"children":7390},{"__ignoreMap":7},[7391,7402,7414,7421,7432,7444,7461,7481,7497,7509,7521,7533,7545,7562,7575,7596,7616,7633],{"type":28,"tag":116,"props":7392,"children":7393},{"class":553,"line":554},[7394,7398],{"type":28,"tag":116,"props":7395,"children":7396},{"style":558},[7397],{"type":55,"value":5257},{"type":28,"tag":116,"props":7399,"children":7400},{"style":564},[7401],{"type":55,"value":567},{"type":28,"tag":116,"props":7403,"children":7404},{"class":553,"line":271},[7405,7409],{"type":28,"tag":116,"props":7406,"children":7407},{"style":564},[7408],{"type":55,"value":5269},{"type":28,"tag":116,"props":7410,"children":7411},{"style":596},[7412],{"type":55,"value":7413},"test\n",{"type":28,"tag":116,"props":7415,"children":7416},{"class":553,"line":582},[7417],{"type":28,"tag":116,"props":7418,"children":7419},{"emptyLinePlaceholder":1271},[7420],{"type":55,"value":1274},{"type":28,"tag":116,"props":7422,"children":7423},{"class":553,"line":602},[7424,7428],{"type":28,"tag":116,"props":7425,"children":7426},{"style":558},[7427],{"type":55,"value":7271},{"type":28,"tag":116,"props":7429,"children":7430},{"style":564},[7431],{"type":55,"value":567},{"type":28,"tag":116,"props":7433,"children":7434},{"class":553,"line":539},[7435,7440],{"type":28,"tag":116,"props":7436,"children":7437},{"style":558},[7438],{"type":55,"value":7439},"   image",{"type":28,"tag":116,"props":7441,"children":7442},{"style":564},[7443],{"type":55,"value":567},{"type":28,"tag":116,"props":7445,"children":7447},{"class":7446,"line":540},[553,616],[7448,7453,7457],{"type":28,"tag":116,"props":7449,"children":7450},{"style":558},[7451],{"type":55,"value":7452},"      name",{"type":28,"tag":116,"props":7454,"children":7455},{"style":564},[7456],{"type":55,"value":593},{"type":28,"tag":116,"props":7458,"children":7459},{"style":596},[7460],{"type":55,"value":6364},{"type":28,"tag":116,"props":7462,"children":7463},{"class":553,"line":541},[7464,7469,7473,7477],{"type":28,"tag":116,"props":7465,"children":7466},{"style":558},[7467],{"type":55,"value":7468},"      entrypoint",{"type":28,"tag":116,"props":7470,"children":7471},{"style":564},[7472],{"type":55,"value":5537},{"type":28,"tag":116,"props":7474,"children":7475},{"style":596},[7476],{"type":55,"value":5542},{"type":28,"tag":116,"props":7478,"children":7479},{"style":564},[7480],{"type":55,"value":5547},{"type":28,"tag":116,"props":7482,"children":7483},{"class":553,"line":542},[7484,7489,7493],{"type":28,"tag":116,"props":7485,"children":7486},{"style":558},[7487],{"type":55,"value":7488},"   stage",{"type":28,"tag":116,"props":7490,"children":7491},{"style":564},[7492],{"type":55,"value":593},{"type":28,"tag":116,"props":7494,"children":7495},{"style":596},[7496],{"type":55,"value":7413},{"type":28,"tag":116,"props":7498,"children":7499},{"class":553,"line":543},[7500,7505],{"type":28,"tag":116,"props":7501,"children":7502},{"style":558},[7503],{"type":55,"value":7504},"   script",{"type":28,"tag":116,"props":7506,"children":7507},{"style":564},[7508],{"type":55,"value":567},{"type":28,"tag":116,"props":7510,"children":7511},{"class":553,"line":1203},[7512,7516],{"type":28,"tag":116,"props":7513,"children":7514},{"style":564},[7515],{"type":55,"value":622},{"type":28,"tag":116,"props":7517,"children":7518},{"style":596},[7519],{"type":55,"value":7520},"shopware-cli extension validate --full . | tee report.json\n",{"type":28,"tag":116,"props":7522,"children":7523},{"class":553,"line":1216},[7524,7529],{"type":28,"tag":116,"props":7525,"children":7526},{"style":558},[7527],{"type":55,"value":7528},"   artifacts",{"type":28,"tag":116,"props":7530,"children":7531},{"style":564},[7532],{"type":55,"value":567},{"type":28,"tag":116,"props":7534,"children":7535},{"class":553,"line":107},[7536,7541],{"type":28,"tag":116,"props":7537,"children":7538},{"style":558},[7539],{"type":55,"value":7540},"      reports",{"type":28,"tag":116,"props":7542,"children":7543},{"style":564},[7544],{"type":55,"value":567},{"type":28,"tag":116,"props":7546,"children":7547},{"class":553,"line":1241},[7548,7553,7557],{"type":28,"tag":116,"props":7549,"children":7550},{"style":558},[7551],{"type":55,"value":7552},"         codequality",{"type":28,"tag":116,"props":7554,"children":7555},{"style":564},[7556],{"type":55,"value":593},{"type":28,"tag":116,"props":7558,"children":7559},{"style":596},[7560],{"type":55,"value":7561},"report.json\n",{"type":28,"tag":116,"props":7563,"children":7565},{"class":7564,"line":1254},[553,616],[7566,7571],{"type":28,"tag":116,"props":7567,"children":7568},{"style":558},[7569],{"type":55,"value":7570},"   rules",{"type":28,"tag":116,"props":7572,"children":7573},{"style":564},[7574],{"type":55,"value":567},{"type":28,"tag":116,"props":7576,"children":7578},{"class":7577,"line":1267},[553,616],[7579,7583,7587,7591],{"type":28,"tag":116,"props":7580,"children":7581},{"style":564},[7582],{"type":55,"value":622},{"type":28,"tag":116,"props":7584,"children":7585},{"style":558},[7586],{"type":55,"value":5609},{"type":28,"tag":116,"props":7588,"children":7589},{"style":564},[7590],{"type":55,"value":593},{"type":28,"tag":116,"props":7592,"children":7593},{"style":596},[7594],{"type":55,"value":7595},"$CI_PIPELINE_SOURCE == \"merge_request_event\"\n",{"type":28,"tag":116,"props":7597,"children":7599},{"class":7598,"line":1277},[553,616],[7600,7604,7608,7612],{"type":28,"tag":116,"props":7601,"children":7602},{"style":564},[7603],{"type":55,"value":622},{"type":28,"tag":116,"props":7605,"children":7606},{"style":558},[7607],{"type":55,"value":5609},{"type":28,"tag":116,"props":7609,"children":7610},{"style":564},[7611],{"type":55,"value":593},{"type":28,"tag":116,"props":7613,"children":7614},{"style":596},[7615],{"type":55,"value":5618},{"type":28,"tag":116,"props":7617,"children":7619},{"class":7618,"line":1290},[553,616],[7620,7625,7629],{"type":28,"tag":116,"props":7621,"children":7622},{"style":558},[7623],{"type":55,"value":7624},"        when",{"type":28,"tag":116,"props":7626,"children":7627},{"style":564},[7628],{"type":55,"value":593},{"type":28,"tag":116,"props":7630,"children":7631},{"style":596},[7632],{"type":55,"value":5635},{"type":28,"tag":116,"props":7634,"children":7636},{"class":7635,"line":1303},[553,616],[7637,7641,7645,7649],{"type":28,"tag":116,"props":7638,"children":7639},{"style":564},[7640],{"type":55,"value":622},{"type":28,"tag":116,"props":7642,"children":7643},{"style":558},[7644],{"type":55,"value":5609},{"type":28,"tag":116,"props":7646,"children":7647},{"style":564},[7648],{"type":55,"value":593},{"type":28,"tag":116,"props":7650,"children":7651},{"style":596},[7652],{"type":55,"value":5655},{"type":28,"tag":47,"props":7654,"children":7655},{},[7656],{"type":55,"value":7657},"This pipeline will run on the default branch and on merge request pipelines.",{"type":28,"tag":47,"props":7659,"children":7660},{},[7661],{"type":55,"value":7662},"Running on the default branch before build and release prevents from accidentally creating a low-quality release.",{"type":28,"tag":47,"props":7664,"children":7665},{},[7666],{"type":55,"value":7667},"A nice touch to the MR pipeline is the Code Quality report integration!",{"type":28,"tag":79,"props":7669,"children":7671},{"id":7670},"php-unit-test",[7672],{"type":55,"value":7241},{"type":28,"tag":47,"props":7674,"children":7675},{},[7676,7678],{"type":55,"value":7677},"First of all, we need to configure PHPUnit by following the ",{"type":28,"tag":520,"props":7679,"children":7681},{"href":7680},"https://developer.shopware.com/docs/guides/plugins/plugins/testing/php-unit.html",[7682],{"type":55,"value":7683},"official shopware documentation",{"type":28,"tag":47,"props":7685,"children":7686},{},[7687],{"type":55,"value":7688},"We won't focus here on this process. When everything is setup, we should be able to run our test like this in out Shopware project root:",{"type":28,"tag":534,"props":7690,"children":7692},{"code":7691,"language":2890,"meta":7,"className":2888,"style":7},"./vendor/bin/phpunit --configuration=\"custom/static-plugins/SwagBasicExample\"\n",[7693],{"type":28,"tag":548,"props":7694,"children":7695},{"__ignoreMap":7},[7696],{"type":28,"tag":116,"props":7697,"children":7698},{"class":553,"line":554},[7699,7704,7709],{"type":28,"tag":116,"props":7700,"children":7701},{"style":2900},[7702],{"type":55,"value":7703},"./vendor/bin/phpunit",{"type":28,"tag":116,"props":7705,"children":7706},{"style":2170},[7707],{"type":55,"value":7708}," --configuration=",{"type":28,"tag":116,"props":7710,"children":7711},{"style":596},[7712],{"type":55,"value":7713},"\"custom/static-plugins/SwagBasicExample\"\n",{"type":28,"tag":111,"props":7715,"children":7717},{"id":7716},"phpunit-pipeline",[7718],{"type":55,"value":7719},"PHPUnit pipeline",{"type":28,"tag":47,"props":7721,"children":7722},{},[7723,7725,7730],{"type":55,"value":7724},"Running PHPUnit for a plugin requires a full Shopware instance. Fortunately, ",{"type":28,"tag":548,"props":7726,"children":7728},{"className":7727},[],[7729],{"type":55,"value":1796},{"type":55,"value":7731}," can help us to deal with it.",{"type":28,"tag":534,"props":7733,"children":7736},{"code":7734,"filename":5436,"highlights":7735,"language":544,"meta":7,"className":545,"style":7},"stages:\n   - test\n\nphpunit:\n  stage: test\n  image:\n    name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n    entrypoint: [\"\"]\n  services:\n    - name: mysql:8.3.0\n      alias: test_database\n      variables:\n        MYSQL_SKIP_TEST_DB: 'yes'\n        MYSQL_ALLOW_EMPTY_PASSWORD: yes\n  variables:\n    GIT_STRATEGY: none\n    SHOPWARE_ROOT: ${CI_PROJECT_DIR}/shopware\n    SHOPWARE_VERSION: 6.6.10.13\n    \n    APP_SECRET: def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48\n    MESSENGER_TRANSPORT_DSN: sync://\n    DATABASE_URL: mysql://root@test_database/shopware\n    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer\n\n    XDEBUG_MODE: coverage\n  before_script:\n    - apk add --no-cache php-8.2-xdebug\n    - shopware-cli project create shopware ${SHOPWARE_VERSION}\n    - cd $SHOPWARE_ROOT\n    - composer req --dev shopware/dev-tools phpunit/phpunit\n    - git clone \"https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\" \"custom/plugins/${CI_PROJECT_NAME}\"\n    - cd custom/plugins/${CI_PROJECT_NAME}\n    - git checkout ${CI_COMMIT_SHA}\n    - cd ${SHOPWARE_ROOT}\n    - composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)\n    - cd custom/plugins/${CI_PROJECT_NAME}\n  script:\n    - ${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml\n\n  cache:\n    - key: $CI_JOB_NAME\n      paths:\n        - $COMPOSER_CACHE_DIR\n  coverage: /^\\s*Lines:\\s*\\d+.\\d+\\%/\n  artifacts:\n    reports:\n      coverage_report:\n        coverage_format: cobertura\n        path: coverage.cobertura.xml\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n",[543,1203,1216,107,1241,1254,1277,1325,1338,1351,1359,1411,1424,2278,2286,2306,2327,2339,2355,2363,1837,1839],[7737],{"type":28,"tag":548,"props":7738,"children":7739},{"__ignoreMap":7},[7740,7751,7763,7770,7782,7797,7808,7823,7842,7855,7876,7894,7907,7925,7943,7954,7972,7989,8006,8013,8031,8049,8067,8083,8090,8107,8119,8132,8145,8158,8171,8184,8197,8210,8223,8236,8248,8259,8272,8279,8290,8309,8320,8331,8348,8359,8371,8383,8400,8417,8428,8447,8466,8481],{"type":28,"tag":116,"props":7741,"children":7742},{"class":553,"line":554},[7743,7747],{"type":28,"tag":116,"props":7744,"children":7745},{"style":558},[7746],{"type":55,"value":5257},{"type":28,"tag":116,"props":7748,"children":7749},{"style":564},[7750],{"type":55,"value":567},{"type":28,"tag":116,"props":7752,"children":7753},{"class":553,"line":271},[7754,7759],{"type":28,"tag":116,"props":7755,"children":7756},{"style":564},[7757],{"type":55,"value":7758},"   - ",{"type":28,"tag":116,"props":7760,"children":7761},{"style":596},[7762],{"type":55,"value":7413},{"type":28,"tag":116,"props":7764,"children":7765},{"class":553,"line":582},[7766],{"type":28,"tag":116,"props":7767,"children":7768},{"emptyLinePlaceholder":1271},[7769],{"type":55,"value":1274},{"type":28,"tag":116,"props":7771,"children":7772},{"class":553,"line":602},[7773,7778],{"type":28,"tag":116,"props":7774,"children":7775},{"style":558},[7776],{"type":55,"value":7777},"phpunit",{"type":28,"tag":116,"props":7779,"children":7780},{"style":564},[7781],{"type":55,"value":567},{"type":28,"tag":116,"props":7783,"children":7784},{"class":553,"line":539},[7785,7789,7793],{"type":28,"tag":116,"props":7786,"children":7787},{"style":558},[7788],{"type":55,"value":5318},{"type":28,"tag":116,"props":7790,"children":7791},{"style":564},[7792],{"type":55,"value":593},{"type":28,"tag":116,"props":7794,"children":7795},{"style":596},[7796],{"type":55,"value":7413},{"type":28,"tag":116,"props":7798,"children":7799},{"class":553,"line":540},[7800,7804],{"type":28,"tag":116,"props":7801,"children":7802},{"style":558},[7803],{"type":55,"value":5301},{"type":28,"tag":116,"props":7805,"children":7806},{"style":564},[7807],{"type":55,"value":567},{"type":28,"tag":116,"props":7809,"children":7810},{"class":553,"line":541},[7811,7815,7819],{"type":28,"tag":116,"props":7812,"children":7813},{"style":558},[7814],{"type":55,"value":5515},{"type":28,"tag":116,"props":7816,"children":7817},{"style":564},[7818],{"type":55,"value":593},{"type":28,"tag":116,"props":7820,"children":7821},{"style":596},[7822],{"type":55,"value":6364},{"type":28,"tag":116,"props":7824,"children":7825},{"class":553,"line":542},[7826,7830,7834,7838],{"type":28,"tag":116,"props":7827,"children":7828},{"style":558},[7829],{"type":55,"value":5532},{"type":28,"tag":116,"props":7831,"children":7832},{"style":564},[7833],{"type":55,"value":5537},{"type":28,"tag":116,"props":7835,"children":7836},{"style":596},[7837],{"type":55,"value":5542},{"type":28,"tag":116,"props":7839,"children":7840},{"style":564},[7841],{"type":55,"value":5547},{"type":28,"tag":116,"props":7843,"children":7845},{"class":7844,"line":543},[553,616],[7846,7851],{"type":28,"tag":116,"props":7847,"children":7848},{"style":558},[7849],{"type":55,"value":7850},"  services",{"type":28,"tag":116,"props":7852,"children":7853},{"style":564},[7854],{"type":55,"value":567},{"type":28,"tag":116,"props":7856,"children":7858},{"class":7857,"line":1203},[553,616],[7859,7863,7867,7871],{"type":28,"tag":116,"props":7860,"children":7861},{"style":564},[7862],{"type":55,"value":5346},{"type":28,"tag":116,"props":7864,"children":7865},{"style":558},[7866],{"type":55,"value":1657},{"type":28,"tag":116,"props":7868,"children":7869},{"style":564},[7870],{"type":55,"value":593},{"type":28,"tag":116,"props":7872,"children":7873},{"style":596},[7874],{"type":55,"value":7875},"mysql:8.3.0\n",{"type":28,"tag":116,"props":7877,"children":7879},{"class":7878,"line":1216},[553,616],[7880,7885,7889],{"type":28,"tag":116,"props":7881,"children":7882},{"style":558},[7883],{"type":55,"value":7884},"      alias",{"type":28,"tag":116,"props":7886,"children":7887},{"style":564},[7888],{"type":55,"value":593},{"type":28,"tag":116,"props":7890,"children":7891},{"style":596},[7892],{"type":55,"value":7893},"test_database\n",{"type":28,"tag":116,"props":7895,"children":7897},{"class":7896,"line":107},[553,616],[7898,7903],{"type":28,"tag":116,"props":7899,"children":7900},{"style":558},[7901],{"type":55,"value":7902},"      variables",{"type":28,"tag":116,"props":7904,"children":7905},{"style":564},[7906],{"type":55,"value":567},{"type":28,"tag":116,"props":7908,"children":7910},{"class":7909,"line":1241},[553,616],[7911,7916,7920],{"type":28,"tag":116,"props":7912,"children":7913},{"style":558},[7914],{"type":55,"value":7915},"        MYSQL_SKIP_TEST_DB",{"type":28,"tag":116,"props":7917,"children":7918},{"style":564},[7919],{"type":55,"value":593},{"type":28,"tag":116,"props":7921,"children":7922},{"style":596},[7923],{"type":55,"value":7924},"'yes'\n",{"type":28,"tag":116,"props":7926,"children":7928},{"class":7927,"line":1254},[553,616],[7929,7934,7938],{"type":28,"tag":116,"props":7930,"children":7931},{"style":558},[7932],{"type":55,"value":7933},"        MYSQL_ALLOW_EMPTY_PASSWORD",{"type":28,"tag":116,"props":7935,"children":7936},{"style":564},[7937],{"type":55,"value":593},{"type":28,"tag":116,"props":7939,"children":7940},{"style":2170},[7941],{"type":55,"value":7942},"yes\n",{"type":28,"tag":116,"props":7944,"children":7945},{"class":553,"line":1267},[7946,7950],{"type":28,"tag":116,"props":7947,"children":7948},{"style":558},[7949],{"type":55,"value":6406},{"type":28,"tag":116,"props":7951,"children":7952},{"style":564},[7953],{"type":55,"value":567},{"type":28,"tag":116,"props":7955,"children":7957},{"class":7956,"line":1277},[553,616],[7958,7963,7967],{"type":28,"tag":116,"props":7959,"children":7960},{"style":558},[7961],{"type":55,"value":7962},"    GIT_STRATEGY",{"type":28,"tag":116,"props":7964,"children":7965},{"style":564},[7966],{"type":55,"value":593},{"type":28,"tag":116,"props":7968,"children":7969},{"style":596},[7970],{"type":55,"value":7971},"none\n",{"type":28,"tag":116,"props":7973,"children":7974},{"class":553,"line":1290},[7975,7980,7984],{"type":28,"tag":116,"props":7976,"children":7977},{"style":558},[7978],{"type":55,"value":7979},"    SHOPWARE_ROOT",{"type":28,"tag":116,"props":7981,"children":7982},{"style":564},[7983],{"type":55,"value":593},{"type":28,"tag":116,"props":7985,"children":7986},{"style":596},[7987],{"type":55,"value":7988},"${CI_PROJECT_DIR}/shopware\n",{"type":28,"tag":116,"props":7990,"children":7991},{"class":553,"line":1303},[7992,7997,8001],{"type":28,"tag":116,"props":7993,"children":7994},{"style":558},[7995],{"type":55,"value":7996},"    SHOPWARE_VERSION",{"type":28,"tag":116,"props":7998,"children":7999},{"style":564},[8000],{"type":55,"value":593},{"type":28,"tag":116,"props":8002,"children":8003},{"style":2170},[8004],{"type":55,"value":8005},"6.6.10.13\n",{"type":28,"tag":116,"props":8007,"children":8008},{"class":553,"line":1312},[8009],{"type":28,"tag":116,"props":8010,"children":8011},{"style":564},[8012],{"type":55,"value":1110},{"type":28,"tag":116,"props":8014,"children":8016},{"class":8015,"line":1325},[553,616],[8017,8022,8026],{"type":28,"tag":116,"props":8018,"children":8019},{"style":558},[8020],{"type":55,"value":8021},"    APP_SECRET",{"type":28,"tag":116,"props":8023,"children":8024},{"style":564},[8025],{"type":55,"value":593},{"type":28,"tag":116,"props":8027,"children":8028},{"style":596},[8029],{"type":55,"value":8030},"def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48\n",{"type":28,"tag":116,"props":8032,"children":8034},{"class":8033,"line":1338},[553,616],[8035,8040,8044],{"type":28,"tag":116,"props":8036,"children":8037},{"style":558},[8038],{"type":55,"value":8039},"    MESSENGER_TRANSPORT_DSN",{"type":28,"tag":116,"props":8041,"children":8042},{"style":564},[8043],{"type":55,"value":593},{"type":28,"tag":116,"props":8045,"children":8046},{"style":596},[8047],{"type":55,"value":8048},"sync://\n",{"type":28,"tag":116,"props":8050,"children":8052},{"class":8051,"line":1351},[553,616],[8053,8058,8062],{"type":28,"tag":116,"props":8054,"children":8055},{"style":558},[8056],{"type":55,"value":8057},"    DATABASE_URL",{"type":28,"tag":116,"props":8059,"children":8060},{"style":564},[8061],{"type":55,"value":593},{"type":28,"tag":116,"props":8063,"children":8064},{"style":596},[8065],{"type":55,"value":8066},"mysql://root@test_database/shopware\n",{"type":28,"tag":116,"props":8068,"children":8070},{"class":8069,"line":1359},[553,616],[8071,8075,8079],{"type":28,"tag":116,"props":8072,"children":8073},{"style":558},[8074],{"type":55,"value":6418},{"type":28,"tag":116,"props":8076,"children":8077},{"style":564},[8078],{"type":55,"value":593},{"type":28,"tag":116,"props":8080,"children":8081},{"style":596},[8082],{"type":55,"value":6427},{"type":28,"tag":116,"props":8084,"children":8085},{"class":553,"line":1372},[8086],{"type":28,"tag":116,"props":8087,"children":8088},{"emptyLinePlaceholder":1271},[8089],{"type":55,"value":1274},{"type":28,"tag":116,"props":8091,"children":8092},{"class":553,"line":1385},[8093,8098,8102],{"type":28,"tag":116,"props":8094,"children":8095},{"style":558},[8096],{"type":55,"value":8097},"    XDEBUG_MODE",{"type":28,"tag":116,"props":8099,"children":8100},{"style":564},[8101],{"type":55,"value":593},{"type":28,"tag":116,"props":8103,"children":8104},{"style":596},[8105],{"type":55,"value":8106},"coverage\n",{"type":28,"tag":116,"props":8108,"children":8109},{"class":553,"line":1398},[8110,8115],{"type":28,"tag":116,"props":8111,"children":8112},{"style":558},[8113],{"type":55,"value":8114},"  before_script",{"type":28,"tag":116,"props":8116,"children":8117},{"style":564},[8118],{"type":55,"value":567},{"type":28,"tag":116,"props":8120,"children":8122},{"class":8121,"line":1411},[553,616],[8123,8127],{"type":28,"tag":116,"props":8124,"children":8125},{"style":564},[8126],{"type":55,"value":5346},{"type":28,"tag":116,"props":8128,"children":8129},{"style":596},[8130],{"type":55,"value":8131},"apk add --no-cache php-8.2-xdebug\n",{"type":28,"tag":116,"props":8133,"children":8135},{"class":8134,"line":1424},[553,616],[8136,8140],{"type":28,"tag":116,"props":8137,"children":8138},{"style":564},[8139],{"type":55,"value":5346},{"type":28,"tag":116,"props":8141,"children":8142},{"style":596},[8143],{"type":55,"value":8144},"shopware-cli project create shopware ${SHOPWARE_VERSION}\n",{"type":28,"tag":116,"props":8146,"children":8148},{"class":8147,"line":2278},[553,616],[8149,8153],{"type":28,"tag":116,"props":8150,"children":8151},{"style":564},[8152],{"type":55,"value":5346},{"type":28,"tag":116,"props":8154,"children":8155},{"style":596},[8156],{"type":55,"value":8157},"cd $SHOPWARE_ROOT\n",{"type":28,"tag":116,"props":8159,"children":8161},{"class":8160,"line":2286},[553,616],[8162,8166],{"type":28,"tag":116,"props":8163,"children":8164},{"style":564},[8165],{"type":55,"value":5346},{"type":28,"tag":116,"props":8167,"children":8168},{"style":596},[8169],{"type":55,"value":8170},"composer req --dev shopware/dev-tools phpunit/phpunit\n",{"type":28,"tag":116,"props":8172,"children":8174},{"class":8173,"line":2306},[553,616],[8175,8179],{"type":28,"tag":116,"props":8176,"children":8177},{"style":564},[8178],{"type":55,"value":5346},{"type":28,"tag":116,"props":8180,"children":8181},{"style":596},[8182],{"type":55,"value":8183},"git clone \"https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\" \"custom/plugins/${CI_PROJECT_NAME}\"\n",{"type":28,"tag":116,"props":8185,"children":8187},{"class":8186,"line":2327},[553,616],[8188,8192],{"type":28,"tag":116,"props":8189,"children":8190},{"style":564},[8191],{"type":55,"value":5346},{"type":28,"tag":116,"props":8193,"children":8194},{"style":596},[8195],{"type":55,"value":8196},"cd custom/plugins/${CI_PROJECT_NAME}\n",{"type":28,"tag":116,"props":8198,"children":8200},{"class":8199,"line":2339},[553,616],[8201,8205],{"type":28,"tag":116,"props":8202,"children":8203},{"style":564},[8204],{"type":55,"value":5346},{"type":28,"tag":116,"props":8206,"children":8207},{"style":596},[8208],{"type":55,"value":8209},"git checkout ${CI_COMMIT_SHA}\n",{"type":28,"tag":116,"props":8211,"children":8213},{"class":8212,"line":2355},[553,616],[8214,8218],{"type":28,"tag":116,"props":8215,"children":8216},{"style":564},[8217],{"type":55,"value":5346},{"type":28,"tag":116,"props":8219,"children":8220},{"style":596},[8221],{"type":55,"value":8222},"cd ${SHOPWARE_ROOT}\n",{"type":28,"tag":116,"props":8224,"children":8226},{"class":8225,"line":2363},[553,616],[8227,8231],{"type":28,"tag":116,"props":8228,"children":8229},{"style":564},[8230],{"type":55,"value":5346},{"type":28,"tag":116,"props":8232,"children":8233},{"style":596},[8234],{"type":55,"value":8235},"composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)\n",{"type":28,"tag":116,"props":8237,"children":8239},{"class":8238,"line":1837},[553,616],[8240,8244],{"type":28,"tag":116,"props":8241,"children":8242},{"style":564},[8243],{"type":55,"value":5346},{"type":28,"tag":116,"props":8245,"children":8246},{"style":596},[8247],{"type":55,"value":8196},{"type":28,"tag":116,"props":8249,"children":8250},{"class":553,"line":1838},[8251,8255],{"type":28,"tag":116,"props":8252,"children":8253},{"style":558},[8254],{"type":55,"value":5334},{"type":28,"tag":116,"props":8256,"children":8257},{"style":564},[8258],{"type":55,"value":567},{"type":28,"tag":116,"props":8260,"children":8262},{"class":8261,"line":1839},[553,616],[8263,8267],{"type":28,"tag":116,"props":8264,"children":8265},{"style":564},[8266],{"type":55,"value":5346},{"type":28,"tag":116,"props":8268,"children":8269},{"style":596},[8270],{"type":55,"value":8271},"${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml\n",{"type":28,"tag":116,"props":8273,"children":8274},{"class":553,"line":1840},[8275],{"type":28,"tag":116,"props":8276,"children":8277},{"emptyLinePlaceholder":1271},[8278],{"type":55,"value":1274},{"type":28,"tag":116,"props":8280,"children":8281},{"class":553,"line":2426},[8282,8286],{"type":28,"tag":116,"props":8283,"children":8284},{"style":558},[8285],{"type":55,"value":6475},{"type":28,"tag":116,"props":8287,"children":8288},{"style":564},[8289],{"type":55,"value":567},{"type":28,"tag":116,"props":8291,"children":8292},{"class":553,"line":2435},[8293,8297,8301,8305],{"type":28,"tag":116,"props":8294,"children":8295},{"style":564},[8296],{"type":55,"value":5346},{"type":28,"tag":116,"props":8298,"children":8299},{"style":558},[8300],{"type":55,"value":6492},{"type":28,"tag":116,"props":8302,"children":8303},{"style":564},[8304],{"type":55,"value":593},{"type":28,"tag":116,"props":8306,"children":8307},{"style":596},[8308],{"type":55,"value":6501},{"type":28,"tag":116,"props":8310,"children":8311},{"class":553,"line":2448},[8312,8316],{"type":28,"tag":116,"props":8313,"children":8314},{"style":558},[8315],{"type":55,"value":6510},{"type":28,"tag":116,"props":8317,"children":8318},{"style":564},[8319],{"type":55,"value":567},{"type":28,"tag":116,"props":8321,"children":8322},{"class":553,"line":2461},[8323,8327],{"type":28,"tag":116,"props":8324,"children":8325},{"style":564},[8326],{"type":55,"value":6523},{"type":28,"tag":116,"props":8328,"children":8329},{"style":596},[8330],{"type":55,"value":6528},{"type":28,"tag":116,"props":8332,"children":8333},{"class":553,"line":2490},[8334,8339,8343],{"type":28,"tag":116,"props":8335,"children":8336},{"style":558},[8337],{"type":55,"value":8338},"  coverage",{"type":28,"tag":116,"props":8340,"children":8341},{"style":564},[8342],{"type":55,"value":593},{"type":28,"tag":116,"props":8344,"children":8345},{"style":596},[8346],{"type":55,"value":8347},"/^\\s*Lines:\\s*\\d+.\\d+\\%/\n",{"type":28,"tag":116,"props":8349,"children":8350},{"class":553,"line":2498},[8351,8355],{"type":28,"tag":116,"props":8352,"children":8353},{"style":558},[8354],{"type":55,"value":6875},{"type":28,"tag":116,"props":8356,"children":8357},{"style":564},[8358],{"type":55,"value":567},{"type":28,"tag":116,"props":8360,"children":8361},{"class":553,"line":2506},[8362,8367],{"type":28,"tag":116,"props":8363,"children":8364},{"style":558},[8365],{"type":55,"value":8366},"    reports",{"type":28,"tag":116,"props":8368,"children":8369},{"style":564},[8370],{"type":55,"value":567},{"type":28,"tag":116,"props":8372,"children":8373},{"class":553,"line":2527},[8374,8379],{"type":28,"tag":116,"props":8375,"children":8376},{"style":558},[8377],{"type":55,"value":8378},"      coverage_report",{"type":28,"tag":116,"props":8380,"children":8381},{"style":564},[8382],{"type":55,"value":567},{"type":28,"tag":116,"props":8384,"children":8385},{"class":553,"line":2540},[8386,8391,8395],{"type":28,"tag":116,"props":8387,"children":8388},{"style":558},[8389],{"type":55,"value":8390},"        coverage_format",{"type":28,"tag":116,"props":8392,"children":8393},{"style":564},[8394],{"type":55,"value":593},{"type":28,"tag":116,"props":8396,"children":8397},{"style":596},[8398],{"type":55,"value":8399},"cobertura\n",{"type":28,"tag":116,"props":8401,"children":8402},{"class":553,"line":2553},[8403,8408,8412],{"type":28,"tag":116,"props":8404,"children":8405},{"style":558},[8406],{"type":55,"value":8407},"        path",{"type":28,"tag":116,"props":8409,"children":8410},{"style":564},[8411],{"type":55,"value":593},{"type":28,"tag":116,"props":8413,"children":8414},{"style":596},[8415],{"type":55,"value":8416},"coverage.cobertura.xml\n",{"type":28,"tag":116,"props":8418,"children":8419},{"class":553,"line":2574},[8420,8424],{"type":28,"tag":116,"props":8421,"children":8422},{"style":558},[8423],{"type":55,"value":5376},{"type":28,"tag":116,"props":8425,"children":8426},{"style":564},[8427],{"type":55,"value":567},{"type":28,"tag":116,"props":8429,"children":8430},{"class":553,"line":2591},[8431,8435,8439,8443],{"type":28,"tag":116,"props":8432,"children":8433},{"style":564},[8434],{"type":55,"value":5346},{"type":28,"tag":116,"props":8436,"children":8437},{"style":558},[8438],{"type":55,"value":5609},{"type":28,"tag":116,"props":8440,"children":8441},{"style":564},[8442],{"type":55,"value":593},{"type":28,"tag":116,"props":8444,"children":8445},{"style":596},[8446],{"type":55,"value":7595},{"type":28,"tag":116,"props":8448,"children":8449},{"class":553,"line":2599},[8450,8454,8458,8462],{"type":28,"tag":116,"props":8451,"children":8452},{"style":564},[8453],{"type":55,"value":5346},{"type":28,"tag":116,"props":8455,"children":8456},{"style":558},[8457],{"type":55,"value":5609},{"type":28,"tag":116,"props":8459,"children":8460},{"style":564},[8461],{"type":55,"value":593},{"type":28,"tag":116,"props":8463,"children":8464},{"style":596},[8465],{"type":55,"value":5618},{"type":28,"tag":116,"props":8467,"children":8468},{"class":553,"line":2620},[8469,8473,8477],{"type":28,"tag":116,"props":8470,"children":8471},{"style":558},[8472],{"type":55,"value":5626},{"type":28,"tag":116,"props":8474,"children":8475},{"style":564},[8476],{"type":55,"value":593},{"type":28,"tag":116,"props":8478,"children":8479},{"style":596},[8480],{"type":55,"value":5635},{"type":28,"tag":116,"props":8482,"children":8483},{"class":553,"line":2637},[8484,8488,8492,8496],{"type":28,"tag":116,"props":8485,"children":8486},{"style":564},[8487],{"type":55,"value":5346},{"type":28,"tag":116,"props":8489,"children":8490},{"style":558},[8491],{"type":55,"value":5609},{"type":28,"tag":116,"props":8493,"children":8494},{"style":564},[8495],{"type":55,"value":593},{"type":28,"tag":116,"props":8497,"children":8498},{"style":596},[8499],{"type":55,"value":5655},{"type":28,"tag":47,"props":8501,"children":8502},{},[8503],{"type":55,"value":1439},{"type":28,"tag":838,"props":8505,"children":8506},{},[8507,8512,8517,8522,8527],{"type":28,"tag":690,"props":8508,"children":8509},{},[8510],{"type":55,"value":8511},"We disable automatic repository cloning (16)",{"type":28,"tag":690,"props":8513,"children":8514},{},[8515],{"type":55,"value":8516},"We include a database service (9-14)",{"type":28,"tag":690,"props":8518,"children":8519},{},[8520],{"type":55,"value":8521},"We set some required Shopware env variables (20-23)",{"type":28,"tag":690,"props":8523,"children":8524},{},[8525],{"type":55,"value":8526},"Create an empty shopware project with phpunit and xdebug (27-36)",{"type":28,"tag":690,"props":8528,"children":8529},{},[8530],{"type":55,"value":8531},"Run PHPUnit with code coverage generation as text and in cobertura format (38)",{"type":28,"tag":47,"props":8533,"children":8534},{},[8535],{"type":55,"value":8536},"Like the Code quality pipeline, this takes full advantage of GitLab coverage reporting",{"type":28,"tag":79,"props":8538,"children":8540},{"id":8539},"putting-it-all-together",[8541],{"type":55,"value":8542},"Putting it all together",{"type":28,"tag":47,"props":8544,"children":8545},{},[8546],{"type":55,"value":8547},"For this part, we don't include the build and release part.",{"type":28,"tag":534,"props":8549,"children":8551},{"code":8550,"filename":5436,"language":544,"meta":7,"className":545,"style":7},"stages:\n   - test\n\nphpunit:\n  stage: test\n  image:\n    name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n    entrypoint: [\"\"]\n  services:\n    - name: mysql:8.3.0\n      alias: test_database\n      variables:\n        MYSQL_SKIP_TEST_DB: 'yes'\n        MYSQL_ALLOW_EMPTY_PASSWORD: yes\n  variables:\n    GIT_STRATEGY: none\n    SHOPWARE_ROOT: ${CI_PROJECT_DIR}/shopware\n    SHOPWARE_VERSION: 6.6.10.13\n    \n    APP_SECRET: def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48\n    MESSENGER_TRANSPORT_DSN: sync://\n    DATABASE_URL: mysql://root@test_database/shopware\n    COMPOSER_CACHE_DIR: ${CI_PROJECT_DIR}/.composer\n\n    XDEBUG_MODE: coverage\n  before_script:\n    - apk add --no-cache php-8.2-xdebug\n    - shopware-cli project create shopware ${SHOPWARE_VERSION}\n    - cd $SHOPWARE_ROOT\n    - composer req --dev shopware/dev-tools phpunit/phpunit\n    - git clone \"https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\" \"custom/plugins/${CI_PROJECT_NAME}\"\n    - cd custom/plugins/${CI_PROJECT_NAME}\n    - git checkout ${CI_COMMIT_SHA}\n    - cd ${SHOPWARE_ROOT}\n    - composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)\n    - cd custom/plugins/${CI_PROJECT_NAME}\n  script:\n    - ${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml\n\n  cache:\n    - key: $CI_JOB_NAME\n      paths:\n        - $COMPOSER_CACHE_DIR\n  coverage: /^\\s*Lines:\\s*\\d+.\\d+\\%/\n  artifacts:\n    reports:\n      coverage_report:\n        coverage_format: cobertura\n        path: coverage.cobertura.xml\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n    - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n      when: never\n    - if: $CI_COMMIT_BRANCH\n\ncode-quality:\n   image:\n      name: ghcr.io/shopware/shopware-cli:latest-php-8.2\n      entrypoint: [\"\"]\n   stage: test\n   script:\n      - shopware-cli extension validate --full . | tee report.json\n   artifacts:\n      reports:\n         codequality: report.json\n   rules:\n      - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n      - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n        when: never\n      - if: $CI_COMMIT_BRANCH\n",[8552],{"type":28,"tag":548,"props":8553,"children":8554},{"__ignoreMap":7},[8555,8566,8577,8584,8595,8610,8621,8636,8655,8666,8685,8700,8711,8726,8741,8752,8767,8782,8797,8804,8819,8834,8849,8864,8871,8886,8897,8908,8919,8930,8941,8952,8963,8974,8985,8996,9007,9018,9029,9036,9047,9066,9077,9088,9103,9114,9125,9136,9151,9166,9177,9196,9215,9230,9249,9256,9267,9278,9293,9312,9327,9338,9349,9360,9371,9386,9397,9416,9435,9450],{"type":28,"tag":116,"props":8556,"children":8557},{"class":553,"line":554},[8558,8562],{"type":28,"tag":116,"props":8559,"children":8560},{"style":558},[8561],{"type":55,"value":5257},{"type":28,"tag":116,"props":8563,"children":8564},{"style":564},[8565],{"type":55,"value":567},{"type":28,"tag":116,"props":8567,"children":8568},{"class":553,"line":271},[8569,8573],{"type":28,"tag":116,"props":8570,"children":8571},{"style":564},[8572],{"type":55,"value":7758},{"type":28,"tag":116,"props":8574,"children":8575},{"style":596},[8576],{"type":55,"value":7413},{"type":28,"tag":116,"props":8578,"children":8579},{"class":553,"line":582},[8580],{"type":28,"tag":116,"props":8581,"children":8582},{"emptyLinePlaceholder":1271},[8583],{"type":55,"value":1274},{"type":28,"tag":116,"props":8585,"children":8586},{"class":553,"line":602},[8587,8591],{"type":28,"tag":116,"props":8588,"children":8589},{"style":558},[8590],{"type":55,"value":7777},{"type":28,"tag":116,"props":8592,"children":8593},{"style":564},[8594],{"type":55,"value":567},{"type":28,"tag":116,"props":8596,"children":8597},{"class":553,"line":539},[8598,8602,8606],{"type":28,"tag":116,"props":8599,"children":8600},{"style":558},[8601],{"type":55,"value":5318},{"type":28,"tag":116,"props":8603,"children":8604},{"style":564},[8605],{"type":55,"value":593},{"type":28,"tag":116,"props":8607,"children":8608},{"style":596},[8609],{"type":55,"value":7413},{"type":28,"tag":116,"props":8611,"children":8612},{"class":553,"line":540},[8613,8617],{"type":28,"tag":116,"props":8614,"children":8615},{"style":558},[8616],{"type":55,"value":5301},{"type":28,"tag":116,"props":8618,"children":8619},{"style":564},[8620],{"type":55,"value":567},{"type":28,"tag":116,"props":8622,"children":8623},{"class":553,"line":541},[8624,8628,8632],{"type":28,"tag":116,"props":8625,"children":8626},{"style":558},[8627],{"type":55,"value":5515},{"type":28,"tag":116,"props":8629,"children":8630},{"style":564},[8631],{"type":55,"value":593},{"type":28,"tag":116,"props":8633,"children":8634},{"style":596},[8635],{"type":55,"value":6364},{"type":28,"tag":116,"props":8637,"children":8638},{"class":553,"line":542},[8639,8643,8647,8651],{"type":28,"tag":116,"props":8640,"children":8641},{"style":558},[8642],{"type":55,"value":5532},{"type":28,"tag":116,"props":8644,"children":8645},{"style":564},[8646],{"type":55,"value":5537},{"type":28,"tag":116,"props":8648,"children":8649},{"style":596},[8650],{"type":55,"value":5542},{"type":28,"tag":116,"props":8652,"children":8653},{"style":564},[8654],{"type":55,"value":5547},{"type":28,"tag":116,"props":8656,"children":8657},{"class":553,"line":543},[8658,8662],{"type":28,"tag":116,"props":8659,"children":8660},{"style":558},[8661],{"type":55,"value":7850},{"type":28,"tag":116,"props":8663,"children":8664},{"style":564},[8665],{"type":55,"value":567},{"type":28,"tag":116,"props":8667,"children":8668},{"class":553,"line":1203},[8669,8673,8677,8681],{"type":28,"tag":116,"props":8670,"children":8671},{"style":564},[8672],{"type":55,"value":5346},{"type":28,"tag":116,"props":8674,"children":8675},{"style":558},[8676],{"type":55,"value":1657},{"type":28,"tag":116,"props":8678,"children":8679},{"style":564},[8680],{"type":55,"value":593},{"type":28,"tag":116,"props":8682,"children":8683},{"style":596},[8684],{"type":55,"value":7875},{"type":28,"tag":116,"props":8686,"children":8687},{"class":553,"line":1216},[8688,8692,8696],{"type":28,"tag":116,"props":8689,"children":8690},{"style":558},[8691],{"type":55,"value":7884},{"type":28,"tag":116,"props":8693,"children":8694},{"style":564},[8695],{"type":55,"value":593},{"type":28,"tag":116,"props":8697,"children":8698},{"style":596},[8699],{"type":55,"value":7893},{"type":28,"tag":116,"props":8701,"children":8702},{"class":553,"line":107},[8703,8707],{"type":28,"tag":116,"props":8704,"children":8705},{"style":558},[8706],{"type":55,"value":7902},{"type":28,"tag":116,"props":8708,"children":8709},{"style":564},[8710],{"type":55,"value":567},{"type":28,"tag":116,"props":8712,"children":8713},{"class":553,"line":1241},[8714,8718,8722],{"type":28,"tag":116,"props":8715,"children":8716},{"style":558},[8717],{"type":55,"value":7915},{"type":28,"tag":116,"props":8719,"children":8720},{"style":564},[8721],{"type":55,"value":593},{"type":28,"tag":116,"props":8723,"children":8724},{"style":596},[8725],{"type":55,"value":7924},{"type":28,"tag":116,"props":8727,"children":8728},{"class":553,"line":1254},[8729,8733,8737],{"type":28,"tag":116,"props":8730,"children":8731},{"style":558},[8732],{"type":55,"value":7933},{"type":28,"tag":116,"props":8734,"children":8735},{"style":564},[8736],{"type":55,"value":593},{"type":28,"tag":116,"props":8738,"children":8739},{"style":2170},[8740],{"type":55,"value":7942},{"type":28,"tag":116,"props":8742,"children":8743},{"class":553,"line":1267},[8744,8748],{"type":28,"tag":116,"props":8745,"children":8746},{"style":558},[8747],{"type":55,"value":6406},{"type":28,"tag":116,"props":8749,"children":8750},{"style":564},[8751],{"type":55,"value":567},{"type":28,"tag":116,"props":8753,"children":8754},{"class":553,"line":1277},[8755,8759,8763],{"type":28,"tag":116,"props":8756,"children":8757},{"style":558},[8758],{"type":55,"value":7962},{"type":28,"tag":116,"props":8760,"children":8761},{"style":564},[8762],{"type":55,"value":593},{"type":28,"tag":116,"props":8764,"children":8765},{"style":596},[8766],{"type":55,"value":7971},{"type":28,"tag":116,"props":8768,"children":8769},{"class":553,"line":1290},[8770,8774,8778],{"type":28,"tag":116,"props":8771,"children":8772},{"style":558},[8773],{"type":55,"value":7979},{"type":28,"tag":116,"props":8775,"children":8776},{"style":564},[8777],{"type":55,"value":593},{"type":28,"tag":116,"props":8779,"children":8780},{"style":596},[8781],{"type":55,"value":7988},{"type":28,"tag":116,"props":8783,"children":8784},{"class":553,"line":1303},[8785,8789,8793],{"type":28,"tag":116,"props":8786,"children":8787},{"style":558},[8788],{"type":55,"value":7996},{"type":28,"tag":116,"props":8790,"children":8791},{"style":564},[8792],{"type":55,"value":593},{"type":28,"tag":116,"props":8794,"children":8795},{"style":2170},[8796],{"type":55,"value":8005},{"type":28,"tag":116,"props":8798,"children":8799},{"class":553,"line":1312},[8800],{"type":28,"tag":116,"props":8801,"children":8802},{"style":564},[8803],{"type":55,"value":1110},{"type":28,"tag":116,"props":8805,"children":8806},{"class":553,"line":1325},[8807,8811,8815],{"type":28,"tag":116,"props":8808,"children":8809},{"style":558},[8810],{"type":55,"value":8021},{"type":28,"tag":116,"props":8812,"children":8813},{"style":564},[8814],{"type":55,"value":593},{"type":28,"tag":116,"props":8816,"children":8817},{"style":596},[8818],{"type":55,"value":8030},{"type":28,"tag":116,"props":8820,"children":8821},{"class":553,"line":1338},[8822,8826,8830],{"type":28,"tag":116,"props":8823,"children":8824},{"style":558},[8825],{"type":55,"value":8039},{"type":28,"tag":116,"props":8827,"children":8828},{"style":564},[8829],{"type":55,"value":593},{"type":28,"tag":116,"props":8831,"children":8832},{"style":596},[8833],{"type":55,"value":8048},{"type":28,"tag":116,"props":8835,"children":8836},{"class":553,"line":1351},[8837,8841,8845],{"type":28,"tag":116,"props":8838,"children":8839},{"style":558},[8840],{"type":55,"value":8057},{"type":28,"tag":116,"props":8842,"children":8843},{"style":564},[8844],{"type":55,"value":593},{"type":28,"tag":116,"props":8846,"children":8847},{"style":596},[8848],{"type":55,"value":8066},{"type":28,"tag":116,"props":8850,"children":8851},{"class":553,"line":1359},[8852,8856,8860],{"type":28,"tag":116,"props":8853,"children":8854},{"style":558},[8855],{"type":55,"value":6418},{"type":28,"tag":116,"props":8857,"children":8858},{"style":564},[8859],{"type":55,"value":593},{"type":28,"tag":116,"props":8861,"children":8862},{"style":596},[8863],{"type":55,"value":6427},{"type":28,"tag":116,"props":8865,"children":8866},{"class":553,"line":1372},[8867],{"type":28,"tag":116,"props":8868,"children":8869},{"emptyLinePlaceholder":1271},[8870],{"type":55,"value":1274},{"type":28,"tag":116,"props":8872,"children":8873},{"class":553,"line":1385},[8874,8878,8882],{"type":28,"tag":116,"props":8875,"children":8876},{"style":558},[8877],{"type":55,"value":8097},{"type":28,"tag":116,"props":8879,"children":8880},{"style":564},[8881],{"type":55,"value":593},{"type":28,"tag":116,"props":8883,"children":8884},{"style":596},[8885],{"type":55,"value":8106},{"type":28,"tag":116,"props":8887,"children":8888},{"class":553,"line":1398},[8889,8893],{"type":28,"tag":116,"props":8890,"children":8891},{"style":558},[8892],{"type":55,"value":8114},{"type":28,"tag":116,"props":8894,"children":8895},{"style":564},[8896],{"type":55,"value":567},{"type":28,"tag":116,"props":8898,"children":8899},{"class":553,"line":1411},[8900,8904],{"type":28,"tag":116,"props":8901,"children":8902},{"style":564},[8903],{"type":55,"value":5346},{"type":28,"tag":116,"props":8905,"children":8906},{"style":596},[8907],{"type":55,"value":8131},{"type":28,"tag":116,"props":8909,"children":8910},{"class":553,"line":1424},[8911,8915],{"type":28,"tag":116,"props":8912,"children":8913},{"style":564},[8914],{"type":55,"value":5346},{"type":28,"tag":116,"props":8916,"children":8917},{"style":596},[8918],{"type":55,"value":8144},{"type":28,"tag":116,"props":8920,"children":8921},{"class":553,"line":2278},[8922,8926],{"type":28,"tag":116,"props":8923,"children":8924},{"style":564},[8925],{"type":55,"value":5346},{"type":28,"tag":116,"props":8927,"children":8928},{"style":596},[8929],{"type":55,"value":8157},{"type":28,"tag":116,"props":8931,"children":8932},{"class":553,"line":2286},[8933,8937],{"type":28,"tag":116,"props":8934,"children":8935},{"style":564},[8936],{"type":55,"value":5346},{"type":28,"tag":116,"props":8938,"children":8939},{"style":596},[8940],{"type":55,"value":8170},{"type":28,"tag":116,"props":8942,"children":8943},{"class":553,"line":2306},[8944,8948],{"type":28,"tag":116,"props":8945,"children":8946},{"style":564},[8947],{"type":55,"value":5346},{"type":28,"tag":116,"props":8949,"children":8950},{"style":596},[8951],{"type":55,"value":8183},{"type":28,"tag":116,"props":8953,"children":8954},{"class":553,"line":2327},[8955,8959],{"type":28,"tag":116,"props":8956,"children":8957},{"style":564},[8958],{"type":55,"value":5346},{"type":28,"tag":116,"props":8960,"children":8961},{"style":596},[8962],{"type":55,"value":8196},{"type":28,"tag":116,"props":8964,"children":8965},{"class":553,"line":2339},[8966,8970],{"type":28,"tag":116,"props":8967,"children":8968},{"style":564},[8969],{"type":55,"value":5346},{"type":28,"tag":116,"props":8971,"children":8972},{"style":596},[8973],{"type":55,"value":8209},{"type":28,"tag":116,"props":8975,"children":8976},{"class":553,"line":2355},[8977,8981],{"type":28,"tag":116,"props":8978,"children":8979},{"style":564},[8980],{"type":55,"value":5346},{"type":28,"tag":116,"props":8982,"children":8983},{"style":596},[8984],{"type":55,"value":8222},{"type":28,"tag":116,"props":8986,"children":8987},{"class":553,"line":2363},[8988,8992],{"type":28,"tag":116,"props":8989,"children":8990},{"style":564},[8991],{"type":55,"value":5346},{"type":28,"tag":116,"props":8993,"children":8994},{"style":596},[8995],{"type":55,"value":8235},{"type":28,"tag":116,"props":8997,"children":8998},{"class":553,"line":1837},[8999,9003],{"type":28,"tag":116,"props":9000,"children":9001},{"style":564},[9002],{"type":55,"value":5346},{"type":28,"tag":116,"props":9004,"children":9005},{"style":596},[9006],{"type":55,"value":8196},{"type":28,"tag":116,"props":9008,"children":9009},{"class":553,"line":1838},[9010,9014],{"type":28,"tag":116,"props":9011,"children":9012},{"style":558},[9013],{"type":55,"value":5334},{"type":28,"tag":116,"props":9015,"children":9016},{"style":564},[9017],{"type":55,"value":567},{"type":28,"tag":116,"props":9019,"children":9020},{"class":553,"line":1839},[9021,9025],{"type":28,"tag":116,"props":9022,"children":9023},{"style":564},[9024],{"type":55,"value":5346},{"type":28,"tag":116,"props":9026,"children":9027},{"style":596},[9028],{"type":55,"value":8271},{"type":28,"tag":116,"props":9030,"children":9031},{"class":553,"line":1840},[9032],{"type":28,"tag":116,"props":9033,"children":9034},{"emptyLinePlaceholder":1271},[9035],{"type":55,"value":1274},{"type":28,"tag":116,"props":9037,"children":9038},{"class":553,"line":2426},[9039,9043],{"type":28,"tag":116,"props":9040,"children":9041},{"style":558},[9042],{"type":55,"value":6475},{"type":28,"tag":116,"props":9044,"children":9045},{"style":564},[9046],{"type":55,"value":567},{"type":28,"tag":116,"props":9048,"children":9049},{"class":553,"line":2435},[9050,9054,9058,9062],{"type":28,"tag":116,"props":9051,"children":9052},{"style":564},[9053],{"type":55,"value":5346},{"type":28,"tag":116,"props":9055,"children":9056},{"style":558},[9057],{"type":55,"value":6492},{"type":28,"tag":116,"props":9059,"children":9060},{"style":564},[9061],{"type":55,"value":593},{"type":28,"tag":116,"props":9063,"children":9064},{"style":596},[9065],{"type":55,"value":6501},{"type":28,"tag":116,"props":9067,"children":9068},{"class":553,"line":2448},[9069,9073],{"type":28,"tag":116,"props":9070,"children":9071},{"style":558},[9072],{"type":55,"value":6510},{"type":28,"tag":116,"props":9074,"children":9075},{"style":564},[9076],{"type":55,"value":567},{"type":28,"tag":116,"props":9078,"children":9079},{"class":553,"line":2461},[9080,9084],{"type":28,"tag":116,"props":9081,"children":9082},{"style":564},[9083],{"type":55,"value":6523},{"type":28,"tag":116,"props":9085,"children":9086},{"style":596},[9087],{"type":55,"value":6528},{"type":28,"tag":116,"props":9089,"children":9090},{"class":553,"line":2490},[9091,9095,9099],{"type":28,"tag":116,"props":9092,"children":9093},{"style":558},[9094],{"type":55,"value":8338},{"type":28,"tag":116,"props":9096,"children":9097},{"style":564},[9098],{"type":55,"value":593},{"type":28,"tag":116,"props":9100,"children":9101},{"style":596},[9102],{"type":55,"value":8347},{"type":28,"tag":116,"props":9104,"children":9105},{"class":553,"line":2498},[9106,9110],{"type":28,"tag":116,"props":9107,"children":9108},{"style":558},[9109],{"type":55,"value":6875},{"type":28,"tag":116,"props":9111,"children":9112},{"style":564},[9113],{"type":55,"value":567},{"type":28,"tag":116,"props":9115,"children":9116},{"class":553,"line":2506},[9117,9121],{"type":28,"tag":116,"props":9118,"children":9119},{"style":558},[9120],{"type":55,"value":8366},{"type":28,"tag":116,"props":9122,"children":9123},{"style":564},[9124],{"type":55,"value":567},{"type":28,"tag":116,"props":9126,"children":9127},{"class":553,"line":2527},[9128,9132],{"type":28,"tag":116,"props":9129,"children":9130},{"style":558},[9131],{"type":55,"value":8378},{"type":28,"tag":116,"props":9133,"children":9134},{"style":564},[9135],{"type":55,"value":567},{"type":28,"tag":116,"props":9137,"children":9138},{"class":553,"line":2540},[9139,9143,9147],{"type":28,"tag":116,"props":9140,"children":9141},{"style":558},[9142],{"type":55,"value":8390},{"type":28,"tag":116,"props":9144,"children":9145},{"style":564},[9146],{"type":55,"value":593},{"type":28,"tag":116,"props":9148,"children":9149},{"style":596},[9150],{"type":55,"value":8399},{"type":28,"tag":116,"props":9152,"children":9153},{"class":553,"line":2553},[9154,9158,9162],{"type":28,"tag":116,"props":9155,"children":9156},{"style":558},[9157],{"type":55,"value":8407},{"type":28,"tag":116,"props":9159,"children":9160},{"style":564},[9161],{"type":55,"value":593},{"type":28,"tag":116,"props":9163,"children":9164},{"style":596},[9165],{"type":55,"value":8416},{"type":28,"tag":116,"props":9167,"children":9168},{"class":553,"line":2574},[9169,9173],{"type":28,"tag":116,"props":9170,"children":9171},{"style":558},[9172],{"type":55,"value":5376},{"type":28,"tag":116,"props":9174,"children":9175},{"style":564},[9176],{"type":55,"value":567},{"type":28,"tag":116,"props":9178,"children":9179},{"class":553,"line":2591},[9180,9184,9188,9192],{"type":28,"tag":116,"props":9181,"children":9182},{"style":564},[9183],{"type":55,"value":5346},{"type":28,"tag":116,"props":9185,"children":9186},{"style":558},[9187],{"type":55,"value":5609},{"type":28,"tag":116,"props":9189,"children":9190},{"style":564},[9191],{"type":55,"value":593},{"type":28,"tag":116,"props":9193,"children":9194},{"style":596},[9195],{"type":55,"value":7595},{"type":28,"tag":116,"props":9197,"children":9198},{"class":553,"line":2599},[9199,9203,9207,9211],{"type":28,"tag":116,"props":9200,"children":9201},{"style":564},[9202],{"type":55,"value":5346},{"type":28,"tag":116,"props":9204,"children":9205},{"style":558},[9206],{"type":55,"value":5609},{"type":28,"tag":116,"props":9208,"children":9209},{"style":564},[9210],{"type":55,"value":593},{"type":28,"tag":116,"props":9212,"children":9213},{"style":596},[9214],{"type":55,"value":5618},{"type":28,"tag":116,"props":9216,"children":9217},{"class":553,"line":2620},[9218,9222,9226],{"type":28,"tag":116,"props":9219,"children":9220},{"style":558},[9221],{"type":55,"value":5626},{"type":28,"tag":116,"props":9223,"children":9224},{"style":564},[9225],{"type":55,"value":593},{"type":28,"tag":116,"props":9227,"children":9228},{"style":596},[9229],{"type":55,"value":5635},{"type":28,"tag":116,"props":9231,"children":9232},{"class":553,"line":2637},[9233,9237,9241,9245],{"type":28,"tag":116,"props":9234,"children":9235},{"style":564},[9236],{"type":55,"value":5346},{"type":28,"tag":116,"props":9238,"children":9239},{"style":558},[9240],{"type":55,"value":5609},{"type":28,"tag":116,"props":9242,"children":9243},{"style":564},[9244],{"type":55,"value":593},{"type":28,"tag":116,"props":9246,"children":9247},{"style":596},[9248],{"type":55,"value":5655},{"type":28,"tag":116,"props":9250,"children":9251},{"class":553,"line":2645},[9252],{"type":28,"tag":116,"props":9253,"children":9254},{"emptyLinePlaceholder":1271},[9255],{"type":55,"value":1274},{"type":28,"tag":116,"props":9257,"children":9258},{"class":553,"line":2658},[9259,9263],{"type":28,"tag":116,"props":9260,"children":9261},{"style":558},[9262],{"type":55,"value":7271},{"type":28,"tag":116,"props":9264,"children":9265},{"style":564},[9266],{"type":55,"value":567},{"type":28,"tag":116,"props":9268,"children":9269},{"class":553,"line":2671},[9270,9274],{"type":28,"tag":116,"props":9271,"children":9272},{"style":558},[9273],{"type":55,"value":7439},{"type":28,"tag":116,"props":9275,"children":9276},{"style":564},[9277],{"type":55,"value":567},{"type":28,"tag":116,"props":9279,"children":9280},{"class":553,"line":2689},[9281,9285,9289],{"type":28,"tag":116,"props":9282,"children":9283},{"style":558},[9284],{"type":55,"value":7452},{"type":28,"tag":116,"props":9286,"children":9287},{"style":564},[9288],{"type":55,"value":593},{"type":28,"tag":116,"props":9290,"children":9291},{"style":596},[9292],{"type":55,"value":6364},{"type":28,"tag":116,"props":9294,"children":9295},{"class":553,"line":2697},[9296,9300,9304,9308],{"type":28,"tag":116,"props":9297,"children":9298},{"style":558},[9299],{"type":55,"value":7468},{"type":28,"tag":116,"props":9301,"children":9302},{"style":564},[9303],{"type":55,"value":5537},{"type":28,"tag":116,"props":9305,"children":9306},{"style":596},[9307],{"type":55,"value":5542},{"type":28,"tag":116,"props":9309,"children":9310},{"style":564},[9311],{"type":55,"value":5547},{"type":28,"tag":116,"props":9313,"children":9314},{"class":553,"line":2710},[9315,9319,9323],{"type":28,"tag":116,"props":9316,"children":9317},{"style":558},[9318],{"type":55,"value":7488},{"type":28,"tag":116,"props":9320,"children":9321},{"style":564},[9322],{"type":55,"value":593},{"type":28,"tag":116,"props":9324,"children":9325},{"style":596},[9326],{"type":55,"value":7413},{"type":28,"tag":116,"props":9328,"children":9329},{"class":553,"line":2719},[9330,9334],{"type":28,"tag":116,"props":9331,"children":9332},{"style":558},[9333],{"type":55,"value":7504},{"type":28,"tag":116,"props":9335,"children":9336},{"style":564},[9337],{"type":55,"value":567},{"type":28,"tag":116,"props":9339,"children":9340},{"class":553,"line":2728},[9341,9345],{"type":28,"tag":116,"props":9342,"children":9343},{"style":564},[9344],{"type":55,"value":622},{"type":28,"tag":116,"props":9346,"children":9347},{"style":596},[9348],{"type":55,"value":7520},{"type":28,"tag":116,"props":9350,"children":9351},{"class":553,"line":2741},[9352,9356],{"type":28,"tag":116,"props":9353,"children":9354},{"style":558},[9355],{"type":55,"value":7528},{"type":28,"tag":116,"props":9357,"children":9358},{"style":564},[9359],{"type":55,"value":567},{"type":28,"tag":116,"props":9361,"children":9362},{"class":553,"line":2749},[9363,9367],{"type":28,"tag":116,"props":9364,"children":9365},{"style":558},[9366],{"type":55,"value":7540},{"type":28,"tag":116,"props":9368,"children":9369},{"style":564},[9370],{"type":55,"value":567},{"type":28,"tag":116,"props":9372,"children":9373},{"class":553,"line":2758},[9374,9378,9382],{"type":28,"tag":116,"props":9375,"children":9376},{"style":558},[9377],{"type":55,"value":7552},{"type":28,"tag":116,"props":9379,"children":9380},{"style":564},[9381],{"type":55,"value":593},{"type":28,"tag":116,"props":9383,"children":9384},{"style":596},[9385],{"type":55,"value":7561},{"type":28,"tag":116,"props":9387,"children":9388},{"class":553,"line":2766},[9389,9393],{"type":28,"tag":116,"props":9390,"children":9391},{"style":558},[9392],{"type":55,"value":7570},{"type":28,"tag":116,"props":9394,"children":9395},{"style":564},[9396],{"type":55,"value":567},{"type":28,"tag":116,"props":9398,"children":9399},{"class":553,"line":2779},[9400,9404,9408,9412],{"type":28,"tag":116,"props":9401,"children":9402},{"style":564},[9403],{"type":55,"value":622},{"type":28,"tag":116,"props":9405,"children":9406},{"style":558},[9407],{"type":55,"value":5609},{"type":28,"tag":116,"props":9409,"children":9410},{"style":564},[9411],{"type":55,"value":593},{"type":28,"tag":116,"props":9413,"children":9414},{"style":596},[9415],{"type":55,"value":7595},{"type":28,"tag":116,"props":9417,"children":9418},{"class":553,"line":2792},[9419,9423,9427,9431],{"type":28,"tag":116,"props":9420,"children":9421},{"style":564},[9422],{"type":55,"value":622},{"type":28,"tag":116,"props":9424,"children":9425},{"style":558},[9426],{"type":55,"value":5609},{"type":28,"tag":116,"props":9428,"children":9429},{"style":564},[9430],{"type":55,"value":593},{"type":28,"tag":116,"props":9432,"children":9433},{"style":596},[9434],{"type":55,"value":5618},{"type":28,"tag":116,"props":9436,"children":9437},{"class":553,"line":2813},[9438,9442,9446],{"type":28,"tag":116,"props":9439,"children":9440},{"style":558},[9441],{"type":55,"value":7624},{"type":28,"tag":116,"props":9443,"children":9444},{"style":564},[9445],{"type":55,"value":593},{"type":28,"tag":116,"props":9447,"children":9448},{"style":596},[9449],{"type":55,"value":5635},{"type":28,"tag":116,"props":9451,"children":9452},{"class":553,"line":2826},[9453,9457,9461,9465],{"type":28,"tag":116,"props":9454,"children":9455},{"style":564},[9456],{"type":55,"value":622},{"type":28,"tag":116,"props":9458,"children":9459},{"style":558},[9460],{"type":55,"value":5609},{"type":28,"tag":116,"props":9462,"children":9463},{"style":564},[9464],{"type":55,"value":593},{"type":28,"tag":116,"props":9466,"children":9467},{"style":596},[9468],{"type":55,"value":5655},{"type":28,"tag":1705,"props":9470,"children":9471},{},[9472],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":9474},[9475,9478,9481],{"id":7271,"depth":271,"text":7274,"children":9476},[9477],{"id":7374,"depth":582,"text":7377},{"id":7670,"depth":271,"text":7241,"children":9479},[9480],{"id":7716,"depth":582,"text":7719},{"id":8539,"depth":271,"text":8542},{"_path":440,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":441,"description":442,"author":394,"image":395,"releaseDate":443,"blogCategories":9483,"articleTags":9484,"tags":9485,"body":9486,"_type":275,"_id":447,"_source":277,"_file":448,"_stem":449,"_extension":280},[398,399],[399,412],[23],{"type":25,"children":9487,"toc":10945},[9488,9493,9498,9503,9508,9513,9531,9536,9578,9584,9597,9610,9615,9621,9634,9647,9656,9662,9667,9780,10298,10333,10344,10347,10352,10513,10526,10532,10537,10607,10612,10618,10623,10634,10647,10681,10708,10720,10741,10754,10757,10762,10775,10793,10798,10803,10923,10941],{"type":28,"tag":47,"props":9489,"children":9490},{},[9491],{"type":55,"value":9492},"Managing a multiservice server can be tricky. Not every software is compatible with another, for example different requirements for database or PHP-versions.",{"type":28,"tag":47,"props":9494,"children":9495},{},[9496],{"type":55,"value":9497},"Additionally, all the software should be in the latest version, to mitigate possible security risks.",{"type":28,"tag":47,"props":9499,"children":9500},{},[9501],{"type":55,"value":9502},"There are many ways to handle this: Ansible, Chef etc.",{"type":28,"tag":47,"props":9504,"children":9505},{},[9506],{"type":55,"value":9507},"Out goal was to have an easy to use, automated and free solution.",{"type":28,"tag":47,"props":9509,"children":9510},{},[9511],{"type":55,"value":9512},"Here are the goals:",{"type":28,"tag":686,"props":9514,"children":9515},{},[9516,9521,9526],{"type":28,"tag":690,"props":9517,"children":9518},{},[9519],{"type":55,"value":9520},"use the GitOps approach to store and version control the deployment",{"type":28,"tag":690,"props":9522,"children":9523},{},[9524],{"type":55,"value":9525},"use containers to run the software",{"type":28,"tag":690,"props":9527,"children":9528},{},[9529],{"type":55,"value":9530},"get automated security updates and opt in for minor/major version updates",{"type":28,"tag":47,"props":9532,"children":9533},{},[9534],{"type":55,"value":9535},"This is the stack we ended with:",{"type":28,"tag":686,"props":9537,"children":9538},{},[9539,9556,9567],{"type":28,"tag":690,"props":9540,"children":9541},{},[9542,9547,9549,9554],{"type":28,"tag":520,"props":9543,"children":9545},{"href":9544},"https://www.docker.com/",[9546],{"type":55,"value":307},{"type":55,"value":9548}," and ",{"type":28,"tag":520,"props":9550,"children":9551},{"href":789},[9552],{"type":55,"value":9553},"Docker Compose",{"type":55,"value":9555}," do manage the software",{"type":28,"tag":690,"props":9557,"children":9558},{},[9559,9565],{"type":28,"tag":520,"props":9560,"children":9562},{"href":9561},"https://about.gitlab.com/",[9563],{"type":55,"value":9564},"GitLab",{"type":55,"value":9566}," to store all the compose files",{"type":28,"tag":690,"props":9568,"children":9569},{},[9570,9576],{"type":28,"tag":520,"props":9571,"children":9573},{"href":9572},"https://docs.renovatebot.com",[9574],{"type":55,"value":9575},"Renovate Bot",{"type":55,"value":9577}," to keep the software up to date",{"type":28,"tag":79,"props":9579,"children":9581},{"id":9580},"about-the-stack",[9582],{"type":55,"value":9583},"About the stack",{"type":28,"tag":47,"props":9585,"children":9586},{},[9587,9589,9595],{"type":55,"value":9588},"We have been using Docker in production for some time now. Depending on the situation, we create the compose file directly on the server, manage it over portainer or ",{"type":28,"tag":548,"props":9590,"children":9592},{"className":9591},[],[9593],{"type":55,"value":9594},"scp",{"type":55,"value":9596}," it from a pipeline.",{"type":28,"tag":47,"props":9598,"children":9599},{},[9600,9602,9608],{"type":55,"value":9601},"GitLab is out primary tool for version control. Additionally, a ",{"type":28,"tag":520,"props":9603,"children":9605},{"href":9604},"https://docs.gitlab.com/runner/",[9606],{"type":55,"value":9607},"GitLab Runner",{"type":55,"value":9609}," takes care of running pipelines.",{"type":28,"tag":47,"props":9611,"children":9612},{},[9613],{"type":55,"value":9614},"Renovate automates dependency updates. PHP, Go, Python, Docker - to name a couple. We already use it for various projects.",{"type":28,"tag":79,"props":9616,"children":9618},{"id":9617},"container-with-docker-and-docker-compose",[9619],{"type":55,"value":9620},"Container with Docker and Docker Compose",{"type":28,"tag":47,"props":9622,"children":9623},{},[9624,9626,9632],{"type":55,"value":9625},"The main reason why we chose Docker is the ability to access a remote Docker host and execute Docker commands.\nRefer to ",{"type":28,"tag":520,"props":9627,"children":9629},{"href":9628},"https://docs.docker.com/reference/cli/docker/#host",[9630],{"type":55,"value":9631},"the official documentation",{"type":55,"value":9633}," for more information.",{"type":28,"tag":47,"props":9635,"children":9636},{},[9637,9639,9645],{"type":55,"value":9638},"We are using ",{"type":28,"tag":548,"props":9640,"children":9642},{"className":9641},[],[9643],{"type":55,"value":9644},"ssh",{"type":55,"value":9646}," to access our target server.",{"type":28,"tag":47,"props":9648,"children":9649},{},[9650],{"type":28,"tag":548,"props":9651,"children":9653},{"className":9652},[],[9654],{"type":55,"value":9655},"DOCKER_HOST=ssh://[username@]\u003CIP or host>[:port] docker compose up --wait",{"type":28,"tag":79,"props":9657,"children":9659},{"id":9658},"gitops-with-gitlab",[9660],{"type":55,"value":9661},"GitOps with GitLab",{"type":28,"tag":47,"props":9663,"children":9664},{},[9665],{"type":55,"value":9666},"The idea behind GitOps is to use a git repository to store the configuration. Here is an example:",{"type":28,"tag":534,"props":9668,"children":9670},{"className":2888,"code":9669,"language":2890,"meta":7,"style":7},".\n├──.gitlab-ci.yml             # pipeline definition\n├── renovate.json             # Renovate configuration\n├── nextcloud\n│   ├── docker-compose.yml   # Nextcloud file hosting and collaboration\n└── traefik\n    └── docker-compose.yml   # Traefik reverse proxy configuration\n\n",[9671],{"type":28,"tag":548,"props":9672,"children":9673},{"__ignoreMap":7},[9674,9683,9697,9715,9727,9750,9763],{"type":28,"tag":116,"props":9675,"children":9676},{"class":553,"line":554},[9677],{"type":28,"tag":116,"props":9678,"children":9680},{"style":9679},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#66D9EF",[9681],{"type":55,"value":9682},".\n",{"type":28,"tag":116,"props":9684,"children":9685},{"class":553,"line":271},[9686,9691],{"type":28,"tag":116,"props":9687,"children":9688},{"style":2900},[9689],{"type":55,"value":9690},"├──.gitlab-ci.yml",{"type":28,"tag":116,"props":9692,"children":9694},{"style":9693},"--shiki-default:#6A737D;--shiki-dark:#6A737D;--shiki-sepia:#88846F",[9695],{"type":55,"value":9696},"             # pipeline definition\n",{"type":28,"tag":116,"props":9698,"children":9699},{"class":553,"line":582},[9700,9705,9710],{"type":28,"tag":116,"props":9701,"children":9702},{"style":2900},[9703],{"type":55,"value":9704},"├──",{"type":28,"tag":116,"props":9706,"children":9707},{"style":596},[9708],{"type":55,"value":9709}," renovate.json",{"type":28,"tag":116,"props":9711,"children":9712},{"style":9693},[9713],{"type":55,"value":9714},"             # Renovate configuration\n",{"type":28,"tag":116,"props":9716,"children":9717},{"class":553,"line":602},[9718,9722],{"type":28,"tag":116,"props":9719,"children":9720},{"style":2900},[9721],{"type":55,"value":9704},{"type":28,"tag":116,"props":9723,"children":9724},{"style":596},[9725],{"type":55,"value":9726}," nextcloud\n",{"type":28,"tag":116,"props":9728,"children":9729},{"class":553,"line":539},[9730,9735,9740,9745],{"type":28,"tag":116,"props":9731,"children":9732},{"style":2900},[9733],{"type":55,"value":9734},"│",{"type":28,"tag":116,"props":9736,"children":9737},{"style":596},[9738],{"type":55,"value":9739},"   ├──",{"type":28,"tag":116,"props":9741,"children":9742},{"style":596},[9743],{"type":55,"value":9744}," docker-compose.yml",{"type":28,"tag":116,"props":9746,"children":9747},{"style":9693},[9748],{"type":55,"value":9749},"   # Nextcloud file hosting and collaboration\n",{"type":28,"tag":116,"props":9751,"children":9752},{"class":553,"line":540},[9753,9758],{"type":28,"tag":116,"props":9754,"children":9755},{"style":2900},[9756],{"type":55,"value":9757},"└──",{"type":28,"tag":116,"props":9759,"children":9760},{"style":596},[9761],{"type":55,"value":9762}," traefik\n",{"type":28,"tag":116,"props":9764,"children":9765},{"class":553,"line":541},[9766,9771,9775],{"type":28,"tag":116,"props":9767,"children":9768},{"style":2900},[9769],{"type":55,"value":9770},"    └──",{"type":28,"tag":116,"props":9772,"children":9773},{"style":596},[9774],{"type":55,"value":9744},{"type":28,"tag":116,"props":9776,"children":9777},{"style":9693},[9778],{"type":55,"value":9779},"   # Traefik reverse proxy configuration\n",{"type":28,"tag":534,"props":9781,"children":9784},{"className":545,"code":9782,"filename":9783,"language":544,"meta":7,"style":7},"volumes:\n  nextcloud:\n  db:\n\nservices:\n  db:\n    image: mariadb:11.8\n    restart: unless-stopped\n    volumes:\n      - db:/var/lib/mysql\n    environment:\n      - MARIADB_ROOT_PASSWORD=${NEXTCLOUD_MARIADB_ROOT_PASSWORD:?error}\n      - MARIADB_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n      - MARIADB_DATABASE=nextcloud\n      - MARIADB_USER=nextcloud\n    command:\n      - --transaction-isolation=READ-COMMITTED\n      - --log-bin=binlog\n      - --binlog-format=ROW\n    healthcheck:\n      test: [\"CMD\", \"healthcheck.sh\", \"--connect\", \"--innodb_initialized\"]\n      interval: 15s\n      timeout: 5s\n      retries: 6\n\n  nextcloud:\n    image: nextcloud:32.0.0\n    restart: unless-stopped\n    depends_on:\n      db:\n        condition: service_healthy\n    volumes:\n      - nextcloud:/var/www/html\n    environment:\n      - MYSQL_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n      - MYSQL_DATABASE=nextcloud\n      - MYSQL_USER=nextcloud\n      - MYSQL_HOST=db\n","nextcloud/docker-compose.yaml",[9785],{"type":28,"tag":548,"props":9786,"children":9787},{"__ignoreMap":7},[9788,9799,9811,9823,9830,9841,9852,9868,9884,9895,9907,9919,9931,9943,9955,9967,9978,9990,10002,10014,10026,10075,10092,10109,10126,10133,10144,10160,10175,10187,10199,10216,10227,10239,10250,10262,10274,10286],{"type":28,"tag":116,"props":9789,"children":9790},{"class":553,"line":554},[9791,9795],{"type":28,"tag":116,"props":9792,"children":9793},{"style":558},[9794],{"type":55,"value":1086},{"type":28,"tag":116,"props":9796,"children":9797},{"style":564},[9798],{"type":55,"value":567},{"type":28,"tag":116,"props":9800,"children":9801},{"class":553,"line":271},[9802,9807],{"type":28,"tag":116,"props":9803,"children":9804},{"style":558},[9805],{"type":55,"value":9806},"  nextcloud",{"type":28,"tag":116,"props":9808,"children":9809},{"style":564},[9810],{"type":55,"value":567},{"type":28,"tag":116,"props":9812,"children":9813},{"class":553,"line":582},[9814,9819],{"type":28,"tag":116,"props":9815,"children":9816},{"style":558},[9817],{"type":55,"value":9818},"  db",{"type":28,"tag":116,"props":9820,"children":9821},{"style":564},[9822],{"type":55,"value":567},{"type":28,"tag":116,"props":9824,"children":9825},{"class":553,"line":602},[9826],{"type":28,"tag":116,"props":9827,"children":9828},{"emptyLinePlaceholder":1271},[9829],{"type":55,"value":1274},{"type":28,"tag":116,"props":9831,"children":9832},{"class":553,"line":539},[9833,9837],{"type":28,"tag":116,"props":9834,"children":9835},{"style":558},[9836],{"type":55,"value":561},{"type":28,"tag":116,"props":9838,"children":9839},{"style":564},[9840],{"type":55,"value":567},{"type":28,"tag":116,"props":9842,"children":9843},{"class":553,"line":540},[9844,9848],{"type":28,"tag":116,"props":9845,"children":9846},{"style":558},[9847],{"type":55,"value":9818},{"type":28,"tag":116,"props":9849,"children":9850},{"style":564},[9851],{"type":55,"value":567},{"type":28,"tag":116,"props":9853,"children":9854},{"class":553,"line":541},[9855,9859,9863],{"type":28,"tag":116,"props":9856,"children":9857},{"style":558},[9858],{"type":55,"value":588},{"type":28,"tag":116,"props":9860,"children":9861},{"style":564},[9862],{"type":55,"value":593},{"type":28,"tag":116,"props":9864,"children":9865},{"style":596},[9866],{"type":55,"value":9867},"mariadb:11.8\n",{"type":28,"tag":116,"props":9869,"children":9870},{"class":553,"line":542},[9871,9875,9879],{"type":28,"tag":116,"props":9872,"children":9873},{"style":558},[9874],{"type":55,"value":1158},{"type":28,"tag":116,"props":9876,"children":9877},{"style":564},[9878],{"type":55,"value":593},{"type":28,"tag":116,"props":9880,"children":9881},{"style":596},[9882],{"type":55,"value":9883},"unless-stopped\n",{"type":28,"tag":116,"props":9885,"children":9886},{"class":553,"line":543},[9887,9891],{"type":28,"tag":116,"props":9888,"children":9889},{"style":558},[9890],{"type":55,"value":1404},{"type":28,"tag":116,"props":9892,"children":9893},{"style":564},[9894],{"type":55,"value":567},{"type":28,"tag":116,"props":9896,"children":9897},{"class":553,"line":1203},[9898,9902],{"type":28,"tag":116,"props":9899,"children":9900},{"style":564},[9901],{"type":55,"value":622},{"type":28,"tag":116,"props":9903,"children":9904},{"style":596},[9905],{"type":55,"value":9906},"db:/var/lib/mysql\n",{"type":28,"tag":116,"props":9908,"children":9909},{"class":553,"line":1216},[9910,9915],{"type":28,"tag":116,"props":9911,"children":9912},{"style":558},[9913],{"type":55,"value":9914},"    environment",{"type":28,"tag":116,"props":9916,"children":9917},{"style":564},[9918],{"type":55,"value":567},{"type":28,"tag":116,"props":9920,"children":9921},{"class":553,"line":107},[9922,9926],{"type":28,"tag":116,"props":9923,"children":9924},{"style":564},[9925],{"type":55,"value":622},{"type":28,"tag":116,"props":9927,"children":9928},{"style":596},[9929],{"type":55,"value":9930},"MARIADB_ROOT_PASSWORD=${NEXTCLOUD_MARIADB_ROOT_PASSWORD:?error}\n",{"type":28,"tag":116,"props":9932,"children":9933},{"class":553,"line":1241},[9934,9938],{"type":28,"tag":116,"props":9935,"children":9936},{"style":564},[9937],{"type":55,"value":622},{"type":28,"tag":116,"props":9939,"children":9940},{"style":596},[9941],{"type":55,"value":9942},"MARIADB_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":28,"tag":116,"props":9944,"children":9945},{"class":553,"line":1254},[9946,9950],{"type":28,"tag":116,"props":9947,"children":9948},{"style":564},[9949],{"type":55,"value":622},{"type":28,"tag":116,"props":9951,"children":9952},{"style":596},[9953],{"type":55,"value":9954},"MARIADB_DATABASE=nextcloud\n",{"type":28,"tag":116,"props":9956,"children":9957},{"class":553,"line":1267},[9958,9962],{"type":28,"tag":116,"props":9959,"children":9960},{"style":564},[9961],{"type":55,"value":622},{"type":28,"tag":116,"props":9963,"children":9964},{"style":596},[9965],{"type":55,"value":9966},"MARIADB_USER=nextcloud\n",{"type":28,"tag":116,"props":9968,"children":9969},{"class":553,"line":1277},[9970,9974],{"type":28,"tag":116,"props":9971,"children":9972},{"style":558},[9973],{"type":55,"value":1209},{"type":28,"tag":116,"props":9975,"children":9976},{"style":564},[9977],{"type":55,"value":567},{"type":28,"tag":116,"props":9979,"children":9980},{"class":553,"line":1290},[9981,9985],{"type":28,"tag":116,"props":9982,"children":9983},{"style":564},[9984],{"type":55,"value":622},{"type":28,"tag":116,"props":9986,"children":9987},{"style":596},[9988],{"type":55,"value":9989},"--transaction-isolation=READ-COMMITTED\n",{"type":28,"tag":116,"props":9991,"children":9992},{"class":553,"line":1303},[9993,9997],{"type":28,"tag":116,"props":9994,"children":9995},{"style":564},[9996],{"type":55,"value":622},{"type":28,"tag":116,"props":9998,"children":9999},{"style":596},[10000],{"type":55,"value":10001},"--log-bin=binlog\n",{"type":28,"tag":116,"props":10003,"children":10004},{"class":553,"line":1312},[10005,10009],{"type":28,"tag":116,"props":10006,"children":10007},{"style":564},[10008],{"type":55,"value":622},{"type":28,"tag":116,"props":10010,"children":10011},{"style":596},[10012],{"type":55,"value":10013},"--binlog-format=ROW\n",{"type":28,"tag":116,"props":10015,"children":10016},{"class":553,"line":1325},[10017,10022],{"type":28,"tag":116,"props":10018,"children":10019},{"style":558},[10020],{"type":55,"value":10021},"    healthcheck",{"type":28,"tag":116,"props":10023,"children":10024},{"style":564},[10025],{"type":55,"value":567},{"type":28,"tag":116,"props":10027,"children":10028},{"class":553,"line":1338},[10029,10034,10038,10043,10048,10053,10057,10062,10066,10071],{"type":28,"tag":116,"props":10030,"children":10031},{"style":558},[10032],{"type":55,"value":10033},"      test",{"type":28,"tag":116,"props":10035,"children":10036},{"style":564},[10037],{"type":55,"value":5537},{"type":28,"tag":116,"props":10039,"children":10040},{"style":596},[10041],{"type":55,"value":10042},"\"CMD\"",{"type":28,"tag":116,"props":10044,"children":10045},{"style":564},[10046],{"type":55,"value":10047},", ",{"type":28,"tag":116,"props":10049,"children":10050},{"style":596},[10051],{"type":55,"value":10052},"\"healthcheck.sh\"",{"type":28,"tag":116,"props":10054,"children":10055},{"style":564},[10056],{"type":55,"value":10047},{"type":28,"tag":116,"props":10058,"children":10059},{"style":596},[10060],{"type":55,"value":10061},"\"--connect\"",{"type":28,"tag":116,"props":10063,"children":10064},{"style":564},[10065],{"type":55,"value":10047},{"type":28,"tag":116,"props":10067,"children":10068},{"style":596},[10069],{"type":55,"value":10070},"\"--innodb_initialized\"",{"type":28,"tag":116,"props":10072,"children":10073},{"style":564},[10074],{"type":55,"value":5547},{"type":28,"tag":116,"props":10076,"children":10077},{"class":553,"line":1351},[10078,10083,10087],{"type":28,"tag":116,"props":10079,"children":10080},{"style":558},[10081],{"type":55,"value":10082},"      interval",{"type":28,"tag":116,"props":10084,"children":10085},{"style":564},[10086],{"type":55,"value":593},{"type":28,"tag":116,"props":10088,"children":10089},{"style":596},[10090],{"type":55,"value":10091},"15s\n",{"type":28,"tag":116,"props":10093,"children":10094},{"class":553,"line":1359},[10095,10100,10104],{"type":28,"tag":116,"props":10096,"children":10097},{"style":558},[10098],{"type":55,"value":10099},"      timeout",{"type":28,"tag":116,"props":10101,"children":10102},{"style":564},[10103],{"type":55,"value":593},{"type":28,"tag":116,"props":10105,"children":10106},{"style":596},[10107],{"type":55,"value":10108},"5s\n",{"type":28,"tag":116,"props":10110,"children":10111},{"class":553,"line":1372},[10112,10117,10121],{"type":28,"tag":116,"props":10113,"children":10114},{"style":558},[10115],{"type":55,"value":10116},"      retries",{"type":28,"tag":116,"props":10118,"children":10119},{"style":564},[10120],{"type":55,"value":593},{"type":28,"tag":116,"props":10122,"children":10123},{"style":2170},[10124],{"type":55,"value":10125},"6\n",{"type":28,"tag":116,"props":10127,"children":10128},{"class":553,"line":1385},[10129],{"type":28,"tag":116,"props":10130,"children":10131},{"emptyLinePlaceholder":1271},[10132],{"type":55,"value":1274},{"type":28,"tag":116,"props":10134,"children":10135},{"class":553,"line":1398},[10136,10140],{"type":28,"tag":116,"props":10137,"children":10138},{"style":558},[10139],{"type":55,"value":9806},{"type":28,"tag":116,"props":10141,"children":10142},{"style":564},[10143],{"type":55,"value":567},{"type":28,"tag":116,"props":10145,"children":10146},{"class":553,"line":1411},[10147,10151,10155],{"type":28,"tag":116,"props":10148,"children":10149},{"style":558},[10150],{"type":55,"value":588},{"type":28,"tag":116,"props":10152,"children":10153},{"style":564},[10154],{"type":55,"value":593},{"type":28,"tag":116,"props":10156,"children":10157},{"style":596},[10158],{"type":55,"value":10159},"nextcloud:32.0.0\n",{"type":28,"tag":116,"props":10161,"children":10162},{"class":553,"line":1424},[10163,10167,10171],{"type":28,"tag":116,"props":10164,"children":10165},{"style":558},[10166],{"type":55,"value":1158},{"type":28,"tag":116,"props":10168,"children":10169},{"style":564},[10170],{"type":55,"value":593},{"type":28,"tag":116,"props":10172,"children":10173},{"style":596},[10174],{"type":55,"value":9883},{"type":28,"tag":116,"props":10176,"children":10177},{"class":553,"line":2278},[10178,10183],{"type":28,"tag":116,"props":10179,"children":10180},{"style":558},[10181],{"type":55,"value":10182},"    depends_on",{"type":28,"tag":116,"props":10184,"children":10185},{"style":564},[10186],{"type":55,"value":567},{"type":28,"tag":116,"props":10188,"children":10189},{"class":553,"line":2286},[10190,10195],{"type":28,"tag":116,"props":10191,"children":10192},{"style":558},[10193],{"type":55,"value":10194},"      db",{"type":28,"tag":116,"props":10196,"children":10197},{"style":564},[10198],{"type":55,"value":567},{"type":28,"tag":116,"props":10200,"children":10201},{"class":553,"line":2306},[10202,10207,10211],{"type":28,"tag":116,"props":10203,"children":10204},{"style":558},[10205],{"type":55,"value":10206},"        condition",{"type":28,"tag":116,"props":10208,"children":10209},{"style":564},[10210],{"type":55,"value":593},{"type":28,"tag":116,"props":10212,"children":10213},{"style":596},[10214],{"type":55,"value":10215},"service_healthy\n",{"type":28,"tag":116,"props":10217,"children":10218},{"class":553,"line":2327},[10219,10223],{"type":28,"tag":116,"props":10220,"children":10221},{"style":558},[10222],{"type":55,"value":1404},{"type":28,"tag":116,"props":10224,"children":10225},{"style":564},[10226],{"type":55,"value":567},{"type":28,"tag":116,"props":10228,"children":10229},{"class":553,"line":2339},[10230,10234],{"type":28,"tag":116,"props":10231,"children":10232},{"style":564},[10233],{"type":55,"value":622},{"type":28,"tag":116,"props":10235,"children":10236},{"style":596},[10237],{"type":55,"value":10238},"nextcloud:/var/www/html\n",{"type":28,"tag":116,"props":10240,"children":10241},{"class":553,"line":2355},[10242,10246],{"type":28,"tag":116,"props":10243,"children":10244},{"style":558},[10245],{"type":55,"value":9914},{"type":28,"tag":116,"props":10247,"children":10248},{"style":564},[10249],{"type":55,"value":567},{"type":28,"tag":116,"props":10251,"children":10252},{"class":553,"line":2363},[10253,10257],{"type":28,"tag":116,"props":10254,"children":10255},{"style":564},[10256],{"type":55,"value":622},{"type":28,"tag":116,"props":10258,"children":10259},{"style":596},[10260],{"type":55,"value":10261},"MYSQL_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":28,"tag":116,"props":10263,"children":10264},{"class":553,"line":1837},[10265,10269],{"type":28,"tag":116,"props":10266,"children":10267},{"style":564},[10268],{"type":55,"value":622},{"type":28,"tag":116,"props":10270,"children":10271},{"style":596},[10272],{"type":55,"value":10273},"MYSQL_DATABASE=nextcloud\n",{"type":28,"tag":116,"props":10275,"children":10276},{"class":553,"line":1838},[10277,10281],{"type":28,"tag":116,"props":10278,"children":10279},{"style":564},[10280],{"type":55,"value":622},{"type":28,"tag":116,"props":10282,"children":10283},{"style":596},[10284],{"type":55,"value":10285},"MYSQL_USER=nextcloud\n",{"type":28,"tag":116,"props":10287,"children":10288},{"class":553,"line":1839},[10289,10293],{"type":28,"tag":116,"props":10290,"children":10291},{"style":564},[10292],{"type":55,"value":622},{"type":28,"tag":116,"props":10294,"children":10295},{"style":596},[10296],{"type":55,"value":10297},"MYSQL_HOST=db\n",{"type":28,"tag":534,"props":10299,"children":10303},{"className":10300,"code":10301,"language":10302,"meta":7,"style":7},"language-dotenv shiki shiki-themes github-dark github-dark monokai","NEXTCLOUD_MARIADB_ROOT_PASSWORD=\nNEXTCLOUD_MARIADB_PASSWORD=\n","dotenv",[10304],{"type":28,"tag":548,"props":10305,"children":10306},{"__ignoreMap":7},[10307,10321],{"type":28,"tag":116,"props":10308,"children":10309},{"class":553,"line":554},[10310,10316],{"type":28,"tag":116,"props":10311,"children":10313},{"style":10312},"--shiki-default:#FFAB70;--shiki-dark:#FFAB70;--shiki-sepia:#F8F8F2",[10314],{"type":55,"value":10315},"NEXTCLOUD_MARIADB_ROOT_PASSWORD",{"type":28,"tag":116,"props":10317,"children":10318},{"style":4807},[10319],{"type":55,"value":10320},"=\n",{"type":28,"tag":116,"props":10322,"children":10323},{"class":553,"line":271},[10324,10329],{"type":28,"tag":116,"props":10325,"children":10326},{"style":10312},[10327],{"type":55,"value":10328},"NEXTCLOUD_MARIADB_PASSWORD",{"type":28,"tag":116,"props":10330,"children":10331},{"style":4807},[10332],{"type":55,"value":10320},{"type":28,"tag":47,"props":10334,"children":10335},{},[10336,10338],{"type":55,"value":10337},"are stored as ",{"type":28,"tag":520,"props":10339,"children":10341},{"href":10340},"https://docs.gitlab.com/ci/variables/",[10342],{"type":55,"value":10343},"CI/CD Variables",{"type":28,"tag":1062,"props":10345,"children":10346},{},[],{"type":28,"tag":47,"props":10348,"children":10349},{},[10350],{"type":55,"value":10351},"To deploy the stack, we have a pipeline:",{"type":28,"tag":534,"props":10353,"children":10355},{"className":545,"code":10354,"filename":5245,"language":544,"meta":7,"style":7},"stages:\n  - deploy\n\ndeploy:\n  stage: deploy\n  image: docker:28\n  variables:\n    DOCKER_HOST: ssh://[username@]\u003CIP or host>[:port]\n  script:\n    - for file in $(find . -type f -name docker-compose.yml); do docker compose -f $file up --remove-orphans --wait; done\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n\n",[10356],{"type":28,"tag":548,"props":10357,"children":10358},{"__ignoreMap":7},[10359,10370,10382,10389,10400,10415,10431,10442,10459,10470,10482,10493],{"type":28,"tag":116,"props":10360,"children":10361},{"class":553,"line":554},[10362,10366],{"type":28,"tag":116,"props":10363,"children":10364},{"style":558},[10365],{"type":55,"value":5257},{"type":28,"tag":116,"props":10367,"children":10368},{"style":564},[10369],{"type":55,"value":567},{"type":28,"tag":116,"props":10371,"children":10372},{"class":553,"line":271},[10373,10377],{"type":28,"tag":116,"props":10374,"children":10375},{"style":564},[10376],{"type":55,"value":5269},{"type":28,"tag":116,"props":10378,"children":10379},{"style":596},[10380],{"type":55,"value":10381},"deploy\n",{"type":28,"tag":116,"props":10383,"children":10384},{"class":553,"line":582},[10385],{"type":28,"tag":116,"props":10386,"children":10387},{"emptyLinePlaceholder":1271},[10388],{"type":55,"value":1274},{"type":28,"tag":116,"props":10390,"children":10391},{"class":553,"line":602},[10392,10396],{"type":28,"tag":116,"props":10393,"children":10394},{"style":558},[10395],{"type":55,"value":5289},{"type":28,"tag":116,"props":10397,"children":10398},{"style":564},[10399],{"type":55,"value":567},{"type":28,"tag":116,"props":10401,"children":10402},{"class":553,"line":539},[10403,10407,10411],{"type":28,"tag":116,"props":10404,"children":10405},{"style":558},[10406],{"type":55,"value":5318},{"type":28,"tag":116,"props":10408,"children":10409},{"style":564},[10410],{"type":55,"value":593},{"type":28,"tag":116,"props":10412,"children":10413},{"style":596},[10414],{"type":55,"value":10381},{"type":28,"tag":116,"props":10416,"children":10417},{"class":553,"line":540},[10418,10422,10426],{"type":28,"tag":116,"props":10419,"children":10420},{"style":558},[10421],{"type":55,"value":5301},{"type":28,"tag":116,"props":10423,"children":10424},{"style":564},[10425],{"type":55,"value":593},{"type":28,"tag":116,"props":10427,"children":10428},{"style":596},[10429],{"type":55,"value":10430},"docker:28\n",{"type":28,"tag":116,"props":10432,"children":10433},{"class":553,"line":541},[10434,10438],{"type":28,"tag":116,"props":10435,"children":10436},{"style":558},[10437],{"type":55,"value":6406},{"type":28,"tag":116,"props":10439,"children":10440},{"style":564},[10441],{"type":55,"value":567},{"type":28,"tag":116,"props":10443,"children":10444},{"class":553,"line":542},[10445,10450,10454],{"type":28,"tag":116,"props":10446,"children":10447},{"style":558},[10448],{"type":55,"value":10449},"    DOCKER_HOST",{"type":28,"tag":116,"props":10451,"children":10452},{"style":564},[10453],{"type":55,"value":593},{"type":28,"tag":116,"props":10455,"children":10456},{"style":596},[10457],{"type":55,"value":10458},"ssh://[username@]\u003CIP or host>[:port]\n",{"type":28,"tag":116,"props":10460,"children":10461},{"class":553,"line":543},[10462,10466],{"type":28,"tag":116,"props":10463,"children":10464},{"style":558},[10465],{"type":55,"value":5334},{"type":28,"tag":116,"props":10467,"children":10468},{"style":564},[10469],{"type":55,"value":567},{"type":28,"tag":116,"props":10471,"children":10472},{"class":553,"line":1203},[10473,10477],{"type":28,"tag":116,"props":10474,"children":10475},{"style":564},[10476],{"type":55,"value":5346},{"type":28,"tag":116,"props":10478,"children":10479},{"style":596},[10480],{"type":55,"value":10481},"for file in $(find . -type f -name docker-compose.yml); do docker compose -f $file up --remove-orphans --wait; done\n",{"type":28,"tag":116,"props":10483,"children":10484},{"class":553,"line":1216},[10485,10489],{"type":28,"tag":116,"props":10486,"children":10487},{"style":558},[10488],{"type":55,"value":5376},{"type":28,"tag":116,"props":10490,"children":10491},{"style":564},[10492],{"type":55,"value":567},{"type":28,"tag":116,"props":10494,"children":10495},{"class":553,"line":107},[10496,10500,10504,10508],{"type":28,"tag":116,"props":10497,"children":10498},{"style":564},[10499],{"type":55,"value":5346},{"type":28,"tag":116,"props":10501,"children":10502},{"style":558},[10503],{"type":55,"value":5609},{"type":28,"tag":116,"props":10505,"children":10506},{"style":564},[10507],{"type":55,"value":593},{"type":28,"tag":116,"props":10509,"children":10510},{"style":596},[10511],{"type":55,"value":10512},"$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n",{"type":28,"tag":47,"props":10514,"children":10515},{},[10516,10518,10524],{"type":55,"value":10517},"The pipeline runs with every commit on the default branch, iterates through all ",{"type":28,"tag":548,"props":10519,"children":10521},{"className":10520},[],[10522],{"type":55,"value":10523},"docker-compose.yml",{"type":55,"value":10525}," files, and deploys them.",{"type":28,"tag":79,"props":10527,"children":10529},{"id":10528},"keep-your-deployments-up-to-date-with-renovate-bot",[10530],{"type":55,"value":10531},"Keep your deployments up-to-date with Renovate Bot",{"type":28,"tag":47,"props":10533,"children":10534},{},[10535],{"type":55,"value":10536},"Here is where Renovate kicks in.",{"type":28,"tag":534,"props":10538,"children":10541},{"className":1833,"code":10539,"filename":10540,"language":384,"meta":7,"style":7},"{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:best-practices\"\n  ]\n}\n","renovate.json",[10542],{"type":28,"tag":548,"props":10543,"children":10544},{"__ignoreMap":7},[10545,10552,10573,10585,10593,10600],{"type":28,"tag":116,"props":10546,"children":10547},{"class":553,"line":554},[10548],{"type":28,"tag":116,"props":10549,"children":10550},{"style":564},[10551],{"type":55,"value":1852},{"type":28,"tag":116,"props":10553,"children":10554},{"class":553,"line":271},[10555,10560,10564,10569],{"type":28,"tag":116,"props":10556,"children":10557},{"style":1858},[10558],{"type":55,"value":10559},"  \"$schema\"",{"type":28,"tag":116,"props":10561,"children":10562},{"style":564},[10563],{"type":55,"value":593},{"type":28,"tag":116,"props":10565,"children":10566},{"style":1868},[10567],{"type":55,"value":10568},"\"https://docs.renovatebot.com/renovate-schema.json\"",{"type":28,"tag":116,"props":10570,"children":10571},{"style":564},[10572],{"type":55,"value":1876},{"type":28,"tag":116,"props":10574,"children":10575},{"class":553,"line":582},[10576,10581],{"type":28,"tag":116,"props":10577,"children":10578},{"style":1858},[10579],{"type":55,"value":10580},"  \"extends\"",{"type":28,"tag":116,"props":10582,"children":10583},{"style":564},[10584],{"type":55,"value":2093},{"type":28,"tag":116,"props":10586,"children":10587},{"class":553,"line":602},[10588],{"type":28,"tag":116,"props":10589,"children":10590},{"style":1868},[10591],{"type":55,"value":10592},"    \"config:best-practices\"\n",{"type":28,"tag":116,"props":10594,"children":10595},{"class":553,"line":539},[10596],{"type":28,"tag":116,"props":10597,"children":10598},{"style":564},[10599],{"type":55,"value":6053},{"type":28,"tag":116,"props":10601,"children":10602},{"class":553,"line":540},[10603],{"type":28,"tag":116,"props":10604,"children":10605},{"style":564},[10606],{"type":55,"value":2880},{"type":28,"tag":47,"props":10608,"children":10609},{},[10610],{"type":55,"value":10611},"Renovate will create Merge Requests for every update. Nice!",{"type":28,"tag":79,"props":10613,"children":10615},{"id":10614},"automated-security-updates-and-opt-in-for-minormajor-version-updates",[10616],{"type":55,"value":10617},"Automated security updates and opt-in for minor/major version updates",{"type":28,"tag":47,"props":10619,"children":10620},{},[10621],{"type":55,"value":10622},"The current configuration creates Merge Requests for every update, but we want security updates to happen without user interaction.",{"type":28,"tag":47,"props":10624,"children":10625},{},[10626,10628],{"type":55,"value":10627},"You need to understand how Docker images are versioned / tagged. It depends on the image, but let's take a look on the official ",{"type":28,"tag":520,"props":10629,"children":10631},{"href":10630},"https://hub.docker.com/_/mariadb",[10632],{"type":55,"value":10633},"MariaDB",{"type":28,"tag":47,"props":10635,"children":10636},{},[10637,10639,10645],{"type":55,"value":10638},"There are ",{"type":28,"tag":548,"props":10640,"children":10642},{"className":10641},[],[10643],{"type":55,"value":10644},"11.8.3-noble, 11.8-noble, 11-noble, lts-noble, 11.8.3, 11.8, 11, lts",{"type":55,"value":10646},", all of which refer to the same image.",{"type":28,"tag":47,"props":10648,"children":10649},{},[10650,10656,10658,10664,10666,10672,10673,10679],{"type":28,"tag":548,"props":10651,"children":10653},{"className":10652},[],[10654],{"type":55,"value":10655},"11.8.3-noble",{"type":55,"value":10657}," means that we get MariaDB in version ",{"type":28,"tag":548,"props":10659,"children":10661},{"className":10660},[],[10662],{"type":55,"value":10663},"11.8.3",{"type":55,"value":10665}," based on Ubuntu Noble.\n",{"type":28,"tag":548,"props":10667,"children":10669},{"className":10668},[],[10670],{"type":55,"value":10671},"11.8-noble",{"type":55,"value":10657},{"type":28,"tag":548,"props":10674,"children":10676},{"className":10675},[],[10677],{"type":55,"value":10678},"11.8.\u003Clatest_path>",{"type":55,"value":10680}," based on Ubuntu Noble.",{"type":28,"tag":47,"props":10682,"children":10683},{},[10684,10686,10692,10694,10699,10701,10706],{"type":55,"value":10685},"When a neu version of MariaDB is released, e.g ",{"type":28,"tag":548,"props":10687,"children":10689},{"className":10688},[],[10690],{"type":55,"value":10691},"11.8.4-noble",{"type":55,"value":10693},", a new ",{"type":28,"tag":548,"props":10695,"children":10697},{"className":10696},[],[10698],{"type":55,"value":10691},{"type":55,"value":10700}," tag will be pushed, but the ",{"type":28,"tag":548,"props":10702,"children":10704},{"className":10703},[],[10705],{"type":55,"value":10671},{"type":55,"value":10707}," will be updated.",{"type":28,"tag":47,"props":10709,"children":10710},{},[10711,10713,10718],{"type":55,"value":10712},"This same is true for the Ubuntu update. The ",{"type":28,"tag":548,"props":10714,"children":10716},{"className":10715},[],[10717],{"type":55,"value":10655},{"type":55,"value":10719}," tag can be updated, if the image is rebuild with the latest Ubuntu image.",{"type":28,"tag":47,"props":10721,"children":10722},{},[10723,10725,10731,10733,10739],{"type":55,"value":10724},"Running ",{"type":28,"tag":548,"props":10726,"children":10728},{"className":10727},[],[10729],{"type":55,"value":10730},"docker compose up",{"type":55,"value":10732}," on ",{"type":28,"tag":548,"props":10734,"children":10736},{"className":10735},[],[10737],{"type":55,"value":10738},"mariadb:11.8-noble",{"type":55,"value":10740}," will do nothing, because Docker is not aware of that change.",{"type":28,"tag":47,"props":10742,"children":10743},{},[10744,10746,10752],{"type":55,"value":10745},"In the example above we reference ",{"type":28,"tag":548,"props":10747,"children":10749},{"className":10748},[],[10750],{"type":55,"value":10751},"mariadb:11.8",{"type":55,"value":10753},", because we want to use the latest patch version based on the most current OS.",{"type":28,"tag":1062,"props":10755,"children":10756},{},[],{"type":28,"tag":47,"props":10758,"children":10759},{},[10760],{"type":55,"value":10761},"How to tell Docker that there is a new version?",{"type":28,"tag":47,"props":10763,"children":10764},{},[10765,10767,10773],{"type":55,"value":10766},"The main idea is to attach a ",{"type":28,"tag":520,"props":10768,"children":10770},{"href":10769},"https://docs.docker.com/dhi/core-concepts/digests/",[10771],{"type":55,"value":10772},"digest",{"type":55,"value":10774}," to the Docker image.",{"type":28,"tag":47,"props":10776,"children":10777},{},[10778,10780,10785,10787],{"type":55,"value":10779},"When running Renovate for the first time, it will find the reference to ",{"type":28,"tag":548,"props":10781,"children":10783},{"className":10782},[],[10784],{"type":55,"value":10751},{"type":55,"value":10786}," and create a merge request to pin the Digest to something like ",{"type":28,"tag":548,"props":10788,"children":10790},{"className":10789},[],[10791],{"type":55,"value":10792},"mariadb:11.8@sha256:ae6119716edac6998ae85508431b3d2e666530ddf4e94c61a10710caec9b0f71",{"type":28,"tag":47,"props":10794,"children":10795},{},[10796],{"type":55,"value":10797},"Renovate will also monitor the upstream changes, so that every time the image get updated, the digest will change and Renovate will create a merge request.",{"type":28,"tag":47,"props":10799,"children":10800},{},[10801],{"type":55,"value":10802},"To merge these updates automatically, we need to do some adjustments.",{"type":28,"tag":534,"props":10804,"children":10807},{"className":1833,"code":10805,"filename":10540,"highlights":10806,"language":384,"meta":7,"style":7},"{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:best-practices\",\n    \"default:automergeDigest\"\n  ],\n  \"automergeType\": \"branch\",\n  \"ignoreTests\": true\n}\n",[539,540,541,542],[10808],{"type":28,"tag":548,"props":10809,"children":10810},{"__ignoreMap":7},[10811,10818,10837,10848,10860,10869,10877,10899,10916],{"type":28,"tag":116,"props":10812,"children":10813},{"class":553,"line":554},[10814],{"type":28,"tag":116,"props":10815,"children":10816},{"style":564},[10817],{"type":55,"value":1852},{"type":28,"tag":116,"props":10819,"children":10820},{"class":553,"line":271},[10821,10825,10829,10833],{"type":28,"tag":116,"props":10822,"children":10823},{"style":1858},[10824],{"type":55,"value":10559},{"type":28,"tag":116,"props":10826,"children":10827},{"style":564},[10828],{"type":55,"value":593},{"type":28,"tag":116,"props":10830,"children":10831},{"style":1868},[10832],{"type":55,"value":10568},{"type":28,"tag":116,"props":10834,"children":10835},{"style":564},[10836],{"type":55,"value":1876},{"type":28,"tag":116,"props":10838,"children":10839},{"class":553,"line":582},[10840,10844],{"type":28,"tag":116,"props":10841,"children":10842},{"style":1858},[10843],{"type":55,"value":10580},{"type":28,"tag":116,"props":10845,"children":10846},{"style":564},[10847],{"type":55,"value":2093},{"type":28,"tag":116,"props":10849,"children":10850},{"class":553,"line":602},[10851,10856],{"type":28,"tag":116,"props":10852,"children":10853},{"style":1868},[10854],{"type":55,"value":10855},"    \"config:best-practices\"",{"type":28,"tag":116,"props":10857,"children":10858},{"style":564},[10859],{"type":55,"value":1876},{"type":28,"tag":116,"props":10861,"children":10863},{"class":10862,"line":539},[553,616],[10864],{"type":28,"tag":116,"props":10865,"children":10866},{"style":1868},[10867],{"type":55,"value":10868},"    \"default:automergeDigest\"\n",{"type":28,"tag":116,"props":10870,"children":10872},{"class":10871,"line":540},[553,616],[10873],{"type":28,"tag":116,"props":10874,"children":10875},{"style":564},[10876],{"type":55,"value":2432},{"type":28,"tag":116,"props":10878,"children":10880},{"class":10879,"line":541},[553,616],[10881,10886,10890,10895],{"type":28,"tag":116,"props":10882,"children":10883},{"style":1858},[10884],{"type":55,"value":10885},"  \"automergeType\"",{"type":28,"tag":116,"props":10887,"children":10888},{"style":564},[10889],{"type":55,"value":593},{"type":28,"tag":116,"props":10891,"children":10892},{"style":1868},[10893],{"type":55,"value":10894},"\"branch\"",{"type":28,"tag":116,"props":10896,"children":10897},{"style":564},[10898],{"type":55,"value":1876},{"type":28,"tag":116,"props":10900,"children":10902},{"class":10901,"line":542},[553,616],[10903,10908,10912],{"type":28,"tag":116,"props":10904,"children":10905},{"style":1858},[10906],{"type":55,"value":10907},"  \"ignoreTests\"",{"type":28,"tag":116,"props":10909,"children":10910},{"style":564},[10911],{"type":55,"value":593},{"type":28,"tag":116,"props":10913,"children":10914},{"style":2170},[10915],{"type":55,"value":2173},{"type":28,"tag":116,"props":10917,"children":10918},{"class":553,"line":543},[10919],{"type":28,"tag":116,"props":10920,"children":10921},{"style":564},[10922],{"type":55,"value":2880},{"type":28,"tag":47,"props":10924,"children":10925},{},[10926,10928,10934,10935],{"type":55,"value":10927},"This instructs Renovate to auto-merge the Digest updates without creating a merge request prior. This reduces noise since there is no merge request notification.\nYou can read more about ",{"type":28,"tag":520,"props":10929,"children":10931},{"href":10930},"https://docs.renovatebot.com/key-concepts/automerge/#branch-vs-pr-automerging",[10932],{"type":55,"value":10933},"automergeType",{"type":55,"value":9548},{"type":28,"tag":520,"props":10936,"children":10938},{"href":10937},"https://docs.renovatebot.com/key-concepts/automerge/#absence-of-tests",[10939],{"type":55,"value":10940},"ignoreTests",{"type":28,"tag":1705,"props":10942,"children":10943},{},[10944],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":10946},[10947,10948,10949,10950,10951],{"id":9580,"depth":271,"text":9583},{"id":9617,"depth":271,"text":9620},{"id":9658,"depth":271,"text":9661},{"id":10528,"depth":271,"text":10531},{"id":10614,"depth":271,"text":10617},{"_path":451,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":452,"description":453,"author":394,"image":395,"releaseDate":454,"blogCategories":10953,"articleTags":10954,"tags":10955,"body":10956,"_type":275,"_id":458,"_source":277,"_file":459,"_stem":460,"_extension":280},[398,399],[399,412],[415,23],{"type":25,"children":10957,"toc":11479},[10958,10962,10973,10979,10992,11001,11032,11038,11065,11070,11098,11404,11409,11475],{"type":28,"tag":1727,"props":10959,"children":10961},{"alt":7,"aspect-ratio":1729,"height":1730,"object-fit":1731,"src":10960},"/blog/shopware-renovate.png",[],{"type":28,"tag":47,"props":10963,"children":10964},{},[10965,10971],{"type":28,"tag":520,"props":10966,"children":10968},{"href":10967},"https://docs.renovatebot.com/",[10969],{"type":55,"value":10970},"Renovate",{"type":55,"value":10972}," is a tool to track your project dependencies and create merge/pull request for them. It works perfectly for most common packages managers, but...",{"type":28,"tag":79,"props":10974,"children":10976},{"id":10975},"shopware-versioning-scheme",[10977],{"type":55,"value":10978},"Shopware versioning scheme",{"type":28,"tag":47,"props":10980,"children":10981},{},[10982,10984,10990],{"type":55,"value":10983},"Shopware is using a custom versioning scheme. You can read the ",{"type":28,"tag":520,"props":10985,"children":10987},{"href":10986},"https://www.shopware.com/en/news/shopware-6-versioning-strategy/",[10988],{"type":55,"value":10989},"official article",{"type":55,"value":10991},", but in short:",{"type":28,"tag":10993,"props":10994,"children":10995},"blockquote",{},[10996],{"type":28,"tag":47,"props":10997,"children":10998},{},[10999],{"type":55,"value":11000},"Shopware implemented SemVer as  \"SemVer with benefits\".",{"type":28,"tag":10993,"props":11002,"children":11003},{},[11004,11009,11027],{"type":28,"tag":47,"props":11005,"children":11006},{},[11007],{"type":55,"value":11008},"A SemVer compliant version has three numbers: Major, Minor, and Patch. They are incremented following this ruleset:",{"type":28,"tag":686,"props":11010,"children":11011},{},[11012,11017,11022],{"type":28,"tag":690,"props":11013,"children":11014},{},[11015],{"type":55,"value":11016},"MAJOR: Incompatible API changes are made",{"type":28,"tag":690,"props":11018,"children":11019},{},[11020],{"type":55,"value":11021},"MINOR: Functionality is added in a backward-compatible manner",{"type":28,"tag":690,"props":11023,"children":11024},{},[11025],{"type":55,"value":11026},"PATCH: Backward-compatible bug fixes are made",{"type":28,"tag":47,"props":11028,"children":11029},{},[11030],{"type":55,"value":11031},"The \"with benefits\" part is: We keep the big marketing number. So Shopware 6 still is the product, but there's a Shopware 6.3.0.0. With 3.0.0 being the SemVer part.",{"type":28,"tag":79,"props":11033,"children":11035},{"id":11034},"renovate-configuration",[11036],{"type":55,"value":11037},"Renovate configuration",{"type":28,"tag":47,"props":11039,"children":11040},{},[11041,11043,11049,11051,11057,11059],{"type":55,"value":11042},"The ",{"type":28,"tag":548,"props":11044,"children":11046},{"className":11045},[],[11047],{"type":55,"value":11048},"\"big marketing number\"",{"type":55,"value":11050}," or ",{"type":28,"tag":548,"props":11052,"children":11054},{"className":11053},[],[11055],{"type":55,"value":11056},"\"generation\"",{"type":55,"value":11058}," is reflected in Renovate as ",{"type":28,"tag":548,"props":11060,"children":11062},{"className":11061},[],[11063],{"type":55,"value":11064},"compatibility",{"type":28,"tag":47,"props":11066,"children":11067},{},[11068],{"type":55,"value":11069},"The following configuration will:",{"type":28,"tag":838,"props":11071,"children":11072},{},[11073,11078,11088,11093],{"type":28,"tag":690,"props":11074,"children":11075},{},[11076],{"type":55,"value":11077},"Group all shopware specific updates",{"type":28,"tag":690,"props":11079,"children":11080},{},[11081,11083],{"type":55,"value":11082},"Group the updates as ",{"type":28,"tag":548,"props":11084,"children":11086},{"className":11085},[],[11087],{"type":55,"value":415},{"type":28,"tag":690,"props":11089,"children":11090},{},[11091],{"type":55,"value":11092},"Tell Renovate how to extract the version",{"type":28,"tag":690,"props":11094,"children":11095},{},[11096],{"type":55,"value":11097},"Tell Renovate where to find changelog information",{"type":28,"tag":534,"props":11099,"children":11101},{"className":1833,"code":11100,"filename":10540,"language":384,"meta":7,"style":7},"{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"packageRules\": [\n    {\n      \"description\": \"Follow Shopware version schema\",\n      \"matchDatasources\": [\n        \"packagist\"\n      ],\n      \"matchPackageNames\": [\n        \"shopware/core\",\n        \"shopware/administration\",\n        \"shopware/elasticsearch\",\n        \"shopware/storefront\"\n      ],\n      \"groupName\": \"shopware\",\n      \"versioning\": \"regex:(?\u003Ccompatibility>\\\\d+)\\\\.(?\u003Cmajor>\\\\d+)(\\\\.(?\u003Cminor>\\\\d+))?(\\\\.(?\u003Cpatch>\\\\d+))?$\",\n      \"sourceUrl\": \"https://github.com/shopware/shopware\"\n    }\n  ]\n}\n",[11102],{"type":28,"tag":548,"props":11103,"children":11104},{"__ignoreMap":7},[11105,11112,11131,11143,11150,11171,11183,11191,11199,11211,11222,11234,11246,11254,11261,11282,11366,11383,11390,11397],{"type":28,"tag":116,"props":11106,"children":11107},{"class":553,"line":554},[11108],{"type":28,"tag":116,"props":11109,"children":11110},{"style":564},[11111],{"type":55,"value":1852},{"type":28,"tag":116,"props":11113,"children":11114},{"class":553,"line":271},[11115,11119,11123,11127],{"type":28,"tag":116,"props":11116,"children":11117},{"style":1858},[11118],{"type":55,"value":10559},{"type":28,"tag":116,"props":11120,"children":11121},{"style":564},[11122],{"type":55,"value":593},{"type":28,"tag":116,"props":11124,"children":11125},{"style":1868},[11126],{"type":55,"value":10568},{"type":28,"tag":116,"props":11128,"children":11129},{"style":564},[11130],{"type":55,"value":1876},{"type":28,"tag":116,"props":11132,"children":11133},{"class":553,"line":582},[11134,11139],{"type":28,"tag":116,"props":11135,"children":11136},{"style":1858},[11137],{"type":55,"value":11138},"  \"packageRules\"",{"type":28,"tag":116,"props":11140,"children":11141},{"style":564},[11142],{"type":55,"value":2093},{"type":28,"tag":116,"props":11144,"children":11145},{"class":553,"line":602},[11146],{"type":28,"tag":116,"props":11147,"children":11148},{"style":564},[11149],{"type":55,"value":2101},{"type":28,"tag":116,"props":11151,"children":11152},{"class":553,"line":539},[11153,11158,11162,11167],{"type":28,"tag":116,"props":11154,"children":11155},{"style":1858},[11156],{"type":55,"value":11157},"      \"description\"",{"type":28,"tag":116,"props":11159,"children":11160},{"style":564},[11161],{"type":55,"value":593},{"type":28,"tag":116,"props":11163,"children":11164},{"style":1868},[11165],{"type":55,"value":11166},"\"Follow Shopware version schema\"",{"type":28,"tag":116,"props":11168,"children":11169},{"style":564},[11170],{"type":55,"value":1876},{"type":28,"tag":116,"props":11172,"children":11173},{"class":553,"line":540},[11174,11179],{"type":28,"tag":116,"props":11175,"children":11176},{"style":1858},[11177],{"type":55,"value":11178},"      \"matchDatasources\"",{"type":28,"tag":116,"props":11180,"children":11181},{"style":564},[11182],{"type":55,"value":2093},{"type":28,"tag":116,"props":11184,"children":11185},{"class":553,"line":541},[11186],{"type":28,"tag":116,"props":11187,"children":11188},{"style":1868},[11189],{"type":55,"value":11190},"        \"packagist\"\n",{"type":28,"tag":116,"props":11192,"children":11193},{"class":553,"line":542},[11194],{"type":28,"tag":116,"props":11195,"children":11196},{"style":564},[11197],{"type":55,"value":11198},"      ],\n",{"type":28,"tag":116,"props":11200,"children":11201},{"class":553,"line":543},[11202,11207],{"type":28,"tag":116,"props":11203,"children":11204},{"style":1858},[11205],{"type":55,"value":11206},"      \"matchPackageNames\"",{"type":28,"tag":116,"props":11208,"children":11209},{"style":564},[11210],{"type":55,"value":2093},{"type":28,"tag":116,"props":11212,"children":11213},{"class":553,"line":1203},[11214,11218],{"type":28,"tag":116,"props":11215,"children":11216},{"style":1868},[11217],{"type":55,"value":3291},{"type":28,"tag":116,"props":11219,"children":11220},{"style":564},[11221],{"type":55,"value":1876},{"type":28,"tag":116,"props":11223,"children":11224},{"class":553,"line":1216},[11225,11230],{"type":28,"tag":116,"props":11226,"children":11227},{"style":1868},[11228],{"type":55,"value":11229},"        \"shopware/administration\"",{"type":28,"tag":116,"props":11231,"children":11232},{"style":564},[11233],{"type":55,"value":1876},{"type":28,"tag":116,"props":11235,"children":11236},{"class":553,"line":107},[11237,11242],{"type":28,"tag":116,"props":11238,"children":11239},{"style":1868},[11240],{"type":55,"value":11241},"        \"shopware/elasticsearch\"",{"type":28,"tag":116,"props":11243,"children":11244},{"style":564},[11245],{"type":55,"value":1876},{"type":28,"tag":116,"props":11247,"children":11248},{"class":553,"line":1241},[11249],{"type":28,"tag":116,"props":11250,"children":11251},{"style":1868},[11252],{"type":55,"value":11253},"        \"shopware/storefront\"\n",{"type":28,"tag":116,"props":11255,"children":11256},{"class":553,"line":1254},[11257],{"type":28,"tag":116,"props":11258,"children":11259},{"style":564},[11260],{"type":55,"value":11198},{"type":28,"tag":116,"props":11262,"children":11263},{"class":553,"line":1267},[11264,11269,11273,11278],{"type":28,"tag":116,"props":11265,"children":11266},{"style":1858},[11267],{"type":55,"value":11268},"      \"groupName\"",{"type":28,"tag":116,"props":11270,"children":11271},{"style":564},[11272],{"type":55,"value":593},{"type":28,"tag":116,"props":11274,"children":11275},{"style":1868},[11276],{"type":55,"value":11277},"\"shopware\"",{"type":28,"tag":116,"props":11279,"children":11280},{"style":564},[11281],{"type":55,"value":1876},{"type":28,"tag":116,"props":11283,"children":11284},{"class":553,"line":1277},[11285,11290,11294,11299,11303,11308,11312,11317,11321,11326,11330,11335,11339,11344,11348,11353,11357,11362],{"type":28,"tag":116,"props":11286,"children":11287},{"style":1858},[11288],{"type":55,"value":11289},"      \"versioning\"",{"type":28,"tag":116,"props":11291,"children":11292},{"style":564},[11293],{"type":55,"value":593},{"type":28,"tag":116,"props":11295,"children":11296},{"style":1868},[11297],{"type":55,"value":11298},"\"regex:(?\u003Ccompatibility>",{"type":28,"tag":116,"props":11300,"children":11301},{"style":2170},[11302],{"type":55,"value":2473},{"type":28,"tag":116,"props":11304,"children":11305},{"style":1868},[11306],{"type":55,"value":11307},"d+)",{"type":28,"tag":116,"props":11309,"children":11310},{"style":2170},[11311],{"type":55,"value":2473},{"type":28,"tag":116,"props":11313,"children":11314},{"style":1868},[11315],{"type":55,"value":11316},".(?\u003Cmajor>",{"type":28,"tag":116,"props":11318,"children":11319},{"style":2170},[11320],{"type":55,"value":2473},{"type":28,"tag":116,"props":11322,"children":11323},{"style":1868},[11324],{"type":55,"value":11325},"d+)(",{"type":28,"tag":116,"props":11327,"children":11328},{"style":2170},[11329],{"type":55,"value":2473},{"type":28,"tag":116,"props":11331,"children":11332},{"style":1868},[11333],{"type":55,"value":11334},".(?\u003Cminor>",{"type":28,"tag":116,"props":11336,"children":11337},{"style":2170},[11338],{"type":55,"value":2473},{"type":28,"tag":116,"props":11340,"children":11341},{"style":1868},[11342],{"type":55,"value":11343},"d+))?(",{"type":28,"tag":116,"props":11345,"children":11346},{"style":2170},[11347],{"type":55,"value":2473},{"type":28,"tag":116,"props":11349,"children":11350},{"style":1868},[11351],{"type":55,"value":11352},".(?\u003Cpatch>",{"type":28,"tag":116,"props":11354,"children":11355},{"style":2170},[11356],{"type":55,"value":2473},{"type":28,"tag":116,"props":11358,"children":11359},{"style":1868},[11360],{"type":55,"value":11361},"d+))?$\"",{"type":28,"tag":116,"props":11363,"children":11364},{"style":564},[11365],{"type":55,"value":1876},{"type":28,"tag":116,"props":11367,"children":11368},{"class":553,"line":1290},[11369,11374,11378],{"type":28,"tag":116,"props":11370,"children":11371},{"style":1858},[11372],{"type":55,"value":11373},"      \"sourceUrl\"",{"type":28,"tag":116,"props":11375,"children":11376},{"style":564},[11377],{"type":55,"value":593},{"type":28,"tag":116,"props":11379,"children":11380},{"style":1868},[11381],{"type":55,"value":11382},"\"https://github.com/shopware/shopware\"\n",{"type":28,"tag":116,"props":11384,"children":11385},{"class":553,"line":1303},[11386],{"type":28,"tag":116,"props":11387,"children":11388},{"style":564},[11389],{"type":55,"value":2423},{"type":28,"tag":116,"props":11391,"children":11392},{"class":553,"line":1312},[11393],{"type":28,"tag":116,"props":11394,"children":11395},{"style":564},[11396],{"type":55,"value":6053},{"type":28,"tag":116,"props":11398,"children":11399},{"class":553,"line":1325},[11400],{"type":28,"tag":116,"props":11401,"children":11402},{"style":564},[11403],{"type":55,"value":2880},{"type":28,"tag":47,"props":11405,"children":11406},{},[11407],{"type":55,"value":11408},"This should result in creation of following merge/pull requests",{"type":28,"tag":686,"props":11410,"children":11411},{},[11412,11446],{"type":28,"tag":690,"props":11413,"children":11414},{},[11415,11417,11423,11424,11430,11431,11437,11438,11444],{"type":55,"value":11416},"fix(deps): update shopware (",{"type":28,"tag":548,"props":11418,"children":11420},{"className":11419},[],[11421],{"type":55,"value":11422},"shopware/administration",{"type":55,"value":10047},{"type":28,"tag":548,"props":11425,"children":11427},{"className":11426},[],[11428],{"type":55,"value":11429},"shopware/core",{"type":55,"value":10047},{"type":28,"tag":548,"props":11432,"children":11434},{"className":11433},[],[11435],{"type":55,"value":11436},"shopware/elasticsearch",{"type":55,"value":10047},{"type":28,"tag":548,"props":11439,"children":11441},{"className":11440},[],[11442],{"type":55,"value":11443},"shopware/storefront",{"type":55,"value":11445},")`",{"type":28,"tag":690,"props":11447,"children":11448},{},[11449,11451,11456,11457,11462,11463,11468,11469,11474],{"type":55,"value":11450},"fix(deps): update shopware to v7 (major) (",{"type":28,"tag":548,"props":11452,"children":11454},{"className":11453},[],[11455],{"type":55,"value":11422},{"type":55,"value":10047},{"type":28,"tag":548,"props":11458,"children":11460},{"className":11459},[],[11461],{"type":55,"value":11429},{"type":55,"value":10047},{"type":28,"tag":548,"props":11464,"children":11466},{"className":11465},[],[11467],{"type":55,"value":11436},{"type":55,"value":10047},{"type":28,"tag":548,"props":11470,"children":11472},{"className":11471},[],[11473],{"type":55,"value":11443},{"type":55,"value":11445},{"type":28,"tag":1705,"props":11476,"children":11477},{},[11478],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":11480},[11481,11482],{"id":10975,"depth":271,"text":10978},{"id":11034,"depth":271,"text":11037},{"_path":462,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":463,"description":464,"author":394,"image":395,"releaseDate":465,"blogCategories":11484,"articleTags":11485,"tags":11486,"body":11487,"_type":275,"_id":470,"_source":277,"_file":471,"_stem":472,"_extension":280},[398,467],[399],[23],{"type":25,"children":11488,"toc":14386},[11489,11493,11499,11509,11760,11765,11771,11776,11781,11786,11885,11891,11896,12135,12141,12146,12164,12171,12187,12514,12519,12582,12588,12603,12627,12999,13003,13039,13042,13050,13053,13056,13062,13073,13083,13096,13099,13106,13500,13504,13529,13532,13535,13545,13551,13907,13911,13924,13927,13932,14362,14366,14382],{"type":28,"tag":1727,"props":11490,"children":11492},{"alt":7,"aspect-ratio":1729,"height":1730,"object-fit":1731,"src":11491},"/blog/gitlab-traefik.png",[],{"type":28,"tag":79,"props":11494,"children":11496},{"id":11495},"the-simplest-way-to-install-gitlab",[11497],{"type":55,"value":11498},"The simplest way to install GitLab",{"type":28,"tag":47,"props":11500,"children":11501},{},[11502,11504],{"type":55,"value":11503},"GitLab provides official instructions to install it using Docker and Docker Compose. You can find it in ",{"type":28,"tag":520,"props":11505,"children":11507},{"href":11506},"https://docs.gitlab.com/install/docker/installation/#install-gitlab-by-using-docker-compose",[11508],{"type":55,"value":9631},{"type":28,"tag":534,"props":11510,"children":11513},{"className":545,"code":11511,"filename":11512,"language":544,"meta":7,"style":7},"services:\n  gitlab:\n    image: gitlab/gitlab-ee:\u003Cversion>-ce.0\n    container_name: gitlab\n    restart: always\n    hostname: '\u003Cgitlab.example.com>'\n    environment:\n      GITLAB_OMNIBUS_CONFIG: |\n        # Add any other gitlab.rb configuration here, each on its own line\n        external_url 'https://\u003Cgitlab.example.com>'\n    ports:\n      - '80:80'\n      - '443:443'\n      - '22:22'\n    volumes:\n      - '$GITLAB_HOME/config:/etc/gitlab'\n      - '$GITLAB_HOME/logs:/var/log/gitlab'\n      - '$GITLAB_HOME/data:/var/opt/gitlab'\n    shm_size: '256m'\n","gitlab/docker-compose.yaml",[11514],{"type":28,"tag":548,"props":11515,"children":11516},{"__ignoreMap":7},[11517,11528,11540,11556,11572,11587,11604,11615,11632,11640,11648,11660,11672,11684,11696,11707,11719,11731,11743],{"type":28,"tag":116,"props":11518,"children":11519},{"class":553,"line":554},[11520,11524],{"type":28,"tag":116,"props":11521,"children":11522},{"style":558},[11523],{"type":55,"value":561},{"type":28,"tag":116,"props":11525,"children":11526},{"style":564},[11527],{"type":55,"value":567},{"type":28,"tag":116,"props":11529,"children":11530},{"class":553,"line":271},[11531,11536],{"type":28,"tag":116,"props":11532,"children":11533},{"style":558},[11534],{"type":55,"value":11535},"  gitlab",{"type":28,"tag":116,"props":11537,"children":11538},{"style":564},[11539],{"type":55,"value":567},{"type":28,"tag":116,"props":11541,"children":11542},{"class":553,"line":582},[11543,11547,11551],{"type":28,"tag":116,"props":11544,"children":11545},{"style":558},[11546],{"type":55,"value":588},{"type":28,"tag":116,"props":11548,"children":11549},{"style":564},[11550],{"type":55,"value":593},{"type":28,"tag":116,"props":11552,"children":11553},{"style":596},[11554],{"type":55,"value":11555},"gitlab/gitlab-ee:\u003Cversion>-ce.0\n",{"type":28,"tag":116,"props":11557,"children":11558},{"class":553,"line":602},[11559,11563,11567],{"type":28,"tag":116,"props":11560,"children":11561},{"style":558},[11562],{"type":55,"value":1141},{"type":28,"tag":116,"props":11564,"children":11565},{"style":564},[11566],{"type":55,"value":593},{"type":28,"tag":116,"props":11568,"children":11569},{"style":596},[11570],{"type":55,"value":11571},"gitlab\n",{"type":28,"tag":116,"props":11573,"children":11574},{"class":553,"line":539},[11575,11579,11583],{"type":28,"tag":116,"props":11576,"children":11577},{"style":558},[11578],{"type":55,"value":1158},{"type":28,"tag":116,"props":11580,"children":11581},{"style":564},[11582],{"type":55,"value":593},{"type":28,"tag":116,"props":11584,"children":11585},{"style":596},[11586],{"type":55,"value":1167},{"type":28,"tag":116,"props":11588,"children":11589},{"class":553,"line":540},[11590,11595,11599],{"type":28,"tag":116,"props":11591,"children":11592},{"style":558},[11593],{"type":55,"value":11594},"    hostname",{"type":28,"tag":116,"props":11596,"children":11597},{"style":564},[11598],{"type":55,"value":593},{"type":28,"tag":116,"props":11600,"children":11601},{"style":596},[11602],{"type":55,"value":11603},"'\u003Cgitlab.example.com>'\n",{"type":28,"tag":116,"props":11605,"children":11606},{"class":553,"line":541},[11607,11611],{"type":28,"tag":116,"props":11608,"children":11609},{"style":558},[11610],{"type":55,"value":9914},{"type":28,"tag":116,"props":11612,"children":11613},{"style":564},[11614],{"type":55,"value":567},{"type":28,"tag":116,"props":11616,"children":11617},{"class":553,"line":542},[11618,11623,11627],{"type":28,"tag":116,"props":11619,"children":11620},{"style":558},[11621],{"type":55,"value":11622},"      GITLAB_OMNIBUS_CONFIG",{"type":28,"tag":116,"props":11624,"children":11625},{"style":564},[11626],{"type":55,"value":593},{"type":28,"tag":116,"props":11628,"children":11629},{"style":4807},[11630],{"type":55,"value":11631},"|\n",{"type":28,"tag":116,"props":11633,"children":11634},{"class":553,"line":543},[11635],{"type":28,"tag":116,"props":11636,"children":11637},{"style":596},[11638],{"type":55,"value":11639},"        # Add any other gitlab.rb configuration here, each on its own line\n",{"type":28,"tag":116,"props":11641,"children":11642},{"class":553,"line":1203},[11643],{"type":28,"tag":116,"props":11644,"children":11645},{"style":596},[11646],{"type":55,"value":11647},"        external_url 'https://\u003Cgitlab.example.com>'\n",{"type":28,"tag":116,"props":11649,"children":11650},{"class":553,"line":1216},[11651,11656],{"type":28,"tag":116,"props":11652,"children":11653},{"style":558},[11654],{"type":55,"value":11655},"    ports",{"type":28,"tag":116,"props":11657,"children":11658},{"style":564},[11659],{"type":55,"value":567},{"type":28,"tag":116,"props":11661,"children":11662},{"class":553,"line":107},[11663,11667],{"type":28,"tag":116,"props":11664,"children":11665},{"style":564},[11666],{"type":55,"value":622},{"type":28,"tag":116,"props":11668,"children":11669},{"style":596},[11670],{"type":55,"value":11671},"'80:80'\n",{"type":28,"tag":116,"props":11673,"children":11674},{"class":553,"line":1241},[11675,11679],{"type":28,"tag":116,"props":11676,"children":11677},{"style":564},[11678],{"type":55,"value":622},{"type":28,"tag":116,"props":11680,"children":11681},{"style":596},[11682],{"type":55,"value":11683},"'443:443'\n",{"type":28,"tag":116,"props":11685,"children":11686},{"class":553,"line":1254},[11687,11691],{"type":28,"tag":116,"props":11688,"children":11689},{"style":564},[11690],{"type":55,"value":622},{"type":28,"tag":116,"props":11692,"children":11693},{"style":596},[11694],{"type":55,"value":11695},"'22:22'\n",{"type":28,"tag":116,"props":11697,"children":11698},{"class":553,"line":1267},[11699,11703],{"type":28,"tag":116,"props":11700,"children":11701},{"style":558},[11702],{"type":55,"value":1404},{"type":28,"tag":116,"props":11704,"children":11705},{"style":564},[11706],{"type":55,"value":567},{"type":28,"tag":116,"props":11708,"children":11709},{"class":553,"line":1277},[11710,11714],{"type":28,"tag":116,"props":11711,"children":11712},{"style":564},[11713],{"type":55,"value":622},{"type":28,"tag":116,"props":11715,"children":11716},{"style":596},[11717],{"type":55,"value":11718},"'$GITLAB_HOME/config:/etc/gitlab'\n",{"type":28,"tag":116,"props":11720,"children":11721},{"class":553,"line":1290},[11722,11726],{"type":28,"tag":116,"props":11723,"children":11724},{"style":564},[11725],{"type":55,"value":622},{"type":28,"tag":116,"props":11727,"children":11728},{"style":596},[11729],{"type":55,"value":11730},"'$GITLAB_HOME/logs:/var/log/gitlab'\n",{"type":28,"tag":116,"props":11732,"children":11733},{"class":553,"line":1303},[11734,11738],{"type":28,"tag":116,"props":11735,"children":11736},{"style":564},[11737],{"type":55,"value":622},{"type":28,"tag":116,"props":11739,"children":11740},{"style":596},[11741],{"type":55,"value":11742},"'$GITLAB_HOME/data:/var/opt/gitlab'\n",{"type":28,"tag":116,"props":11744,"children":11745},{"class":553,"line":1312},[11746,11751,11755],{"type":28,"tag":116,"props":11747,"children":11748},{"style":558},[11749],{"type":55,"value":11750},"    shm_size",{"type":28,"tag":116,"props":11752,"children":11753},{"style":564},[11754],{"type":55,"value":593},{"type":28,"tag":116,"props":11756,"children":11757},{"style":596},[11758],{"type":55,"value":11759},"'256m'\n",{"type":28,"tag":47,"props":11761,"children":11762},{},[11763],{"type":55,"value":11764},"This assumes you have your server dedicated to GitLab and all required ports (http, https, ssh) are free.\nGitLab will take care of everything, including TLS configuration with Lets Encrypt",{"type":28,"tag":79,"props":11766,"children":11768},{"id":11767},"integrating-gitlab-alongside-other-deployments",[11769],{"type":55,"value":11770},"Integrating GitLab alongside other deployments",{"type":28,"tag":47,"props":11772,"children":11773},{},[11774],{"type":55,"value":11775},"What if you can't or don't want to install GitLab on a dedicated server?",{"type":28,"tag":47,"props":11777,"children":11778},{},[11779],{"type":55,"value":11780},"Maybe you just want a single server for all you services?",{"type":28,"tag":47,"props":11782,"children":11783},{},[11784],{"type":55,"value":11785},"This is an example structure how you could organize your deployments:",{"type":28,"tag":534,"props":11787,"children":11789},{"className":2888,"code":11788,"language":2890,"meta":7,"style":7},".\n├── gitlab/                # GitLab service stack\n├── gitlab-runner/         # GitLab Runner for CI/CD\n├── mattermost/            # Mattermost team collaboration\n├── nextcloud/             # Nextcloud file hosting and collaboration\n└── traefik/               # Traefik reverse proxy configuration\n",[11790],{"type":28,"tag":548,"props":11791,"children":11792},{"__ignoreMap":7},[11793,11800,11817,11834,11851,11868],{"type":28,"tag":116,"props":11794,"children":11795},{"class":553,"line":554},[11796],{"type":28,"tag":116,"props":11797,"children":11798},{"style":9679},[11799],{"type":55,"value":9682},{"type":28,"tag":116,"props":11801,"children":11802},{"class":553,"line":271},[11803,11807,11812],{"type":28,"tag":116,"props":11804,"children":11805},{"style":2900},[11806],{"type":55,"value":9704},{"type":28,"tag":116,"props":11808,"children":11809},{"style":596},[11810],{"type":55,"value":11811}," gitlab/",{"type":28,"tag":116,"props":11813,"children":11814},{"style":9693},[11815],{"type":55,"value":11816},"                # GitLab service stack\n",{"type":28,"tag":116,"props":11818,"children":11819},{"class":553,"line":582},[11820,11824,11829],{"type":28,"tag":116,"props":11821,"children":11822},{"style":2900},[11823],{"type":55,"value":9704},{"type":28,"tag":116,"props":11825,"children":11826},{"style":596},[11827],{"type":55,"value":11828}," gitlab-runner/",{"type":28,"tag":116,"props":11830,"children":11831},{"style":9693},[11832],{"type":55,"value":11833},"         # GitLab Runner for CI/CD\n",{"type":28,"tag":116,"props":11835,"children":11836},{"class":553,"line":602},[11837,11841,11846],{"type":28,"tag":116,"props":11838,"children":11839},{"style":2900},[11840],{"type":55,"value":9704},{"type":28,"tag":116,"props":11842,"children":11843},{"style":596},[11844],{"type":55,"value":11845}," mattermost/",{"type":28,"tag":116,"props":11847,"children":11848},{"style":9693},[11849],{"type":55,"value":11850},"            # Mattermost team collaboration\n",{"type":28,"tag":116,"props":11852,"children":11853},{"class":553,"line":539},[11854,11858,11863],{"type":28,"tag":116,"props":11855,"children":11856},{"style":2900},[11857],{"type":55,"value":9704},{"type":28,"tag":116,"props":11859,"children":11860},{"style":596},[11861],{"type":55,"value":11862}," nextcloud/",{"type":28,"tag":116,"props":11864,"children":11865},{"style":9693},[11866],{"type":55,"value":11867},"             # Nextcloud file hosting and collaboration\n",{"type":28,"tag":116,"props":11869,"children":11870},{"class":553,"line":540},[11871,11875,11880],{"type":28,"tag":116,"props":11872,"children":11873},{"style":2900},[11874],{"type":55,"value":9757},{"type":28,"tag":116,"props":11876,"children":11877},{"style":596},[11878],{"type":55,"value":11879}," traefik/",{"type":28,"tag":116,"props":11881,"children":11882},{"style":9693},[11883],{"type":55,"value":11884},"               # Traefik reverse proxy configuration\n",{"type":28,"tag":111,"props":11886,"children":11888},{"id":11887},"using-a-dedicated-ip",[11889],{"type":55,"value":11890},"Using a dedicated IP",{"type":28,"tag":47,"props":11892,"children":11893},{},[11894],{"type":55,"value":11895},"In case you have a possibility to attach an additional IP to your server (like a Floating IP on Hetzner),\nyou can simply bind the ports to this IP.",{"type":28,"tag":534,"props":11897,"children":11900},{"className":545,"code":11898,"filename":11512,"highlights":11899,"language":544,"meta":7,"style":7},"services:\n  gitlab:\n    image: gitlab/gitlab-ee:\u003Cversion>-ce.0\n    container_name: gitlab\n    restart: always\n    hostname: '\u003Cgitlab.example.com>'\n    environment:\n      GITLAB_OMNIBUS_CONFIG: |\n        # Add any other gitlab.rb configuration here, each on its own line\n        external_url 'https://\u003Cgitlab.example.com>'\n    ports:\n      - '192.168.0.1:80:80'\n      - '192.168.0.1:443:443'\n      - '192.168.0.1:22:22'\n    volumes:\n      - '$GITLAB_HOME/config:/etc/gitlab'\n      - '$GITLAB_HOME/logs:/var/log/gitlab'\n      - '$GITLAB_HOME/data:/var/opt/gitlab'\n    shm_size: '256m'\n",[107,1241,1254],[11901],{"type":28,"tag":548,"props":11902,"children":11903},{"__ignoreMap":7},[11904,11915,11926,11941,11956,11971,11986,11997,12012,12019,12026,12037,12050,12063,12076,12087,12098,12109,12120],{"type":28,"tag":116,"props":11905,"children":11906},{"class":553,"line":554},[11907,11911],{"type":28,"tag":116,"props":11908,"children":11909},{"style":558},[11910],{"type":55,"value":561},{"type":28,"tag":116,"props":11912,"children":11913},{"style":564},[11914],{"type":55,"value":567},{"type":28,"tag":116,"props":11916,"children":11917},{"class":553,"line":271},[11918,11922],{"type":28,"tag":116,"props":11919,"children":11920},{"style":558},[11921],{"type":55,"value":11535},{"type":28,"tag":116,"props":11923,"children":11924},{"style":564},[11925],{"type":55,"value":567},{"type":28,"tag":116,"props":11927,"children":11928},{"class":553,"line":582},[11929,11933,11937],{"type":28,"tag":116,"props":11930,"children":11931},{"style":558},[11932],{"type":55,"value":588},{"type":28,"tag":116,"props":11934,"children":11935},{"style":564},[11936],{"type":55,"value":593},{"type":28,"tag":116,"props":11938,"children":11939},{"style":596},[11940],{"type":55,"value":11555},{"type":28,"tag":116,"props":11942,"children":11943},{"class":553,"line":602},[11944,11948,11952],{"type":28,"tag":116,"props":11945,"children":11946},{"style":558},[11947],{"type":55,"value":1141},{"type":28,"tag":116,"props":11949,"children":11950},{"style":564},[11951],{"type":55,"value":593},{"type":28,"tag":116,"props":11953,"children":11954},{"style":596},[11955],{"type":55,"value":11571},{"type":28,"tag":116,"props":11957,"children":11958},{"class":553,"line":539},[11959,11963,11967],{"type":28,"tag":116,"props":11960,"children":11961},{"style":558},[11962],{"type":55,"value":1158},{"type":28,"tag":116,"props":11964,"children":11965},{"style":564},[11966],{"type":55,"value":593},{"type":28,"tag":116,"props":11968,"children":11969},{"style":596},[11970],{"type":55,"value":1167},{"type":28,"tag":116,"props":11972,"children":11973},{"class":553,"line":540},[11974,11978,11982],{"type":28,"tag":116,"props":11975,"children":11976},{"style":558},[11977],{"type":55,"value":11594},{"type":28,"tag":116,"props":11979,"children":11980},{"style":564},[11981],{"type":55,"value":593},{"type":28,"tag":116,"props":11983,"children":11984},{"style":596},[11985],{"type":55,"value":11603},{"type":28,"tag":116,"props":11987,"children":11988},{"class":553,"line":541},[11989,11993],{"type":28,"tag":116,"props":11990,"children":11991},{"style":558},[11992],{"type":55,"value":9914},{"type":28,"tag":116,"props":11994,"children":11995},{"style":564},[11996],{"type":55,"value":567},{"type":28,"tag":116,"props":11998,"children":11999},{"class":553,"line":542},[12000,12004,12008],{"type":28,"tag":116,"props":12001,"children":12002},{"style":558},[12003],{"type":55,"value":11622},{"type":28,"tag":116,"props":12005,"children":12006},{"style":564},[12007],{"type":55,"value":593},{"type":28,"tag":116,"props":12009,"children":12010},{"style":4807},[12011],{"type":55,"value":11631},{"type":28,"tag":116,"props":12013,"children":12014},{"class":553,"line":543},[12015],{"type":28,"tag":116,"props":12016,"children":12017},{"style":596},[12018],{"type":55,"value":11639},{"type":28,"tag":116,"props":12020,"children":12021},{"class":553,"line":1203},[12022],{"type":28,"tag":116,"props":12023,"children":12024},{"style":596},[12025],{"type":55,"value":11647},{"type":28,"tag":116,"props":12027,"children":12028},{"class":553,"line":1216},[12029,12033],{"type":28,"tag":116,"props":12030,"children":12031},{"style":558},[12032],{"type":55,"value":11655},{"type":28,"tag":116,"props":12034,"children":12035},{"style":564},[12036],{"type":55,"value":567},{"type":28,"tag":116,"props":12038,"children":12040},{"class":12039,"line":107},[553,616],[12041,12045],{"type":28,"tag":116,"props":12042,"children":12043},{"style":564},[12044],{"type":55,"value":622},{"type":28,"tag":116,"props":12046,"children":12047},{"style":596},[12048],{"type":55,"value":12049},"'192.168.0.1:80:80'\n",{"type":28,"tag":116,"props":12051,"children":12053},{"class":12052,"line":1241},[553,616],[12054,12058],{"type":28,"tag":116,"props":12055,"children":12056},{"style":564},[12057],{"type":55,"value":622},{"type":28,"tag":116,"props":12059,"children":12060},{"style":596},[12061],{"type":55,"value":12062},"'192.168.0.1:443:443'\n",{"type":28,"tag":116,"props":12064,"children":12066},{"class":12065,"line":1254},[553,616],[12067,12071],{"type":28,"tag":116,"props":12068,"children":12069},{"style":564},[12070],{"type":55,"value":622},{"type":28,"tag":116,"props":12072,"children":12073},{"style":596},[12074],{"type":55,"value":12075},"'192.168.0.1:22:22'\n",{"type":28,"tag":116,"props":12077,"children":12078},{"class":553,"line":1267},[12079,12083],{"type":28,"tag":116,"props":12080,"children":12081},{"style":558},[12082],{"type":55,"value":1404},{"type":28,"tag":116,"props":12084,"children":12085},{"style":564},[12086],{"type":55,"value":567},{"type":28,"tag":116,"props":12088,"children":12089},{"class":553,"line":1277},[12090,12094],{"type":28,"tag":116,"props":12091,"children":12092},{"style":564},[12093],{"type":55,"value":622},{"type":28,"tag":116,"props":12095,"children":12096},{"style":596},[12097],{"type":55,"value":11718},{"type":28,"tag":116,"props":12099,"children":12100},{"class":553,"line":1290},[12101,12105],{"type":28,"tag":116,"props":12102,"children":12103},{"style":564},[12104],{"type":55,"value":622},{"type":28,"tag":116,"props":12106,"children":12107},{"style":596},[12108],{"type":55,"value":11730},{"type":28,"tag":116,"props":12110,"children":12111},{"class":553,"line":1303},[12112,12116],{"type":28,"tag":116,"props":12113,"children":12114},{"style":564},[12115],{"type":55,"value":622},{"type":28,"tag":116,"props":12117,"children":12118},{"style":596},[12119],{"type":55,"value":11742},{"type":28,"tag":116,"props":12121,"children":12122},{"class":553,"line":1312},[12123,12127,12131],{"type":28,"tag":116,"props":12124,"children":12125},{"style":558},[12126],{"type":55,"value":11750},{"type":28,"tag":116,"props":12128,"children":12129},{"style":564},[12130],{"type":55,"value":593},{"type":28,"tag":116,"props":12132,"children":12133},{"style":596},[12134],{"type":55,"value":11759},{"type":28,"tag":111,"props":12136,"children":12138},{"id":12137},"using-traefik-as-a-reverse-proxy",[12139],{"type":55,"value":12140},"Using Traefik as a reverse proxy",{"type":28,"tag":47,"props":12142,"children":12143},{},[12144],{"type":55,"value":12145},"In this case I assume that you:",{"type":28,"tag":686,"props":12147,"children":12148},{},[12149,12154,12159],{"type":28,"tag":690,"props":12150,"children":12151},{},[12152],{"type":55,"value":12153},"can't or don't want to assign a dedicated IP for GitLab",{"type":28,"tag":690,"props":12155,"children":12156},{},[12157],{"type":55,"value":12158},"can't or don't want to change you default ssh port",{"type":28,"tag":690,"props":12160,"children":12161},{},[12162],{"type":55,"value":12163},"want to use Traefik as a reverse proxy",{"type":28,"tag":12165,"props":12166,"children":12168},"h4",{"id":12167},"the-traefik-deployment",[12169],{"type":55,"value":12170},"The Traefik deployment",{"type":28,"tag":47,"props":12172,"children":12173},{},[12174,12176,12185],{"type":55,"value":12175},"Remember to replace ",{"type":28,"tag":51,"props":12177,"children":12178},{},[12179],{"type":28,"tag":548,"props":12180,"children":12182},{"className":12181},[],[12183],{"type":55,"value":12184},"\u003Cinfo@example.com>",{"type":55,"value":12186}," with your own email.",{"type":28,"tag":534,"props":12188,"children":12190},{"className":545,"code":12189,"filename":1073,"language":544,"meta":7,"style":7},"volumes:\n  letsencrypt:\n\nservices:\n  traefik:\n    image: traefik:3\n    container_name: traefik\n    restart: always\n    network_mode: host\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock:ro\n      - letsencrypt:/letsencrypt\n    command:\n      - --log.level=INFO\n\n      - --entrypoints.web.address=:80\n      - --entrypoints.web.http.redirections.entrypoint.to=websecure\n      - --entrypoints.web.http.redirections.entrypoint.scheme=https\n\n      - --entrypoints.websecure.address=:443\n      - --entrypoints.websecure.http.tls.certresolver=letsencrypt\n\n      - --providers.docker=true\n      - --providers.docker.exposedByDefault=false\n\n      - --certificatesresolvers.letsencrypt.acme.email=\u003Cinfo@example.com>\n      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n",[12191],{"type":28,"tag":548,"props":12192,"children":12193},{"__ignoreMap":7},[12194,12205,12216,12223,12234,12245,12260,12275,12290,12305,12316,12327,12339,12350,12362,12369,12380,12391,12402,12409,12420,12431,12438,12450,12462,12469,12481,12492,12503],{"type":28,"tag":116,"props":12195,"children":12196},{"class":553,"line":554},[12197,12201],{"type":28,"tag":116,"props":12198,"children":12199},{"style":558},[12200],{"type":55,"value":1086},{"type":28,"tag":116,"props":12202,"children":12203},{"style":564},[12204],{"type":55,"value":567},{"type":28,"tag":116,"props":12206,"children":12207},{"class":553,"line":271},[12208,12212],{"type":28,"tag":116,"props":12209,"children":12210},{"style":558},[12211],{"type":55,"value":1098},{"type":28,"tag":116,"props":12213,"children":12214},{"style":564},[12215],{"type":55,"value":567},{"type":28,"tag":116,"props":12217,"children":12218},{"class":553,"line":582},[12219],{"type":28,"tag":116,"props":12220,"children":12221},{"emptyLinePlaceholder":1271},[12222],{"type":55,"value":1274},{"type":28,"tag":116,"props":12224,"children":12225},{"class":553,"line":602},[12226,12230],{"type":28,"tag":116,"props":12227,"children":12228},{"style":558},[12229],{"type":55,"value":561},{"type":28,"tag":116,"props":12231,"children":12232},{"style":564},[12233],{"type":55,"value":567},{"type":28,"tag":116,"props":12235,"children":12236},{"class":553,"line":539},[12237,12241],{"type":28,"tag":116,"props":12238,"children":12239},{"style":558},[12240],{"type":55,"value":1129},{"type":28,"tag":116,"props":12242,"children":12243},{"style":564},[12244],{"type":55,"value":567},{"type":28,"tag":116,"props":12246,"children":12247},{"class":553,"line":540},[12248,12252,12256],{"type":28,"tag":116,"props":12249,"children":12250},{"style":558},[12251],{"type":55,"value":588},{"type":28,"tag":116,"props":12253,"children":12254},{"style":564},[12255],{"type":55,"value":593},{"type":28,"tag":116,"props":12257,"children":12258},{"style":596},[12259],{"type":55,"value":1183},{"type":28,"tag":116,"props":12261,"children":12262},{"class":553,"line":541},[12263,12267,12271],{"type":28,"tag":116,"props":12264,"children":12265},{"style":558},[12266],{"type":55,"value":1141},{"type":28,"tag":116,"props":12268,"children":12269},{"style":564},[12270],{"type":55,"value":593},{"type":28,"tag":116,"props":12272,"children":12273},{"style":596},[12274],{"type":55,"value":1150},{"type":28,"tag":116,"props":12276,"children":12277},{"class":553,"line":542},[12278,12282,12286],{"type":28,"tag":116,"props":12279,"children":12280},{"style":558},[12281],{"type":55,"value":1158},{"type":28,"tag":116,"props":12283,"children":12284},{"style":564},[12285],{"type":55,"value":593},{"type":28,"tag":116,"props":12287,"children":12288},{"style":596},[12289],{"type":55,"value":1167},{"type":28,"tag":116,"props":12291,"children":12292},{"class":553,"line":543},[12293,12297,12301],{"type":28,"tag":116,"props":12294,"children":12295},{"style":558},[12296],{"type":55,"value":1191},{"type":28,"tag":116,"props":12298,"children":12299},{"style":564},[12300],{"type":55,"value":593},{"type":28,"tag":116,"props":12302,"children":12303},{"style":596},[12304],{"type":55,"value":1200},{"type":28,"tag":116,"props":12306,"children":12307},{"class":553,"line":1203},[12308,12312],{"type":28,"tag":116,"props":12309,"children":12310},{"style":558},[12311],{"type":55,"value":1404},{"type":28,"tag":116,"props":12313,"children":12314},{"style":564},[12315],{"type":55,"value":567},{"type":28,"tag":116,"props":12317,"children":12318},{"class":553,"line":1216},[12319,12323],{"type":28,"tag":116,"props":12320,"children":12321},{"style":564},[12322],{"type":55,"value":622},{"type":28,"tag":116,"props":12324,"children":12325},{"style":596},[12326],{"type":55,"value":1421},{"type":28,"tag":116,"props":12328,"children":12329},{"class":553,"line":107},[12330,12334],{"type":28,"tag":116,"props":12331,"children":12332},{"style":564},[12333],{"type":55,"value":622},{"type":28,"tag":116,"props":12335,"children":12336},{"style":596},[12337],{"type":55,"value":12338},"letsencrypt:/letsencrypt\n",{"type":28,"tag":116,"props":12340,"children":12341},{"class":553,"line":1241},[12342,12346],{"type":28,"tag":116,"props":12343,"children":12344},{"style":558},[12345],{"type":55,"value":1209},{"type":28,"tag":116,"props":12347,"children":12348},{"style":564},[12349],{"type":55,"value":567},{"type":28,"tag":116,"props":12351,"children":12352},{"class":553,"line":1254},[12353,12357],{"type":28,"tag":116,"props":12354,"children":12355},{"style":564},[12356],{"type":55,"value":622},{"type":28,"tag":116,"props":12358,"children":12359},{"style":596},[12360],{"type":55,"value":12361},"--log.level=INFO\n",{"type":28,"tag":116,"props":12363,"children":12364},{"class":553,"line":1267},[12365],{"type":28,"tag":116,"props":12366,"children":12367},{"emptyLinePlaceholder":1271},[12368],{"type":55,"value":1274},{"type":28,"tag":116,"props":12370,"children":12371},{"class":553,"line":1277},[12372,12376],{"type":28,"tag":116,"props":12373,"children":12374},{"style":564},[12375],{"type":55,"value":622},{"type":28,"tag":116,"props":12377,"children":12378},{"style":596},[12379],{"type":55,"value":1287},{"type":28,"tag":116,"props":12381,"children":12382},{"class":553,"line":1290},[12383,12387],{"type":28,"tag":116,"props":12384,"children":12385},{"style":564},[12386],{"type":55,"value":622},{"type":28,"tag":116,"props":12388,"children":12389},{"style":596},[12390],{"type":55,"value":1322},{"type":28,"tag":116,"props":12392,"children":12393},{"class":553,"line":1303},[12394,12398],{"type":28,"tag":116,"props":12395,"children":12396},{"style":564},[12397],{"type":55,"value":622},{"type":28,"tag":116,"props":12399,"children":12400},{"style":596},[12401],{"type":55,"value":1335},{"type":28,"tag":116,"props":12403,"children":12404},{"class":553,"line":1312},[12405],{"type":28,"tag":116,"props":12406,"children":12407},{"emptyLinePlaceholder":1271},[12408],{"type":55,"value":1274},{"type":28,"tag":116,"props":12410,"children":12411},{"class":553,"line":1325},[12412,12416],{"type":28,"tag":116,"props":12413,"children":12414},{"style":564},[12415],{"type":55,"value":622},{"type":28,"tag":116,"props":12417,"children":12418},{"style":596},[12419],{"type":55,"value":1300},{"type":28,"tag":116,"props":12421,"children":12422},{"class":553,"line":1338},[12423,12427],{"type":28,"tag":116,"props":12424,"children":12425},{"style":564},[12426],{"type":55,"value":622},{"type":28,"tag":116,"props":12428,"children":12429},{"style":596},[12430],{"type":55,"value":1348},{"type":28,"tag":116,"props":12432,"children":12433},{"class":553,"line":1351},[12434],{"type":28,"tag":116,"props":12435,"children":12436},{"emptyLinePlaceholder":1271},[12437],{"type":55,"value":1274},{"type":28,"tag":116,"props":12439,"children":12440},{"class":553,"line":1359},[12441,12445],{"type":28,"tag":116,"props":12442,"children":12443},{"style":564},[12444],{"type":55,"value":622},{"type":28,"tag":116,"props":12446,"children":12447},{"style":596},[12448],{"type":55,"value":12449},"--providers.docker=true\n",{"type":28,"tag":116,"props":12451,"children":12452},{"class":553,"line":1372},[12453,12457],{"type":28,"tag":116,"props":12454,"children":12455},{"style":564},[12456],{"type":55,"value":622},{"type":28,"tag":116,"props":12458,"children":12459},{"style":596},[12460],{"type":55,"value":12461},"--providers.docker.exposedByDefault=false\n",{"type":28,"tag":116,"props":12463,"children":12464},{"class":553,"line":1385},[12465],{"type":28,"tag":116,"props":12466,"children":12467},{"emptyLinePlaceholder":1271},[12468],{"type":55,"value":1274},{"type":28,"tag":116,"props":12470,"children":12471},{"class":553,"line":1398},[12472,12476],{"type":28,"tag":116,"props":12473,"children":12474},{"style":564},[12475],{"type":55,"value":622},{"type":28,"tag":116,"props":12477,"children":12478},{"style":596},[12479],{"type":55,"value":12480},"--certificatesresolvers.letsencrypt.acme.email=\u003Cinfo@example.com>\n",{"type":28,"tag":116,"props":12482,"children":12483},{"class":553,"line":1411},[12484,12488],{"type":28,"tag":116,"props":12485,"children":12486},{"style":564},[12487],{"type":55,"value":622},{"type":28,"tag":116,"props":12489,"children":12490},{"style":596},[12491],{"type":55,"value":1251},{"type":28,"tag":116,"props":12493,"children":12494},{"class":553,"line":1424},[12495,12499],{"type":28,"tag":116,"props":12496,"children":12497},{"style":564},[12498],{"type":55,"value":622},{"type":28,"tag":116,"props":12500,"children":12501},{"style":596},[12502],{"type":55,"value":1226},{"type":28,"tag":116,"props":12504,"children":12505},{"class":553,"line":2278},[12506,12510],{"type":28,"tag":116,"props":12507,"children":12508},{"style":564},[12509],{"type":55,"value":622},{"type":28,"tag":116,"props":12511,"children":12512},{"style":596},[12513],{"type":55,"value":1264},{"type":28,"tag":47,"props":12515,"children":12516},{},[12517],{"type":55,"value":12518},"This setup will:",{"type":28,"tag":686,"props":12520,"children":12521},{},[12522,12531,12540,12545,12562,12571],{"type":28,"tag":690,"props":12523,"children":12524},{},[12525],{"type":28,"tag":520,"props":12526,"children":12528},{"href":12527},"https://doc.traefik.io/traefik/reference/install-configuration/providers/docker/",[12529],{"type":55,"value":12530},"enable the docker provider",{"type":28,"tag":690,"props":12532,"children":12533},{},[12534],{"type":28,"tag":520,"props":12535,"children":12537},{"href":12536},"https://doc.traefik.io/traefik/providers/docker/#exposedbydefault",[12538],{"type":55,"value":12539},"disable the container discovery",{"type":28,"tag":690,"props":12541,"children":12542},{},[12543],{"type":55,"value":12544},"redirect all HTTP traffic to HTTPS",{"type":28,"tag":690,"props":12546,"children":12547},{},[12548],{"type":28,"tag":520,"props":12549,"children":12551},{"href":12550},"https://doc.traefik.io/traefik/https/acme/#httpchallenge",[12552,12554,12560],{"type":55,"value":12553},"configure Let's Encrypt with ",{"type":28,"tag":548,"props":12555,"children":12557},{"className":12556},[],[12558],{"type":55,"value":12559},"HTTP-01",{"type":55,"value":12561}," challenge",{"type":28,"tag":690,"props":12563,"children":12564},{},[12565],{"type":28,"tag":520,"props":12566,"children":12568},{"href":12567},"https://doc.traefik.io/traefik/routing/entrypoints/#tls",[12569],{"type":55,"value":12570},"apply the TLS configuration to all routes",{"type":28,"tag":690,"props":12572,"children":12573},{},[12574,12580],{"type":28,"tag":520,"props":12575,"children":12577},{"href":12576},"https://docs.docker.com/engine/network/tutorials/host/",[12578],{"type":55,"value":12579},"start the Traefik container bound directly to host's network",{"type":55,"value":12581},", so no addition configuration is required for traefik",{"type":28,"tag":12165,"props":12583,"children":12585},{"id":12584},"the-gitlab-deployment",[12586],{"type":55,"value":12587},"The GitLab deployment",{"type":28,"tag":47,"props":12589,"children":12590},{},[12591,12592,12601],{"type":55,"value":12175},{"type":28,"tag":51,"props":12593,"children":12594},{},[12595],{"type":28,"tag":548,"props":12596,"children":12598},{"className":12597},[],[12599],{"type":55,"value":12600},"\u003Cgitlab.example.com>",{"type":55,"value":12602}," with your own domain.",{"type":28,"tag":47,"props":12604,"children":12605},{},[12606,12608,12614,12616,12625],{"type":55,"value":12607},"Please take a look in the ",{"type":28,"tag":520,"props":12609,"children":12611},{"href":12610},"https://docs.gitlab.com/install/docker/installation/#create-a-directory-for-the-volumes",[12612],{"type":55,"value":12613},"official dokumentation",{"type":55,"value":12615}," about ",{"type":28,"tag":51,"props":12617,"children":12618},{},[12619],{"type":28,"tag":548,"props":12620,"children":12622},{"className":12621},[],[12623],{"type":55,"value":12624},"GITLAB_HOME",{"type":55,"value":12626}," directory",{"type":28,"tag":534,"props":12628,"children":12631},{"className":545,"code":12629,"filename":11512,"highlights":12630,"language":544,"meta":7,"style":7},"services:\n  gitlab:\n    image: gitlab/gitlab-ce:\u003Cversion>-ce.0\n    container_name: gitlab\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.gitlab.rule=Host(`\u003Cgitlab.example.com>`)\"\n      - \"traefik.http.routers.gitlab.service=gitlab\"\n      - \"traefik.http.services.gitlab.loadbalancer.server.port=80\"\n    restart: always\n    hostname: 'gitlab.example.com'\n    environment:\n      GITLAB_OMNIBUS_CONFIG: |\n        # Add any other gitlab.rb configuration here, each on its own line\n        external_url '\u003Chttps://gitlab.example.com>'\n        \n        letsencrypt['enable'] = false\n        \n        nginx['listen_port'] = 80\n        nginx['listen_https'] = false\n        nginx['proxy_set_headers'] = {\n          \"X-Forwarded-Proto\" => \"https\",\n          \"X-Forwarded-Ssl\" => \"on\"\n        }\n        \n        gitlab_rails['gitlab_shell_ssh_port'] = 2424\n    ports:\n      - '2424:22'\n    volumes:\n      - '$GITLAB_HOME/config:/etc/gitlab'\n      - '$GITLAB_HOME/logs:/var/log/gitlab'\n      - '$GITLAB_HOME/data:/var/opt/gitlab'\n    shm_size: '256m'\n",[539,540,541,542,543,1290,1312,1325,1338,1351,1359,1372,1398,1424],[12632],{"type":28,"tag":548,"props":12633,"children":12634},{"__ignoreMap":7},[12635,12646,12657,12673,12688,12700,12712,12725,12738,12751,12766,12782,12793,12808,12815,12823,12831,12840,12847,12856,12865,12874,12883,12892,12900,12907,12916,12927,12940,12951,12962,12973,12984],{"type":28,"tag":116,"props":12636,"children":12637},{"class":553,"line":554},[12638,12642],{"type":28,"tag":116,"props":12639,"children":12640},{"style":558},[12641],{"type":55,"value":561},{"type":28,"tag":116,"props":12643,"children":12644},{"style":564},[12645],{"type":55,"value":567},{"type":28,"tag":116,"props":12647,"children":12648},{"class":553,"line":271},[12649,12653],{"type":28,"tag":116,"props":12650,"children":12651},{"style":558},[12652],{"type":55,"value":11535},{"type":28,"tag":116,"props":12654,"children":12655},{"style":564},[12656],{"type":55,"value":567},{"type":28,"tag":116,"props":12658,"children":12659},{"class":553,"line":582},[12660,12664,12668],{"type":28,"tag":116,"props":12661,"children":12662},{"style":558},[12663],{"type":55,"value":588},{"type":28,"tag":116,"props":12665,"children":12666},{"style":564},[12667],{"type":55,"value":593},{"type":28,"tag":116,"props":12669,"children":12670},{"style":596},[12671],{"type":55,"value":12672},"gitlab/gitlab-ce:\u003Cversion>-ce.0\n",{"type":28,"tag":116,"props":12674,"children":12675},{"class":553,"line":602},[12676,12680,12684],{"type":28,"tag":116,"props":12677,"children":12678},{"style":558},[12679],{"type":55,"value":1141},{"type":28,"tag":116,"props":12681,"children":12682},{"style":564},[12683],{"type":55,"value":593},{"type":28,"tag":116,"props":12685,"children":12686},{"style":596},[12687],{"type":55,"value":11571},{"type":28,"tag":116,"props":12689,"children":12691},{"class":12690,"line":539},[553,616],[12692,12696],{"type":28,"tag":116,"props":12693,"children":12694},{"style":558},[12695],{"type":55,"value":608},{"type":28,"tag":116,"props":12697,"children":12698},{"style":564},[12699],{"type":55,"value":567},{"type":28,"tag":116,"props":12701,"children":12703},{"class":12702,"line":540},[553,616],[12704,12708],{"type":28,"tag":116,"props":12705,"children":12706},{"style":564},[12707],{"type":55,"value":622},{"type":28,"tag":116,"props":12709,"children":12710},{"style":596},[12711],{"type":55,"value":627},{"type":28,"tag":116,"props":12713,"children":12715},{"class":12714,"line":541},[553,616],[12716,12720],{"type":28,"tag":116,"props":12717,"children":12718},{"style":564},[12719],{"type":55,"value":622},{"type":28,"tag":116,"props":12721,"children":12722},{"style":596},[12723],{"type":55,"value":12724},"\"traefik.http.routers.gitlab.rule=Host(`\u003Cgitlab.example.com>`)\"\n",{"type":28,"tag":116,"props":12726,"children":12728},{"class":12727,"line":542},[553,616],[12729,12733],{"type":28,"tag":116,"props":12730,"children":12731},{"style":564},[12732],{"type":55,"value":622},{"type":28,"tag":116,"props":12734,"children":12735},{"style":596},[12736],{"type":55,"value":12737},"\"traefik.http.routers.gitlab.service=gitlab\"\n",{"type":28,"tag":116,"props":12739,"children":12741},{"class":12740,"line":543},[553,616],[12742,12746],{"type":28,"tag":116,"props":12743,"children":12744},{"style":564},[12745],{"type":55,"value":622},{"type":28,"tag":116,"props":12747,"children":12748},{"style":596},[12749],{"type":55,"value":12750},"\"traefik.http.services.gitlab.loadbalancer.server.port=80\"\n",{"type":28,"tag":116,"props":12752,"children":12753},{"class":553,"line":1203},[12754,12758,12762],{"type":28,"tag":116,"props":12755,"children":12756},{"style":558},[12757],{"type":55,"value":1158},{"type":28,"tag":116,"props":12759,"children":12760},{"style":564},[12761],{"type":55,"value":593},{"type":28,"tag":116,"props":12763,"children":12764},{"style":596},[12765],{"type":55,"value":1167},{"type":28,"tag":116,"props":12767,"children":12768},{"class":553,"line":1216},[12769,12773,12777],{"type":28,"tag":116,"props":12770,"children":12771},{"style":558},[12772],{"type":55,"value":11594},{"type":28,"tag":116,"props":12774,"children":12775},{"style":564},[12776],{"type":55,"value":593},{"type":28,"tag":116,"props":12778,"children":12779},{"style":596},[12780],{"type":55,"value":12781},"'gitlab.example.com'\n",{"type":28,"tag":116,"props":12783,"children":12784},{"class":553,"line":107},[12785,12789],{"type":28,"tag":116,"props":12786,"children":12787},{"style":558},[12788],{"type":55,"value":9914},{"type":28,"tag":116,"props":12790,"children":12791},{"style":564},[12792],{"type":55,"value":567},{"type":28,"tag":116,"props":12794,"children":12795},{"class":553,"line":1241},[12796,12800,12804],{"type":28,"tag":116,"props":12797,"children":12798},{"style":558},[12799],{"type":55,"value":11622},{"type":28,"tag":116,"props":12801,"children":12802},{"style":564},[12803],{"type":55,"value":593},{"type":28,"tag":116,"props":12805,"children":12806},{"style":4807},[12807],{"type":55,"value":11631},{"type":28,"tag":116,"props":12809,"children":12810},{"class":553,"line":1254},[12811],{"type":28,"tag":116,"props":12812,"children":12813},{"style":596},[12814],{"type":55,"value":11639},{"type":28,"tag":116,"props":12816,"children":12817},{"class":553,"line":1267},[12818],{"type":28,"tag":116,"props":12819,"children":12820},{"style":596},[12821],{"type":55,"value":12822},"        external_url '\u003Chttps://gitlab.example.com>'\n",{"type":28,"tag":116,"props":12824,"children":12825},{"class":553,"line":1277},[12826],{"type":28,"tag":116,"props":12827,"children":12828},{"style":596},[12829],{"type":55,"value":12830},"        \n",{"type":28,"tag":116,"props":12832,"children":12834},{"class":12833,"line":1290},[553,616],[12835],{"type":28,"tag":116,"props":12836,"children":12837},{"style":596},[12838],{"type":55,"value":12839},"        letsencrypt['enable'] = false\n",{"type":28,"tag":116,"props":12841,"children":12842},{"class":553,"line":1303},[12843],{"type":28,"tag":116,"props":12844,"children":12845},{"style":596},[12846],{"type":55,"value":12830},{"type":28,"tag":116,"props":12848,"children":12850},{"class":12849,"line":1312},[553,616],[12851],{"type":28,"tag":116,"props":12852,"children":12853},{"style":596},[12854],{"type":55,"value":12855},"        nginx['listen_port'] = 80\n",{"type":28,"tag":116,"props":12857,"children":12859},{"class":12858,"line":1325},[553,616],[12860],{"type":28,"tag":116,"props":12861,"children":12862},{"style":596},[12863],{"type":55,"value":12864},"        nginx['listen_https'] = false\n",{"type":28,"tag":116,"props":12866,"children":12868},{"class":12867,"line":1338},[553,616],[12869],{"type":28,"tag":116,"props":12870,"children":12871},{"style":596},[12872],{"type":55,"value":12873},"        nginx['proxy_set_headers'] = {\n",{"type":28,"tag":116,"props":12875,"children":12877},{"class":12876,"line":1351},[553,616],[12878],{"type":28,"tag":116,"props":12879,"children":12880},{"style":596},[12881],{"type":55,"value":12882},"          \"X-Forwarded-Proto\" => \"https\",\n",{"type":28,"tag":116,"props":12884,"children":12886},{"class":12885,"line":1359},[553,616],[12887],{"type":28,"tag":116,"props":12888,"children":12889},{"style":596},[12890],{"type":55,"value":12891},"          \"X-Forwarded-Ssl\" => \"on\"\n",{"type":28,"tag":116,"props":12893,"children":12895},{"class":12894,"line":1372},[553,616],[12896],{"type":28,"tag":116,"props":12897,"children":12898},{"style":596},[12899],{"type":55,"value":3407},{"type":28,"tag":116,"props":12901,"children":12902},{"class":553,"line":1385},[12903],{"type":28,"tag":116,"props":12904,"children":12905},{"style":596},[12906],{"type":55,"value":12830},{"type":28,"tag":116,"props":12908,"children":12910},{"class":12909,"line":1398},[553,616],[12911],{"type":28,"tag":116,"props":12912,"children":12913},{"style":596},[12914],{"type":55,"value":12915},"        gitlab_rails['gitlab_shell_ssh_port'] = 2424\n",{"type":28,"tag":116,"props":12917,"children":12918},{"class":553,"line":1411},[12919,12923],{"type":28,"tag":116,"props":12920,"children":12921},{"style":558},[12922],{"type":55,"value":11655},{"type":28,"tag":116,"props":12924,"children":12925},{"style":564},[12926],{"type":55,"value":567},{"type":28,"tag":116,"props":12928,"children":12930},{"class":12929,"line":1424},[553,616],[12931,12935],{"type":28,"tag":116,"props":12932,"children":12933},{"style":564},[12934],{"type":55,"value":622},{"type":28,"tag":116,"props":12936,"children":12937},{"style":596},[12938],{"type":55,"value":12939},"'2424:22'\n",{"type":28,"tag":116,"props":12941,"children":12942},{"class":553,"line":2278},[12943,12947],{"type":28,"tag":116,"props":12944,"children":12945},{"style":558},[12946],{"type":55,"value":1404},{"type":28,"tag":116,"props":12948,"children":12949},{"style":564},[12950],{"type":55,"value":567},{"type":28,"tag":116,"props":12952,"children":12953},{"class":553,"line":2286},[12954,12958],{"type":28,"tag":116,"props":12955,"children":12956},{"style":564},[12957],{"type":55,"value":622},{"type":28,"tag":116,"props":12959,"children":12960},{"style":596},[12961],{"type":55,"value":11718},{"type":28,"tag":116,"props":12963,"children":12964},{"class":553,"line":2306},[12965,12969],{"type":28,"tag":116,"props":12966,"children":12967},{"style":564},[12968],{"type":55,"value":622},{"type":28,"tag":116,"props":12970,"children":12971},{"style":596},[12972],{"type":55,"value":11730},{"type":28,"tag":116,"props":12974,"children":12975},{"class":553,"line":2327},[12976,12980],{"type":28,"tag":116,"props":12977,"children":12978},{"style":564},[12979],{"type":55,"value":622},{"type":28,"tag":116,"props":12981,"children":12982},{"style":596},[12983],{"type":55,"value":11742},{"type":28,"tag":116,"props":12985,"children":12986},{"class":553,"line":2339},[12987,12991,12995],{"type":28,"tag":116,"props":12988,"children":12989},{"style":558},[12990],{"type":55,"value":11750},{"type":28,"tag":116,"props":12992,"children":12993},{"style":564},[12994],{"type":55,"value":593},{"type":28,"tag":116,"props":12996,"children":12997},{"style":596},[12998],{"type":55,"value":11759},{"type":28,"tag":47,"props":13000,"children":13001},{},[13002],{"type":55,"value":12518},{"type":28,"tag":686,"props":13004,"children":13005},{},[13006,13011,13016,13021,13026],{"type":28,"tag":690,"props":13007,"children":13008},{},[13009],{"type":55,"value":13010},"disable the Let's Encrypt",{"type":28,"tag":690,"props":13012,"children":13013},{},[13014],{"type":55,"value":13015},"disable listening on https and listen on port 80",{"type":28,"tag":690,"props":13017,"children":13018},{},[13019],{"type":55,"value":13020},"set the required proxy headers",{"type":28,"tag":690,"props":13022,"children":13023},{},[13024],{"type":55,"value":13025},"change the ssh port to 2424",{"type":28,"tag":690,"props":13027,"children":13028},{},[13029,13031,13037],{"type":55,"value":13030},"instruct Traefik to route all traffic for ",{"type":28,"tag":548,"props":13032,"children":13034},{"className":13033},[],[13035],{"type":55,"value":13036},"gitlab.example.com",{"type":55,"value":13038}," to port 80 of the container",{"type":28,"tag":1542,"props":13040,"children":13041},{},[],{"type":28,"tag":47,"props":13043,"children":13044},{},[13045],{"type":28,"tag":116,"props":13046,"children":13048},{"className":13047},[5122],[13049],{"type":55,"value":7172},{"type":28,"tag":1542,"props":13051,"children":13052},{},[],{"type":28,"tag":1062,"props":13054,"children":13055},{},[],{"type":28,"tag":111,"props":13057,"children":13059},{"id":13058},"gitlab-container-registry",[13060],{"type":55,"value":13061},"GitLab Container registry",{"type":28,"tag":47,"props":13063,"children":13064},{},[13065,13067],{"type":55,"value":13066},"When you got so far, you probably also want to set up the ",{"type":28,"tag":520,"props":13068,"children":13070},{"href":13069},"https://docs.gitlab.com/administration/packages/container_registry/",[13071],{"type":55,"value":13072},"container registry",{"type":28,"tag":12165,"props":13074,"children":13076},{"id":13075},"configure-container-registry-under-its-own-domain",[13077],{"type":28,"tag":520,"props":13078,"children":13080},{"href":13079},"https://docs.gitlab.com/administration/packages/container_registry/#configure-container-registry-under-its-own-domain",[13081],{"type":55,"value":13082},"Configure container registry under its own domain",{"type":28,"tag":47,"props":13084,"children":13085},{},[13086,13088,13094],{"type":55,"value":13087},"This setup is easy. We just need to set the ",{"type":28,"tag":548,"props":13089,"children":13091},{"className":13090},[],[13092],{"type":55,"value":13093},"registry_external_url",{"type":55,"value":13095}," and instruct Traefik where to route the requests",{"type":28,"tag":1542,"props":13097,"children":13098},{},[],{"type":28,"tag":13100,"props":13101,"children":13103},"h5",{"id":13102},"update-the-gitlab-config",[13104],{"type":55,"value":13105},"Update the GitLab config",{"type":28,"tag":534,"props":13107,"children":13110},{"className":545,"code":13108,"filename":11512,"highlights":13109,"language":544,"meta":7,"style":7},"services:\n  gitlab:\n    image: gitlab/gitlab-ce:\u003Cversion>-ce.0\n    container_name: gitlab\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.gitlab.rule=Host(`\u003Cgitlab.example.com>`)\"\n      - \"traefik.http.routers.gitlab.service=gitlab\"\n      - \"traefik.http.services.gitlab.loadbalancer.server.port=80\"\n      - \"traefik.http.routers.container-registry.rule=Host(`registry.gitlab.example.com`)\"\n      - \"traefik.http.services.container-registry.loadbalancer.server.port=5000\"\n    restart: always\n    hostname: 'gitlab.example.com'\n    environment:\n      GITLAB_OMNIBUS_CONFIG: |\n        # Add any other gitlab.rb configuration here, each on its own line\n        external_url '\u003Chttps://gitlab.example.com>'\n\n        letsencrypt['enable'] = false\n\n        nginx['listen_port'] = 80\n        nginx['listen_https'] = false\n        nginx['proxy_set_headers'] = {\n          \"X-Forwarded-Proto\" => \"https\",\n          \"X-Forwarded-Ssl\" => \"on\"\n        }\n\n        gitlab_rails['gitlab_shell_ssh_port'] = 2424\n\n        registry_external_url '\u003Chttps://registry.gitlab.example.com>'\n        registry_nginx['enable'] = false\n    ports:\n      - '2424:22'\n    volumes:\n      - '$GITLAB_HOME/config:/etc/gitlab'\n      - '$GITLAB_HOME/logs:/var/log/gitlab'\n      - '$GITLAB_HOME/data:/var/opt/gitlab'\n    shm_size: '256m'\n",[1203,1216,2286,2306],[13111],{"type":28,"tag":548,"props":13112,"children":13113},{"__ignoreMap":7},[13114,13125,13136,13151,13166,13177,13188,13199,13210,13221,13234,13247,13262,13277,13288,13303,13310,13317,13324,13331,13338,13345,13352,13359,13366,13373,13380,13387,13394,13401,13410,13419,13430,13441,13452,13463,13474,13485],{"type":28,"tag":116,"props":13115,"children":13116},{"class":553,"line":554},[13117,13121],{"type":28,"tag":116,"props":13118,"children":13119},{"style":558},[13120],{"type":55,"value":561},{"type":28,"tag":116,"props":13122,"children":13123},{"style":564},[13124],{"type":55,"value":567},{"type":28,"tag":116,"props":13126,"children":13127},{"class":553,"line":271},[13128,13132],{"type":28,"tag":116,"props":13129,"children":13130},{"style":558},[13131],{"type":55,"value":11535},{"type":28,"tag":116,"props":13133,"children":13134},{"style":564},[13135],{"type":55,"value":567},{"type":28,"tag":116,"props":13137,"children":13138},{"class":553,"line":582},[13139,13143,13147],{"type":28,"tag":116,"props":13140,"children":13141},{"style":558},[13142],{"type":55,"value":588},{"type":28,"tag":116,"props":13144,"children":13145},{"style":564},[13146],{"type":55,"value":593},{"type":28,"tag":116,"props":13148,"children":13149},{"style":596},[13150],{"type":55,"value":12672},{"type":28,"tag":116,"props":13152,"children":13153},{"class":553,"line":602},[13154,13158,13162],{"type":28,"tag":116,"props":13155,"children":13156},{"style":558},[13157],{"type":55,"value":1141},{"type":28,"tag":116,"props":13159,"children":13160},{"style":564},[13161],{"type":55,"value":593},{"type":28,"tag":116,"props":13163,"children":13164},{"style":596},[13165],{"type":55,"value":11571},{"type":28,"tag":116,"props":13167,"children":13168},{"class":553,"line":539},[13169,13173],{"type":28,"tag":116,"props":13170,"children":13171},{"style":558},[13172],{"type":55,"value":608},{"type":28,"tag":116,"props":13174,"children":13175},{"style":564},[13176],{"type":55,"value":567},{"type":28,"tag":116,"props":13178,"children":13179},{"class":553,"line":540},[13180,13184],{"type":28,"tag":116,"props":13181,"children":13182},{"style":564},[13183],{"type":55,"value":622},{"type":28,"tag":116,"props":13185,"children":13186},{"style":596},[13187],{"type":55,"value":627},{"type":28,"tag":116,"props":13189,"children":13190},{"class":553,"line":541},[13191,13195],{"type":28,"tag":116,"props":13192,"children":13193},{"style":564},[13194],{"type":55,"value":622},{"type":28,"tag":116,"props":13196,"children":13197},{"style":596},[13198],{"type":55,"value":12724},{"type":28,"tag":116,"props":13200,"children":13201},{"class":553,"line":542},[13202,13206],{"type":28,"tag":116,"props":13203,"children":13204},{"style":564},[13205],{"type":55,"value":622},{"type":28,"tag":116,"props":13207,"children":13208},{"style":596},[13209],{"type":55,"value":12737},{"type":28,"tag":116,"props":13211,"children":13212},{"class":553,"line":543},[13213,13217],{"type":28,"tag":116,"props":13214,"children":13215},{"style":564},[13216],{"type":55,"value":622},{"type":28,"tag":116,"props":13218,"children":13219},{"style":596},[13220],{"type":55,"value":12750},{"type":28,"tag":116,"props":13222,"children":13224},{"class":13223,"line":1203},[553,616],[13225,13229],{"type":28,"tag":116,"props":13226,"children":13227},{"style":564},[13228],{"type":55,"value":622},{"type":28,"tag":116,"props":13230,"children":13231},{"style":596},[13232],{"type":55,"value":13233},"\"traefik.http.routers.container-registry.rule=Host(`registry.gitlab.example.com`)\"\n",{"type":28,"tag":116,"props":13235,"children":13237},{"class":13236,"line":1216},[553,616],[13238,13242],{"type":28,"tag":116,"props":13239,"children":13240},{"style":564},[13241],{"type":55,"value":622},{"type":28,"tag":116,"props":13243,"children":13244},{"style":596},[13245],{"type":55,"value":13246},"\"traefik.http.services.container-registry.loadbalancer.server.port=5000\"\n",{"type":28,"tag":116,"props":13248,"children":13249},{"class":553,"line":107},[13250,13254,13258],{"type":28,"tag":116,"props":13251,"children":13252},{"style":558},[13253],{"type":55,"value":1158},{"type":28,"tag":116,"props":13255,"children":13256},{"style":564},[13257],{"type":55,"value":593},{"type":28,"tag":116,"props":13259,"children":13260},{"style":596},[13261],{"type":55,"value":1167},{"type":28,"tag":116,"props":13263,"children":13264},{"class":553,"line":1241},[13265,13269,13273],{"type":28,"tag":116,"props":13266,"children":13267},{"style":558},[13268],{"type":55,"value":11594},{"type":28,"tag":116,"props":13270,"children":13271},{"style":564},[13272],{"type":55,"value":593},{"type":28,"tag":116,"props":13274,"children":13275},{"style":596},[13276],{"type":55,"value":12781},{"type":28,"tag":116,"props":13278,"children":13279},{"class":553,"line":1254},[13280,13284],{"type":28,"tag":116,"props":13281,"children":13282},{"style":558},[13283],{"type":55,"value":9914},{"type":28,"tag":116,"props":13285,"children":13286},{"style":564},[13287],{"type":55,"value":567},{"type":28,"tag":116,"props":13289,"children":13290},{"class":553,"line":1267},[13291,13295,13299],{"type":28,"tag":116,"props":13292,"children":13293},{"style":558},[13294],{"type":55,"value":11622},{"type":28,"tag":116,"props":13296,"children":13297},{"style":564},[13298],{"type":55,"value":593},{"type":28,"tag":116,"props":13300,"children":13301},{"style":4807},[13302],{"type":55,"value":11631},{"type":28,"tag":116,"props":13304,"children":13305},{"class":553,"line":1277},[13306],{"type":28,"tag":116,"props":13307,"children":13308},{"style":596},[13309],{"type":55,"value":11639},{"type":28,"tag":116,"props":13311,"children":13312},{"class":553,"line":1290},[13313],{"type":28,"tag":116,"props":13314,"children":13315},{"style":596},[13316],{"type":55,"value":12822},{"type":28,"tag":116,"props":13318,"children":13319},{"class":553,"line":1303},[13320],{"type":28,"tag":116,"props":13321,"children":13322},{"emptyLinePlaceholder":1271},[13323],{"type":55,"value":1274},{"type":28,"tag":116,"props":13325,"children":13326},{"class":553,"line":1312},[13327],{"type":28,"tag":116,"props":13328,"children":13329},{"style":596},[13330],{"type":55,"value":12839},{"type":28,"tag":116,"props":13332,"children":13333},{"class":553,"line":1325},[13334],{"type":28,"tag":116,"props":13335,"children":13336},{"emptyLinePlaceholder":1271},[13337],{"type":55,"value":1274},{"type":28,"tag":116,"props":13339,"children":13340},{"class":553,"line":1338},[13341],{"type":28,"tag":116,"props":13342,"children":13343},{"style":596},[13344],{"type":55,"value":12855},{"type":28,"tag":116,"props":13346,"children":13347},{"class":553,"line":1351},[13348],{"type":28,"tag":116,"props":13349,"children":13350},{"style":596},[13351],{"type":55,"value":12864},{"type":28,"tag":116,"props":13353,"children":13354},{"class":553,"line":1359},[13355],{"type":28,"tag":116,"props":13356,"children":13357},{"style":596},[13358],{"type":55,"value":12873},{"type":28,"tag":116,"props":13360,"children":13361},{"class":553,"line":1372},[13362],{"type":28,"tag":116,"props":13363,"children":13364},{"style":596},[13365],{"type":55,"value":12882},{"type":28,"tag":116,"props":13367,"children":13368},{"class":553,"line":1385},[13369],{"type":28,"tag":116,"props":13370,"children":13371},{"style":596},[13372],{"type":55,"value":12891},{"type":28,"tag":116,"props":13374,"children":13375},{"class":553,"line":1398},[13376],{"type":28,"tag":116,"props":13377,"children":13378},{"style":596},[13379],{"type":55,"value":3407},{"type":28,"tag":116,"props":13381,"children":13382},{"class":553,"line":1411},[13383],{"type":28,"tag":116,"props":13384,"children":13385},{"emptyLinePlaceholder":1271},[13386],{"type":55,"value":1274},{"type":28,"tag":116,"props":13388,"children":13389},{"class":553,"line":1424},[13390],{"type":28,"tag":116,"props":13391,"children":13392},{"style":596},[13393],{"type":55,"value":12915},{"type":28,"tag":116,"props":13395,"children":13396},{"class":553,"line":2278},[13397],{"type":28,"tag":116,"props":13398,"children":13399},{"emptyLinePlaceholder":1271},[13400],{"type":55,"value":1274},{"type":28,"tag":116,"props":13402,"children":13404},{"class":13403,"line":2286},[553,616],[13405],{"type":28,"tag":116,"props":13406,"children":13407},{"style":596},[13408],{"type":55,"value":13409},"        registry_external_url '\u003Chttps://registry.gitlab.example.com>'\n",{"type":28,"tag":116,"props":13411,"children":13413},{"class":13412,"line":2306},[553,616],[13414],{"type":28,"tag":116,"props":13415,"children":13416},{"style":596},[13417],{"type":55,"value":13418},"        registry_nginx['enable'] = false\n",{"type":28,"tag":116,"props":13420,"children":13421},{"class":553,"line":2327},[13422,13426],{"type":28,"tag":116,"props":13423,"children":13424},{"style":558},[13425],{"type":55,"value":11655},{"type":28,"tag":116,"props":13427,"children":13428},{"style":564},[13429],{"type":55,"value":567},{"type":28,"tag":116,"props":13431,"children":13432},{"class":553,"line":2339},[13433,13437],{"type":28,"tag":116,"props":13434,"children":13435},{"style":564},[13436],{"type":55,"value":622},{"type":28,"tag":116,"props":13438,"children":13439},{"style":596},[13440],{"type":55,"value":12939},{"type":28,"tag":116,"props":13442,"children":13443},{"class":553,"line":2355},[13444,13448],{"type":28,"tag":116,"props":13445,"children":13446},{"style":558},[13447],{"type":55,"value":1404},{"type":28,"tag":116,"props":13449,"children":13450},{"style":564},[13451],{"type":55,"value":567},{"type":28,"tag":116,"props":13453,"children":13454},{"class":553,"line":2363},[13455,13459],{"type":28,"tag":116,"props":13456,"children":13457},{"style":564},[13458],{"type":55,"value":622},{"type":28,"tag":116,"props":13460,"children":13461},{"style":596},[13462],{"type":55,"value":11718},{"type":28,"tag":116,"props":13464,"children":13465},{"class":553,"line":1837},[13466,13470],{"type":28,"tag":116,"props":13467,"children":13468},{"style":564},[13469],{"type":55,"value":622},{"type":28,"tag":116,"props":13471,"children":13472},{"style":596},[13473],{"type":55,"value":11730},{"type":28,"tag":116,"props":13475,"children":13476},{"class":553,"line":1838},[13477,13481],{"type":28,"tag":116,"props":13478,"children":13479},{"style":564},[13480],{"type":55,"value":622},{"type":28,"tag":116,"props":13482,"children":13483},{"style":596},[13484],{"type":55,"value":11742},{"type":28,"tag":116,"props":13486,"children":13487},{"class":553,"line":1839},[13488,13492,13496],{"type":28,"tag":116,"props":13489,"children":13490},{"style":558},[13491],{"type":55,"value":11750},{"type":28,"tag":116,"props":13493,"children":13494},{"style":564},[13495],{"type":55,"value":593},{"type":28,"tag":116,"props":13497,"children":13498},{"style":596},[13499],{"type":55,"value":11759},{"type":28,"tag":47,"props":13501,"children":13502},{},[13503],{"type":55,"value":12518},{"type":28,"tag":686,"props":13505,"children":13506},{},[13507,13512,13517],{"type":28,"tag":690,"props":13508,"children":13509},{},[13510],{"type":55,"value":13511},"set the registry external url",{"type":28,"tag":690,"props":13513,"children":13514},{},[13515],{"type":55,"value":13516},"disable the nginx for the registry",{"type":28,"tag":690,"props":13518,"children":13519},{},[13520,13521,13527],{"type":55,"value":13030},{"type":28,"tag":548,"props":13522,"children":13524},{"className":13523},[],[13525],{"type":55,"value":13526},"registry.gitlab.example.com",{"type":55,"value":13528}," to port 5000 of the container",{"type":28,"tag":1542,"props":13530,"children":13531},{},[],{"type":28,"tag":1062,"props":13533,"children":13534},{},[],{"type":28,"tag":12165,"props":13536,"children":13538},{"id":13537},"configure-container-registry-under-an-existing-gitlab-domain",[13539],{"type":28,"tag":520,"props":13540,"children":13542},{"href":13541},"https://docs.gitlab.com/administration/packages/container_registry/#configure-container-registry-under-an-existing-gitlab-domain",[13543],{"type":55,"value":13544},"Configure container registry under an existing GitLab domain",{"type":28,"tag":13100,"props":13546,"children":13548},{"id":13547},"update-the-traefik-config",[13549],{"type":55,"value":13550},"Update the Traefik config",{"type":28,"tag":534,"props":13552,"children":13555},{"className":545,"code":13553,"filename":1073,"highlights":13554,"language":544,"meta":7,"style":7},"volumes:\n  letsencrypt:\n\nservices:\n  traefik:\n    image: traefik:3\n    container_name: traefik\n    restart: always\n    network_mode: host\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock:ro\n      - letsencrypt:/letsencrypt\n    command:\n      - --log.level=INFO\n\n      - --entrypoints.web.address=:80\n      - --entrypoints.web.http.redirections.entrypoint.to=websecure\n      - --entrypoints.web.http.redirections.entrypoint.scheme=https\n\n      - --entrypoints.websecure.address=:443\n      - --entrypoints.websecure.http.tls.certresolver=letsencrypt\n        \n      - --entrypoints.container-registry.address=:5050\n      - --entrypoints.container-registry.http.tls.certresolver=letsencrypt\n\n      - --providers.docker=true\n      - --providers.docker.exposedByDefault=false\n\n      - --certificatesresolvers.letsencrypt.acme.email=\u003Cinfo@example.com>\n      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge=true\n      - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n",[1359,1372],[13556],{"type":28,"tag":548,"props":13557,"children":13558},{"__ignoreMap":7},[13559,13570,13581,13588,13599,13610,13625,13640,13655,13670,13681,13692,13703,13714,13725,13732,13743,13754,13765,13772,13783,13794,13801,13814,13827,13834,13845,13856,13863,13874,13885,13896],{"type":28,"tag":116,"props":13560,"children":13561},{"class":553,"line":554},[13562,13566],{"type":28,"tag":116,"props":13563,"children":13564},{"style":558},[13565],{"type":55,"value":1086},{"type":28,"tag":116,"props":13567,"children":13568},{"style":564},[13569],{"type":55,"value":567},{"type":28,"tag":116,"props":13571,"children":13572},{"class":553,"line":271},[13573,13577],{"type":28,"tag":116,"props":13574,"children":13575},{"style":558},[13576],{"type":55,"value":1098},{"type":28,"tag":116,"props":13578,"children":13579},{"style":564},[13580],{"type":55,"value":567},{"type":28,"tag":116,"props":13582,"children":13583},{"class":553,"line":582},[13584],{"type":28,"tag":116,"props":13585,"children":13586},{"emptyLinePlaceholder":1271},[13587],{"type":55,"value":1274},{"type":28,"tag":116,"props":13589,"children":13590},{"class":553,"line":602},[13591,13595],{"type":28,"tag":116,"props":13592,"children":13593},{"style":558},[13594],{"type":55,"value":561},{"type":28,"tag":116,"props":13596,"children":13597},{"style":564},[13598],{"type":55,"value":567},{"type":28,"tag":116,"props":13600,"children":13601},{"class":553,"line":539},[13602,13606],{"type":28,"tag":116,"props":13603,"children":13604},{"style":558},[13605],{"type":55,"value":1129},{"type":28,"tag":116,"props":13607,"children":13608},{"style":564},[13609],{"type":55,"value":567},{"type":28,"tag":116,"props":13611,"children":13612},{"class":553,"line":540},[13613,13617,13621],{"type":28,"tag":116,"props":13614,"children":13615},{"style":558},[13616],{"type":55,"value":588},{"type":28,"tag":116,"props":13618,"children":13619},{"style":564},[13620],{"type":55,"value":593},{"type":28,"tag":116,"props":13622,"children":13623},{"style":596},[13624],{"type":55,"value":1183},{"type":28,"tag":116,"props":13626,"children":13627},{"class":553,"line":541},[13628,13632,13636],{"type":28,"tag":116,"props":13629,"children":13630},{"style":558},[13631],{"type":55,"value":1141},{"type":28,"tag":116,"props":13633,"children":13634},{"style":564},[13635],{"type":55,"value":593},{"type":28,"tag":116,"props":13637,"children":13638},{"style":596},[13639],{"type":55,"value":1150},{"type":28,"tag":116,"props":13641,"children":13642},{"class":553,"line":542},[13643,13647,13651],{"type":28,"tag":116,"props":13644,"children":13645},{"style":558},[13646],{"type":55,"value":1158},{"type":28,"tag":116,"props":13648,"children":13649},{"style":564},[13650],{"type":55,"value":593},{"type":28,"tag":116,"props":13652,"children":13653},{"style":596},[13654],{"type":55,"value":1167},{"type":28,"tag":116,"props":13656,"children":13657},{"class":553,"line":543},[13658,13662,13666],{"type":28,"tag":116,"props":13659,"children":13660},{"style":558},[13661],{"type":55,"value":1191},{"type":28,"tag":116,"props":13663,"children":13664},{"style":564},[13665],{"type":55,"value":593},{"type":28,"tag":116,"props":13667,"children":13668},{"style":596},[13669],{"type":55,"value":1200},{"type":28,"tag":116,"props":13671,"children":13672},{"class":553,"line":1203},[13673,13677],{"type":28,"tag":116,"props":13674,"children":13675},{"style":558},[13676],{"type":55,"value":1404},{"type":28,"tag":116,"props":13678,"children":13679},{"style":564},[13680],{"type":55,"value":567},{"type":28,"tag":116,"props":13682,"children":13683},{"class":553,"line":1216},[13684,13688],{"type":28,"tag":116,"props":13685,"children":13686},{"style":564},[13687],{"type":55,"value":622},{"type":28,"tag":116,"props":13689,"children":13690},{"style":596},[13691],{"type":55,"value":1421},{"type":28,"tag":116,"props":13693,"children":13694},{"class":553,"line":107},[13695,13699],{"type":28,"tag":116,"props":13696,"children":13697},{"style":564},[13698],{"type":55,"value":622},{"type":28,"tag":116,"props":13700,"children":13701},{"style":596},[13702],{"type":55,"value":12338},{"type":28,"tag":116,"props":13704,"children":13705},{"class":553,"line":1241},[13706,13710],{"type":28,"tag":116,"props":13707,"children":13708},{"style":558},[13709],{"type":55,"value":1209},{"type":28,"tag":116,"props":13711,"children":13712},{"style":564},[13713],{"type":55,"value":567},{"type":28,"tag":116,"props":13715,"children":13716},{"class":553,"line":1254},[13717,13721],{"type":28,"tag":116,"props":13718,"children":13719},{"style":564},[13720],{"type":55,"value":622},{"type":28,"tag":116,"props":13722,"children":13723},{"style":596},[13724],{"type":55,"value":12361},{"type":28,"tag":116,"props":13726,"children":13727},{"class":553,"line":1267},[13728],{"type":28,"tag":116,"props":13729,"children":13730},{"emptyLinePlaceholder":1271},[13731],{"type":55,"value":1274},{"type":28,"tag":116,"props":13733,"children":13734},{"class":553,"line":1277},[13735,13739],{"type":28,"tag":116,"props":13736,"children":13737},{"style":564},[13738],{"type":55,"value":622},{"type":28,"tag":116,"props":13740,"children":13741},{"style":596},[13742],{"type":55,"value":1287},{"type":28,"tag":116,"props":13744,"children":13745},{"class":553,"line":1290},[13746,13750],{"type":28,"tag":116,"props":13747,"children":13748},{"style":564},[13749],{"type":55,"value":622},{"type":28,"tag":116,"props":13751,"children":13752},{"style":596},[13753],{"type":55,"value":1322},{"type":28,"tag":116,"props":13755,"children":13756},{"class":553,"line":1303},[13757,13761],{"type":28,"tag":116,"props":13758,"children":13759},{"style":564},[13760],{"type":55,"value":622},{"type":28,"tag":116,"props":13762,"children":13763},{"style":596},[13764],{"type":55,"value":1335},{"type":28,"tag":116,"props":13766,"children":13767},{"class":553,"line":1312},[13768],{"type":28,"tag":116,"props":13769,"children":13770},{"emptyLinePlaceholder":1271},[13771],{"type":55,"value":1274},{"type":28,"tag":116,"props":13773,"children":13774},{"class":553,"line":1325},[13775,13779],{"type":28,"tag":116,"props":13776,"children":13777},{"style":564},[13778],{"type":55,"value":622},{"type":28,"tag":116,"props":13780,"children":13781},{"style":596},[13782],{"type":55,"value":1300},{"type":28,"tag":116,"props":13784,"children":13785},{"class":553,"line":1338},[13786,13790],{"type":28,"tag":116,"props":13787,"children":13788},{"style":564},[13789],{"type":55,"value":622},{"type":28,"tag":116,"props":13791,"children":13792},{"style":596},[13793],{"type":55,"value":1348},{"type":28,"tag":116,"props":13795,"children":13796},{"class":553,"line":1351},[13797],{"type":28,"tag":116,"props":13798,"children":13799},{"style":564},[13800],{"type":55,"value":12830},{"type":28,"tag":116,"props":13802,"children":13804},{"class":13803,"line":1359},[553,616],[13805,13809],{"type":28,"tag":116,"props":13806,"children":13807},{"style":564},[13808],{"type":55,"value":622},{"type":28,"tag":116,"props":13810,"children":13811},{"style":596},[13812],{"type":55,"value":13813},"--entrypoints.container-registry.address=:5050\n",{"type":28,"tag":116,"props":13815,"children":13817},{"class":13816,"line":1372},[553,616],[13818,13822],{"type":28,"tag":116,"props":13819,"children":13820},{"style":564},[13821],{"type":55,"value":622},{"type":28,"tag":116,"props":13823,"children":13824},{"style":596},[13825],{"type":55,"value":13826},"--entrypoints.container-registry.http.tls.certresolver=letsencrypt\n",{"type":28,"tag":116,"props":13828,"children":13829},{"class":553,"line":1385},[13830],{"type":28,"tag":116,"props":13831,"children":13832},{"emptyLinePlaceholder":1271},[13833],{"type":55,"value":1274},{"type":28,"tag":116,"props":13835,"children":13836},{"class":553,"line":1398},[13837,13841],{"type":28,"tag":116,"props":13838,"children":13839},{"style":564},[13840],{"type":55,"value":622},{"type":28,"tag":116,"props":13842,"children":13843},{"style":596},[13844],{"type":55,"value":12449},{"type":28,"tag":116,"props":13846,"children":13847},{"class":553,"line":1411},[13848,13852],{"type":28,"tag":116,"props":13849,"children":13850},{"style":564},[13851],{"type":55,"value":622},{"type":28,"tag":116,"props":13853,"children":13854},{"style":596},[13855],{"type":55,"value":12461},{"type":28,"tag":116,"props":13857,"children":13858},{"class":553,"line":1424},[13859],{"type":28,"tag":116,"props":13860,"children":13861},{"emptyLinePlaceholder":1271},[13862],{"type":55,"value":1274},{"type":28,"tag":116,"props":13864,"children":13865},{"class":553,"line":2278},[13866,13870],{"type":28,"tag":116,"props":13867,"children":13868},{"style":564},[13869],{"type":55,"value":622},{"type":28,"tag":116,"props":13871,"children":13872},{"style":596},[13873],{"type":55,"value":12480},{"type":28,"tag":116,"props":13875,"children":13876},{"class":553,"line":2286},[13877,13881],{"type":28,"tag":116,"props":13878,"children":13879},{"style":564},[13880],{"type":55,"value":622},{"type":28,"tag":116,"props":13882,"children":13883},{"style":596},[13884],{"type":55,"value":1251},{"type":28,"tag":116,"props":13886,"children":13887},{"class":553,"line":2306},[13888,13892],{"type":28,"tag":116,"props":13889,"children":13890},{"style":564},[13891],{"type":55,"value":622},{"type":28,"tag":116,"props":13893,"children":13894},{"style":596},[13895],{"type":55,"value":1226},{"type":28,"tag":116,"props":13897,"children":13898},{"class":553,"line":2327},[13899,13903],{"type":28,"tag":116,"props":13900,"children":13901},{"style":564},[13902],{"type":55,"value":622},{"type":28,"tag":116,"props":13904,"children":13905},{"style":596},[13906],{"type":55,"value":1264},{"type":28,"tag":47,"props":13908,"children":13909},{},[13910],{"type":55,"value":12518},{"type":28,"tag":686,"props":13912,"children":13913},{},[13914,13919],{"type":28,"tag":690,"props":13915,"children":13916},{},[13917],{"type":55,"value":13918},"add a new entry point for the container registry",{"type":28,"tag":690,"props":13920,"children":13921},{},[13922],{"type":55,"value":13923},"apply the TLS configuration to all routes in this entrypoint",{"type":28,"tag":1542,"props":13925,"children":13926},{},[],{"type":28,"tag":13100,"props":13928,"children":13930},{"id":13929},"update-the-gitlab-config-1",[13931],{"type":55,"value":13105},{"type":28,"tag":534,"props":13933,"children":13936},{"className":545,"code":13934,"filename":11512,"highlights":13935,"language":544,"meta":7,"style":7},"services:\n  gitlab:\n    image: gitlab/gitlab-ce:\u003Cversion>-ce.0\n    container_name: gitlab\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.gitlab.rule=Host(`\u003Cgitlab.example.com>`)\"\n      - \"traefik.http.routers.gitlab.entrypoints=web,websecure\"\n      - \"traefik.http.routers.gitlab.service=gitlab\"\n      - \"traefik.http.services.gitlab.loadbalancer.server.port=80\"\n      - \"traefik.http.routers.container-registry.rule=Host(`gitlab.example.com`)\"\n      - \"traefik.http.routers.container-registry.entrypoints=container-registry\"\n      - \"traefik.http.routers.container-registry.service=container-registry\"\n      - \"traefik.http.services.container-registry.loadbalancer.server.port=5000\"\n    restart: always\n    hostname: 'gitlab.example.com'\n    environment:\n      GITLAB_OMNIBUS_CONFIG: |\n        # Add any other gitlab.rb configuration here, each on its own line\n        external_url '\u003Chttps://gitlab.example.com>'\n\n        letsencrypt['enable'] = false\n\n        nginx['listen_port'] = 80\n        nginx['listen_https'] = false\n        nginx['proxy_set_headers'] = {\n          \"X-Forwarded-Proto\" => \"https\",\n          \"X-Forwarded-Ssl\" => \"on\"\n        }\n\n        gitlab_rails['gitlab_shell_ssh_port'] = 2424\n\n        registry_external_url '\u003Chttps://gitlab.example.com:5050>'\n        registry_nginx['enable'] = false\n    ports:\n      - '2424:22'\n    volumes:\n      - '$GITLAB_HOME/config:/etc/gitlab'\n      - '$GITLAB_HOME/logs:/var/log/gitlab'\n      - '$GITLAB_HOME/data:/var/opt/gitlab'\n    shm_size: '256m'\n",[542,1216,107,1241,1254,2339],[13937],{"type":28,"tag":548,"props":13938,"children":13939},{"__ignoreMap":7},[13940,13951,13962,13977,13992,14003,14014,14025,14038,14049,14060,14073,14086,14099,14111,14126,14141,14152,14167,14174,14181,14188,14195,14202,14209,14216,14223,14230,14237,14244,14251,14258,14265,14274,14281,14292,14303,14314,14325,14336,14347],{"type":28,"tag":116,"props":13941,"children":13942},{"class":553,"line":554},[13943,13947],{"type":28,"tag":116,"props":13944,"children":13945},{"style":558},[13946],{"type":55,"value":561},{"type":28,"tag":116,"props":13948,"children":13949},{"style":564},[13950],{"type":55,"value":567},{"type":28,"tag":116,"props":13952,"children":13953},{"class":553,"line":271},[13954,13958],{"type":28,"tag":116,"props":13955,"children":13956},{"style":558},[13957],{"type":55,"value":11535},{"type":28,"tag":116,"props":13959,"children":13960},{"style":564},[13961],{"type":55,"value":567},{"type":28,"tag":116,"props":13963,"children":13964},{"class":553,"line":582},[13965,13969,13973],{"type":28,"tag":116,"props":13966,"children":13967},{"style":558},[13968],{"type":55,"value":588},{"type":28,"tag":116,"props":13970,"children":13971},{"style":564},[13972],{"type":55,"value":593},{"type":28,"tag":116,"props":13974,"children":13975},{"style":596},[13976],{"type":55,"value":12672},{"type":28,"tag":116,"props":13978,"children":13979},{"class":553,"line":602},[13980,13984,13988],{"type":28,"tag":116,"props":13981,"children":13982},{"style":558},[13983],{"type":55,"value":1141},{"type":28,"tag":116,"props":13985,"children":13986},{"style":564},[13987],{"type":55,"value":593},{"type":28,"tag":116,"props":13989,"children":13990},{"style":596},[13991],{"type":55,"value":11571},{"type":28,"tag":116,"props":13993,"children":13994},{"class":553,"line":539},[13995,13999],{"type":28,"tag":116,"props":13996,"children":13997},{"style":558},[13998],{"type":55,"value":608},{"type":28,"tag":116,"props":14000,"children":14001},{"style":564},[14002],{"type":55,"value":567},{"type":28,"tag":116,"props":14004,"children":14005},{"class":553,"line":540},[14006,14010],{"type":28,"tag":116,"props":14007,"children":14008},{"style":564},[14009],{"type":55,"value":622},{"type":28,"tag":116,"props":14011,"children":14012},{"style":596},[14013],{"type":55,"value":627},{"type":28,"tag":116,"props":14015,"children":14016},{"class":553,"line":541},[14017,14021],{"type":28,"tag":116,"props":14018,"children":14019},{"style":564},[14020],{"type":55,"value":622},{"type":28,"tag":116,"props":14022,"children":14023},{"style":596},[14024],{"type":55,"value":12724},{"type":28,"tag":116,"props":14026,"children":14028},{"class":14027,"line":542},[553,616],[14029,14033],{"type":28,"tag":116,"props":14030,"children":14031},{"style":564},[14032],{"type":55,"value":622},{"type":28,"tag":116,"props":14034,"children":14035},{"style":596},[14036],{"type":55,"value":14037},"\"traefik.http.routers.gitlab.entrypoints=web,websecure\"\n",{"type":28,"tag":116,"props":14039,"children":14040},{"class":553,"line":543},[14041,14045],{"type":28,"tag":116,"props":14042,"children":14043},{"style":564},[14044],{"type":55,"value":622},{"type":28,"tag":116,"props":14046,"children":14047},{"style":596},[14048],{"type":55,"value":12737},{"type":28,"tag":116,"props":14050,"children":14051},{"class":553,"line":1203},[14052,14056],{"type":28,"tag":116,"props":14053,"children":14054},{"style":564},[14055],{"type":55,"value":622},{"type":28,"tag":116,"props":14057,"children":14058},{"style":596},[14059],{"type":55,"value":12750},{"type":28,"tag":116,"props":14061,"children":14063},{"class":14062,"line":1216},[553,616],[14064,14068],{"type":28,"tag":116,"props":14065,"children":14066},{"style":564},[14067],{"type":55,"value":622},{"type":28,"tag":116,"props":14069,"children":14070},{"style":596},[14071],{"type":55,"value":14072},"\"traefik.http.routers.container-registry.rule=Host(`gitlab.example.com`)\"\n",{"type":28,"tag":116,"props":14074,"children":14076},{"class":14075,"line":107},[553,616],[14077,14081],{"type":28,"tag":116,"props":14078,"children":14079},{"style":564},[14080],{"type":55,"value":622},{"type":28,"tag":116,"props":14082,"children":14083},{"style":596},[14084],{"type":55,"value":14085},"\"traefik.http.routers.container-registry.entrypoints=container-registry\"\n",{"type":28,"tag":116,"props":14087,"children":14089},{"class":14088,"line":1241},[553,616],[14090,14094],{"type":28,"tag":116,"props":14091,"children":14092},{"style":564},[14093],{"type":55,"value":622},{"type":28,"tag":116,"props":14095,"children":14096},{"style":596},[14097],{"type":55,"value":14098},"\"traefik.http.routers.container-registry.service=container-registry\"\n",{"type":28,"tag":116,"props":14100,"children":14102},{"class":14101,"line":1254},[553,616],[14103,14107],{"type":28,"tag":116,"props":14104,"children":14105},{"style":564},[14106],{"type":55,"value":622},{"type":28,"tag":116,"props":14108,"children":14109},{"style":596},[14110],{"type":55,"value":13246},{"type":28,"tag":116,"props":14112,"children":14113},{"class":553,"line":1267},[14114,14118,14122],{"type":28,"tag":116,"props":14115,"children":14116},{"style":558},[14117],{"type":55,"value":1158},{"type":28,"tag":116,"props":14119,"children":14120},{"style":564},[14121],{"type":55,"value":593},{"type":28,"tag":116,"props":14123,"children":14124},{"style":596},[14125],{"type":55,"value":1167},{"type":28,"tag":116,"props":14127,"children":14128},{"class":553,"line":1277},[14129,14133,14137],{"type":28,"tag":116,"props":14130,"children":14131},{"style":558},[14132],{"type":55,"value":11594},{"type":28,"tag":116,"props":14134,"children":14135},{"style":564},[14136],{"type":55,"value":593},{"type":28,"tag":116,"props":14138,"children":14139},{"style":596},[14140],{"type":55,"value":12781},{"type":28,"tag":116,"props":14142,"children":14143},{"class":553,"line":1290},[14144,14148],{"type":28,"tag":116,"props":14145,"children":14146},{"style":558},[14147],{"type":55,"value":9914},{"type":28,"tag":116,"props":14149,"children":14150},{"style":564},[14151],{"type":55,"value":567},{"type":28,"tag":116,"props":14153,"children":14154},{"class":553,"line":1303},[14155,14159,14163],{"type":28,"tag":116,"props":14156,"children":14157},{"style":558},[14158],{"type":55,"value":11622},{"type":28,"tag":116,"props":14160,"children":14161},{"style":564},[14162],{"type":55,"value":593},{"type":28,"tag":116,"props":14164,"children":14165},{"style":4807},[14166],{"type":55,"value":11631},{"type":28,"tag":116,"props":14168,"children":14169},{"class":553,"line":1312},[14170],{"type":28,"tag":116,"props":14171,"children":14172},{"style":596},[14173],{"type":55,"value":11639},{"type":28,"tag":116,"props":14175,"children":14176},{"class":553,"line":1325},[14177],{"type":28,"tag":116,"props":14178,"children":14179},{"style":596},[14180],{"type":55,"value":12822},{"type":28,"tag":116,"props":14182,"children":14183},{"class":553,"line":1338},[14184],{"type":28,"tag":116,"props":14185,"children":14186},{"emptyLinePlaceholder":1271},[14187],{"type":55,"value":1274},{"type":28,"tag":116,"props":14189,"children":14190},{"class":553,"line":1351},[14191],{"type":28,"tag":116,"props":14192,"children":14193},{"style":596},[14194],{"type":55,"value":12839},{"type":28,"tag":116,"props":14196,"children":14197},{"class":553,"line":1359},[14198],{"type":28,"tag":116,"props":14199,"children":14200},{"emptyLinePlaceholder":1271},[14201],{"type":55,"value":1274},{"type":28,"tag":116,"props":14203,"children":14204},{"class":553,"line":1372},[14205],{"type":28,"tag":116,"props":14206,"children":14207},{"style":596},[14208],{"type":55,"value":12855},{"type":28,"tag":116,"props":14210,"children":14211},{"class":553,"line":1385},[14212],{"type":28,"tag":116,"props":14213,"children":14214},{"style":596},[14215],{"type":55,"value":12864},{"type":28,"tag":116,"props":14217,"children":14218},{"class":553,"line":1398},[14219],{"type":28,"tag":116,"props":14220,"children":14221},{"style":596},[14222],{"type":55,"value":12873},{"type":28,"tag":116,"props":14224,"children":14225},{"class":553,"line":1411},[14226],{"type":28,"tag":116,"props":14227,"children":14228},{"style":596},[14229],{"type":55,"value":12882},{"type":28,"tag":116,"props":14231,"children":14232},{"class":553,"line":1424},[14233],{"type":28,"tag":116,"props":14234,"children":14235},{"style":596},[14236],{"type":55,"value":12891},{"type":28,"tag":116,"props":14238,"children":14239},{"class":553,"line":2278},[14240],{"type":28,"tag":116,"props":14241,"children":14242},{"style":596},[14243],{"type":55,"value":3407},{"type":28,"tag":116,"props":14245,"children":14246},{"class":553,"line":2286},[14247],{"type":28,"tag":116,"props":14248,"children":14249},{"emptyLinePlaceholder":1271},[14250],{"type":55,"value":1274},{"type":28,"tag":116,"props":14252,"children":14253},{"class":553,"line":2306},[14254],{"type":28,"tag":116,"props":14255,"children":14256},{"style":596},[14257],{"type":55,"value":12915},{"type":28,"tag":116,"props":14259,"children":14260},{"class":553,"line":2327},[14261],{"type":28,"tag":116,"props":14262,"children":14263},{"emptyLinePlaceholder":1271},[14264],{"type":55,"value":1274},{"type":28,"tag":116,"props":14266,"children":14268},{"class":14267,"line":2339},[553,616],[14269],{"type":28,"tag":116,"props":14270,"children":14271},{"style":596},[14272],{"type":55,"value":14273},"        registry_external_url '\u003Chttps://gitlab.example.com:5050>'\n",{"type":28,"tag":116,"props":14275,"children":14276},{"class":553,"line":2355},[14277],{"type":28,"tag":116,"props":14278,"children":14279},{"style":596},[14280],{"type":55,"value":13418},{"type":28,"tag":116,"props":14282,"children":14283},{"class":553,"line":2363},[14284,14288],{"type":28,"tag":116,"props":14285,"children":14286},{"style":558},[14287],{"type":55,"value":11655},{"type":28,"tag":116,"props":14289,"children":14290},{"style":564},[14291],{"type":55,"value":567},{"type":28,"tag":116,"props":14293,"children":14294},{"class":553,"line":1837},[14295,14299],{"type":28,"tag":116,"props":14296,"children":14297},{"style":564},[14298],{"type":55,"value":622},{"type":28,"tag":116,"props":14300,"children":14301},{"style":596},[14302],{"type":55,"value":12939},{"type":28,"tag":116,"props":14304,"children":14305},{"class":553,"line":1838},[14306,14310],{"type":28,"tag":116,"props":14307,"children":14308},{"style":558},[14309],{"type":55,"value":1404},{"type":28,"tag":116,"props":14311,"children":14312},{"style":564},[14313],{"type":55,"value":567},{"type":28,"tag":116,"props":14315,"children":14316},{"class":553,"line":1839},[14317,14321],{"type":28,"tag":116,"props":14318,"children":14319},{"style":564},[14320],{"type":55,"value":622},{"type":28,"tag":116,"props":14322,"children":14323},{"style":596},[14324],{"type":55,"value":11718},{"type":28,"tag":116,"props":14326,"children":14327},{"class":553,"line":1840},[14328,14332],{"type":28,"tag":116,"props":14329,"children":14330},{"style":564},[14331],{"type":55,"value":622},{"type":28,"tag":116,"props":14333,"children":14334},{"style":596},[14335],{"type":55,"value":11730},{"type":28,"tag":116,"props":14337,"children":14338},{"class":553,"line":2426},[14339,14343],{"type":28,"tag":116,"props":14340,"children":14341},{"style":564},[14342],{"type":55,"value":622},{"type":28,"tag":116,"props":14344,"children":14345},{"style":596},[14346],{"type":55,"value":11742},{"type":28,"tag":116,"props":14348,"children":14349},{"class":553,"line":2435},[14350,14354,14358],{"type":28,"tag":116,"props":14351,"children":14352},{"style":558},[14353],{"type":55,"value":11750},{"type":28,"tag":116,"props":14355,"children":14356},{"style":564},[14357],{"type":55,"value":593},{"type":28,"tag":116,"props":14359,"children":14360},{"style":596},[14361],{"type":55,"value":11759},{"type":28,"tag":47,"props":14363,"children":14364},{},[14365],{"type":55,"value":12518},{"type":28,"tag":686,"props":14367,"children":14368},{},[14369,14373,14377],{"type":28,"tag":690,"props":14370,"children":14371},{},[14372],{"type":55,"value":13511},{"type":28,"tag":690,"props":14374,"children":14375},{},[14376],{"type":55,"value":13516},{"type":28,"tag":690,"props":14378,"children":14379},{},[14380],{"type":55,"value":14381},"instruct Traefik to route all traffic from port 5050 to port 5000 of the container",{"type":28,"tag":1705,"props":14383,"children":14384},{},[14385],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":14387},[14388,14389],{"id":11495,"depth":271,"text":11498},{"id":11767,"depth":271,"text":11770,"children":14390},[14391,14392,14393],{"id":11887,"depth":582,"text":11890},{"id":12137,"depth":582,"text":12140},{"id":13058,"depth":582,"text":13061},{"_path":474,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":475,"description":476,"author":477,"image":395,"releaseDate":478,"blogCategories":14395,"articleTags":14396,"tags":14397,"body":14398,"_type":275,"_id":483,"_source":277,"_file":484,"_stem":485,"_extension":280},[480],[399],[23],{"type":25,"children":14399,"toc":15631},[14400,14406,14425,14431,14477,14540,14552,14558,14568,14609,14618,14650,14690,14699,14732,14751,14794,14800,14809,14841,14886,14911,14921,14936,14942,14951,14980,15101,15105,15149,15155,15164,15216,15247,15271,15302,15320,15326,15335,15366,15385,15421,15440,15466,15478,15484,15493,15519,15575,15581,15609,15621],{"type":28,"tag":1727,"props":14401,"children":14405},{"alt":14402,"aspect-ratio":14403,"height":1730,"object-fit":1731,"src":14404},"A person holding a sticker with the word \"Dev-ops\" wright in front of the camera","2.07","/blog/person_holding_devops_sticker.jpg",[],{"type":28,"tag":116,"props":14407,"children":14411},{"className":14408},[14409,14410],"text-right","text-caption",[14412],{"type":28,"tag":47,"props":14413,"children":14414},{},[14415],{"type":28,"tag":14416,"props":14417,"children":14418},"em",{},[14419],{"type":28,"tag":520,"props":14420,"children":14422},{"href":14421},"https://www.pexels.com/photo/person-holding-a-sticker-11035393/",[14423],{"type":55,"value":14424},"Photo by RealToughCandy.com",{"type":28,"tag":79,"props":14426,"children":14428},{"id":14427},"why-developing-a-web-application-is-only-the-beginning",[14429],{"type":55,"value":14430},"Why developing a (web) application is only the beginning",{"type":28,"tag":47,"props":14432,"children":14433},{},[14434,14436,14441,14443,14448,14450,14454,14456,14461,14463,14468,14470,14475],{"type":55,"value":14435},"Web applications are mostly developed and tested in a ",{"type":28,"tag":14416,"props":14437,"children":14438},{},[14439],{"type":55,"value":14440},"Dev",{"type":55,"value":14442}," environment (Development environment) - however the\nactual endurance test takes place on the ",{"type":28,"tag":14416,"props":14444,"children":14445},{},[14446],{"type":55,"value":14447},"Prod",{"type":55,"value":14449}," systems (Production environment). Here, ",{"type":28,"tag":51,"props":14451,"children":14452},{},[14453],{"type":55,"value":399},{"type":55,"value":14455}," (short for\n",{"type":28,"tag":14416,"props":14457,"children":14458},{},[14459],{"type":55,"value":14460},"Development Operations",{"type":55,"value":14462},", representing the close integration between development and IT operations) plays a key role.\nEspecially with web applications on ",{"type":28,"tag":51,"props":14464,"children":14465},{},[14466],{"type":55,"value":14467},"Linux servers",{"type":55,"value":14469}," with complex ",{"type":28,"tag":51,"props":14471,"children":14472},{},[14473],{"type":55,"value":14474},"network infrastructures",{"type":55,"value":14476},", it often only becomes\nclear on the live system how stable and efficient an application is running. In this article, we take a look at some\npopular theories surrounding DevOps in the web environment and examine their validity. In particular, we will focus on\naspects that are relevant to mid-market customers and partners of a software agency.",{"type":28,"tag":47,"props":14478,"children":14479},{},[14480,14482,14487,14489,14494,14495,14500,14502,14511,14512,14521,14523,14531,14533,14538],{"type":55,"value":14481},"We will shed light on why development environments reach their limits, why genuine load tests and ",{"type":28,"tag":14416,"props":14483,"children":14484},{},[14485],{"type":55,"value":14486},"Edge Cases",{"type":55,"value":14488}," are\ndifficult to simulate, and why work begins properly only after the launch (namely under ",{"type":28,"tag":14416,"props":14490,"children":14491},{},[14492],{"type":55,"value":14493},"monitoring",{"type":55,"value":9548},{"type":28,"tag":14416,"props":14496,"children":14497},{},[14498],{"type":55,"value":14499},"continuous\nimprovement",{"type":55,"value":14501},"). We will also explore the tools that are indispensable in our daily work, from\n",{"type":28,"tag":520,"props":14503,"children":14505},{"href":14504},"https://sentry.io/",[14506],{"type":28,"tag":51,"props":14507,"children":14508},{},[14509],{"type":55,"value":14510},"Sentry",{"type":55,"value":10047},{"type":28,"tag":520,"props":14513,"children":14515},{"href":14514},"https://grafana.com/",[14516],{"type":28,"tag":51,"props":14517,"children":14518},{},[14519],{"type":55,"value":14520},"Grafana",{"type":55,"value":14522},", to\n",{"type":28,"tag":520,"props":14524,"children":14526},{"href":14525},"https://www.zabbix.com/",[14527],{"type":28,"tag":51,"props":14528,"children":14529},{},[14530],{"type":55,"value":314},{"type":55,"value":14532},", and how ",{"type":28,"tag":51,"props":14534,"children":14535},{},[14536],{"type":55,"value":14537},"CI/CD pipelines",{"type":55,"value":14539}," help even less experienced developers to deploy\nsafely.",{"type":28,"tag":116,"props":14541,"children":14543},{"className":14542},[14409],[14544],{"type":28,"tag":47,"props":14545,"children":14546},{},[14547],{"type":28,"tag":14416,"props":14548,"children":14549},{},[14550],{"type":55,"value":14551},"Reading duration: approx. 20 minutes",{"type":28,"tag":79,"props":14553,"children":14555},{"id":14554},"development-environment-vs-reality-limited-performance-and-unknown-edge-cases",[14556],{"type":55,"value":14557},"Development environment vs. reality: Limited performance and unknown edge cases",{"type":28,"tag":47,"props":14559,"children":14560},{},[14561,14566],{"type":28,"tag":51,"props":14562,"children":14563},{},[14564],{"type":55,"value":14565},"Thesis:",{"type":55,"value":14567}," Software projects and web applications are built in development environments that are limited in performance\nand test data.",{"type":28,"tag":47,"props":14569,"children":14570},{},[14571,14573,14578,14580,14585,14587,14592,14594,14599,14601,14607],{"type":55,"value":14572},"During the development phase, a web application often runs on a laptop, a desktop PC, or in an isolated\ntest environment of the developers. This ",{"type":28,"tag":51,"props":14574,"children":14575},{},[14576],{"type":55,"value":14577},"Dev environment",{"type":55,"value":14579}," is typically ",{"type":28,"tag":51,"props":14581,"children":14582},{},[14583],{"type":55,"value":14584},"less powerful",{"type":55,"value":14586}," than the later\nproduction servers and contains only a fraction of real data. This is normal at first - nobody has a complete\ncopy of the production database on their laptop, and local quick work is also a goal. However,\nthis discrepancy often leads to some problems not becoming visible in the dev environment at all. Also, with\nperformance issues, there's a tendency to quickly assume that the productive system, with its superior performance, will\nnot struggle as much. A ",{"type":28,"tag":51,"props":14588,"children":14589},{},[14590],{"type":55,"value":14591},"staging",{"type":55,"value":14593}," environment can try to mimic the production environment\nbut it has its ",{"type":28,"tag":51,"props":14595,"children":14596},{},[14597],{"type":55,"value":14598},"limits",{"type":55,"value":14600},": Production environments have nuances that are difficult to simulate in staging - such as real\nuser behavior, large amounts of data, or complex system interactions\n",{"type":28,"tag":520,"props":14602,"children":14604},{"href":14603},"https://www.browserstack.com/guide/testing-in-production#:~:text=1.%20Real,only%20surface%20under%20specific%20conditions",[14605],{"type":55,"value":14606},"browserstack.com",{"type":55,"value":14608},"\n. In other words: Everything runs \"smoothly\" in the test environment, but reality introduces completely different\nfactors.",{"type":28,"tag":47,"props":14610,"children":14611},{},[14612,14616],{"type":28,"tag":51,"props":14613,"children":14614},{},[14615],{"type":55,"value":14565},{"type":55,"value":14617}," Developers and clients often lack a complete overview of realistic use cases, edge cases, and peak loads.",{"type":28,"tag":47,"props":14619,"children":14620},{},[14621,14623,14628,14630,14635,14637,14641,14643,14648],{"type":55,"value":14622},"Development teams and even clients know the ",{"type":28,"tag":14416,"props":14624,"children":14625},{},[14626],{"type":55,"value":14627},"major use cases",{"type":55,"value":14629}," of their software, but ",{"type":28,"tag":51,"props":14631,"children":14632},{},[14633],{"type":55,"value":14634},"real users",{"type":55,"value":14636},"\noften push applications to their limits. Suddenly they use features in combinations that nobody had thought of,\nor input unexpected data. Such ",{"type":28,"tag":51,"props":14638,"children":14639},{},[14640],{"type":55,"value":14486},{"type":55,"value":14642}," (special or boundary cases) often remain undetected in the specification.\nOnly in an actual operation do errors occur, which no one had foreseen before. One reason for this is\nthat some bugs only appear under specific conditions that are not anticipated in pre-production tests.\nFor example, a user profile with an ",{"type":28,"tag":14416,"props":14644,"children":14645},{},[14646],{"type":55,"value":14647},"emoji",{"type":55,"value":14649}," in the name might trigger an error somewhere in the process –\nsomething that did not appear in the test dataset. Or a client uses the web app on an older browser and faces\ndisplay issues. Cases like these often only show up when the application is being used \"in the wild\".",{"type":28,"tag":47,"props":14651,"children":14652},{},[14653,14655,14660,14662,14667,14669,14674,14676,14681,14683,14688],{"type":55,"value":14654},"In addition, clients might be familiar with their business processes, but ",{"type":28,"tag":51,"props":14656,"children":14657},{},[14658],{"type":55,"value":14659},"peak loads",{"type":55,"value":14661}," due to marketing actions or\ncompletely atypical\nusage times (e.g., at 3 a.m. on weekends) are easily underestimated. The ",{"type":28,"tag":51,"props":14663,"children":14664},{},[14665],{"type":55,"value":14666},"critical view",{"type":55,"value":14668}," here:\nModern approaches aim to close this gap by advocating that development and production environments should be as\nsimilar as possible (",{"type":28,"tag":14416,"props":14670,"children":14671},{},[14672],{"type":55,"value":14673},"dev/prod parity",{"type":55,"value":14675},") in order to minimize later surprises.\n",{"type":28,"tag":51,"props":14677,"children":14678},{},[14679],{"type":55,"value":14680},"Containerization",{"type":55,"value":14682}," (e.g. with Docker) allows to locally create an environment that at least in terms of\ndependencies and requirements of the software factors comes very close to the production environment. However, it\nremains unrealistic to anticipate ",{"type":28,"tag":51,"props":14684,"children":14685},{},[14686],{"type":55,"value":14687},"all",{"type":55,"value":14689}," real conditions.",{"type":28,"tag":47,"props":14691,"children":14692},{},[14693,14697],{"type":28,"tag":51,"props":14694,"children":14695},{},[14696],{"type":55,"value":14565},{"type":55,"value":14698}," Behavior under prolonged load, external crawlers, penetration tests, or spam-bots are difficult to simulate.",{"type":28,"tag":47,"props":14700,"children":14701},{},[14702,14704,14709,14711,14716,14718,14723,14725,14730],{"type":55,"value":14703},"Performance tests are good practice, but ",{"type":28,"tag":51,"props":14705,"children":14706},{},[14707],{"type":55,"value":14708},"constant load 24/7",{"type":55,"value":14710}," over weeks cannot be fully replicated “in lab”.\nMost companies conduct stress tests before a launch – yet these often only last a few hours or days. How the application\nbehaves over months (memory leaks? Database grows unexpectedly? Logs fill up the hard disk?) remains open. Also,\n",{"type":28,"tag":51,"props":14712,"children":14713},{},[14714],{"type":55,"value":14715},"malicious attacks",{"type":55,"value":14717}," are a topic. External ",{"type":28,"tag":51,"props":14719,"children":14720},{},[14721],{"type":55,"value":14722},"crawlers",{"type":55,"value":14724}," (e.g. by Google, Bing, or others) might massively call up pages\nor ",{"type":28,"tag":51,"props":14726,"children":14727},{},[14728],{"type":55,"value":14729},"spam bots",{"type":55,"value":14731}," cause atypical entries and calls. A constant barrage by a penetration testing tool or even a real\nattack simulation (DDoS) is only somewhat feasible, without possibly endangering the real systems or rendering them\nunusable for daily operations.",{"type":28,"tag":47,"props":14733,"children":14734},{},[14735,14737,14742,14744,14749],{"type":55,"value":14736},"The developer and DevOps community are consistent on this: it is ",{"type":28,"tag":51,"props":14738,"children":14739},{},[14740],{"type":55,"value":14741},"incredibly difficult to truly simulate the production\nload",{"type":55,"value":14743},". Even with test environments that resemble the prod environment, unforeseen effects can occur. An interesting\napproach is therefore almost counterintuitive: sometimes, purposefully ",{"type":28,"tag":51,"props":14745,"children":14746},{},[14747],{"type":55,"value":14748},"undersized test environments are used",{"type":55,"value":14750}," to\nuncover weaknesses. In the mentioned report, a small test database led to a growing log filling up the disk faster – a\nproblem that would have only been noticed much later in a larger environment.",{"type":28,"tag":47,"props":14752,"children":14753},{},[14754,14755,14760,14762,14767,14769,14774,14776,14784,14786,14792],{"type":55,"value":11042},{"type":28,"tag":51,"props":14756,"children":14757},{},[14758],{"type":55,"value":14759},"overriding opinion",{"type":55,"value":14761}," in the tech community, however, is that ",{"type":28,"tag":51,"props":14763,"children":14764},{},[14765],{"type":55,"value":14766},"nothing measures up to real production tests",{"type":55,"value":14768},".\nBig players like Netflix even propagate ",{"type":28,"tag":14416,"props":14770,"children":14771},{},[14772],{"type":55,"value":14773},"chaos engineering",{"type":55,"value":14775},", where disruptions are specifically generated in the running\nproduction to test the system robustness. An expert sums it up like this: “To test effectively, the system must be\nrunning in production. Because only ",{"type":28,"tag":14416,"props":14777,"children":14778},{},[14779],{"type":28,"tag":51,"props":14780,"children":14781},{},[14782],{"type":55,"value":14783},"in production",{"type":55,"value":14785}," can one work with factors such as state data, real inputs, and\nthe behavior of external systems“\n",{"type":28,"tag":520,"props":14787,"children":14789},{"href":14788},"https://www.techtarget.com/searchsoftwarequality/tip/9-techniques-for-fixing-bugs-in-production#:~:text=want%20it%20to%2C%20and%20code,and%20how%20external%20systems%20behave",[14790],{"type":55,"value":14791},"techtarget.com",{"type":55,"value":14793},"\n. This means, we will only see some errors once we go live. Then it's important to be able to react quickly –\nand this is exactly where DevOps comes in.",{"type":28,"tag":79,"props":14795,"children":14797},{"id":14796},"after-the-launch-is-before-the-launch-analysis-and-optimization-during-operation",[14798],{"type":55,"value":14799},"After the launch is before the launch: Analysis and optimization during operation",{"type":28,"tag":47,"props":14801,"children":14802},{},[14803,14807],{"type":28,"tag":51,"props":14804,"children":14805},{},[14806],{"type":55,"value":14565},{"type":55,"value":14808}," Further analysis and optimization after the launch is essential.",{"type":28,"tag":47,"props":14810,"children":14811},{},[14812,14814,14819,14821,14826,14828,14833,14839],{"type":55,"value":14813},"In the past, a software project was considered finished after the go-live - today we know that ",{"type":28,"tag":51,"props":14815,"children":14816},{},[14817],{"type":55,"value":14818},"Continuous Improvement",{"type":55,"value":14820},"\nis a critical part of successful software. It's precisely ",{"type":28,"tag":51,"props":14822,"children":14823},{},[14824],{"type":55,"value":14825},"after the launch",{"type":55,"value":14827}," that the phase begins in which real use\ndata is evaluated, bottlenecks are identified, and optimizations are made. As one expert article emphasizes: ",{"type":28,"tag":14416,"props":14829,"children":14830},{},[14831],{"type":55,"value":14832},"\"Even with\nrigorous pre-launch testing, actual users can uncover performance problems in practice that were not obvious during\ndevelopment. Post-launch monitoring helps identify these problems before they affect a large number of users.\"",{"type":28,"tag":520,"props":14834,"children":14836},{"href":14835},"https://www.topdevelopers.co/blog/post-launch-support-in-software-development/#:~:text=Even%20with%20rigorous%20pre,a%20large%20number%20of%20users",[14837],{"type":55,"value":14838},"topdevelopers.co",{"type":55,"value":14840},"\n. In other words: A launch without subsequent monitoring is like a maiden voyage without someone at the helm.\nIn practice, especially small and medium-sized companies often underestimate this effort.",{"type":28,"tag":47,"props":14842,"children":14843},{},[14844,14849,14851,14856,14858,14863,14865,14870,14872,14877,14879,14884],{"type":28,"tag":51,"props":14845,"children":14846},{},[14847],{"type":55,"value":14848},"Critical Perspective:",{"type":55,"value":14850}," Some people think good software would run “out of the box” - but based on our experience, this\nis extremely rarely the case. It takes time and iterative improvements to ",{"type":28,"tag":51,"props":14852,"children":14853},{},[14854],{"type":55,"value":14855},"stabilize and speed up",{"type":55,"value":14857}," a (web)\napplication. Studies show that ",{"type":28,"tag":14416,"props":14859,"children":14860},{},[14861],{"type":55,"value":14862},"continuous maintenance",{"type":55,"value":14864}," can significantly increase ",{"type":28,"tag":51,"props":14866,"children":14867},{},[14868],{"type":55,"value":14869},"user satisfaction and retention",{"type":55,"value":14871},".\nThis includes regular ",{"type":28,"tag":51,"props":14873,"children":14874},{},[14875],{"type":55,"value":14876},"bug fixes",{"type":55,"value":14878},", performance tuning (e.g., adjusting caching strategies, optimizing database\nindexes), and ",{"type":28,"tag":51,"props":14880,"children":14881},{},[14882],{"type":55,"value":14883},"security patches",{"type":55,"value":14885},". Security vulnerabilities that only emerge gradually must be immediately sealed off\nto prevent damage.",{"type":28,"tag":47,"props":14887,"children":14888},{},[14889,14891,14896,14898,14903,14905,14910],{"type":55,"value":14890},"Another aspect is the ",{"type":28,"tag":51,"props":14892,"children":14893},{},[14894],{"type":55,"value":14895},"feedback loop",{"type":55,"value":14897},": Through real user feedback, you learn which features are well-received and\nwhere usability problems exist, if any. Ideally, this feedback flows directly into the backlog of the development team.\nA culture of ",{"type":28,"tag":14416,"props":14899,"children":14900},{},[14901],{"type":55,"value":14902},"continuous deployment",{"type":55,"value":14904}," ensures that improvements reach customers promptly and are not postponed until the\nnext major “release”. Modern DevOps teams consider their software as a living product: ",{"type":28,"tag":14416,"props":14906,"children":14907},{},[14908],{"type":55,"value":14909},"\"Software does not end with the\nlaunch - it should be seen as a living product. Post-launch support enables continuous improvement based on user\nfeedback and performance data.\"",{"type":55,"value":794},{"type":28,"tag":47,"props":14912,"children":14913},{},[14914,14916],{"type":55,"value":14915},"Current practice in successful companies clearly shows: after the launch is before the launch. ",{"type":28,"tag":51,"props":14917,"children":14918},{},[14919],{"type":55,"value":14920},"Stagnation is dangerous",{"type":28,"tag":686,"props":14922,"children":14923},{},[14924],{"type":28,"tag":690,"props":14925,"children":14926},{},[14927,14929,14934],{"type":55,"value":14928},"anyone who does not invest in ",{"type":28,"tag":51,"props":14930,"children":14931},{},[14932],{"type":55,"value":14933},"monitoring, troubleshooting, and optimization",{"type":55,"value":14935}," after the go-live risks failures,\ndissatisfied users, and outdated software. For medium-sized companies, this specifically means allocating sufficient\nresources for the operational phase or having a competent partner who takes over the monitoring and maintenance.",{"type":28,"tag":79,"props":14937,"children":14939},{"id":14938},"monitoring-and-logging-observation-is-essential",[14940],{"type":55,"value":14941},"Monitoring and Logging: Observation is essential",{"type":28,"tag":47,"props":14943,"children":14944},{},[14945,14949],{"type":28,"tag":51,"props":14946,"children":14947},{},[14948],{"type":55,"value":14565},{"type":55,"value":14950}," Monitoring tools like Sentry or Grafana are essential for logging and error analysis.",{"type":28,"tag":47,"props":14952,"children":14953},{},[14954,14956,14961,14963,14970,14971,14978],{"type":55,"value":14955},"To quickly identify problems in operation, ",{"type":28,"tag":51,"props":14957,"children":14958},{},[14959],{"type":55,"value":14960},"monitoring and logging tools",{"type":55,"value":14962}," are absolutely crucial. Two prominent\nexamples are ",{"type":28,"tag":520,"props":14964,"children":14965},{"href":14504},[14966],{"type":28,"tag":51,"props":14967,"children":14968},{},[14969],{"type":55,"value":14510},{"type":55,"value":9548},{"type":28,"tag":520,"props":14972,"children":14973},{"href":14514},[14974],{"type":28,"tag":51,"props":14975,"children":14976},{},[14977],{"type":55,"value":14520},{"type":55,"value":14979}," (often in combination with\ntime-series databases like Prometheus or log databases like ElasticSearch/Loki).",{"type":28,"tag":686,"props":14981,"children":14982},{},[14983,15034],{"type":28,"tag":690,"props":14984,"children":14985},{},[14986,14993,14995,15000,15002,15007,15009,15018,15020,15025,15027,15032],{"type":28,"tag":520,"props":14987,"children":14988},{"href":14504},[14989],{"type":28,"tag":51,"props":14990,"children":14991},{},[14992],{"type":55,"value":14510},{"type":55,"value":14994}," is a specialized tool for ",{"type":28,"tag":51,"props":14996,"children":14997},{},[14998],{"type":55,"value":14999},"error tracking",{"type":55,"value":15001},". It captures errors and exceptions in\nthe application and collects them centrally. Why is this important? In production, a developer cannot just hang out\nwith the debugger on the code. Sentry closes this gap: It delivers detailed error reports (with stack trace, user\ninformation, context variables, etc.) as soon as any exception occurs in the code. In the dev community, Sentry is now\nconsidered an ",{"type":28,"tag":51,"props":15003,"children":15004},{},[15005],{"type":55,"value":15006},"industrial standard",{"type":55,"value":15008}," when it comes to crash reporting\n",{"type":28,"tag":520,"props":15010,"children":15012},{"href":15011},"https://medium.com/@AndrzejSala/efficient-error-tracking-with-sentry-e975c186947c#:~:text=Sentry%20is%20a%20crash,an%20industry%20standard%20by%20TechRadar",[15013,15015],{"type":55,"value":15014},"medium.com",{"type":28,"tag":1542,"props":15016,"children":15017},{},[],{"type":55,"value":15019},".\nEven less experienced developers find errors faster with Sentry because the tool eliminates much of the manual\ndetective work. Without a tool like Sentry, many errors in a complex web application would not be noticed until users\ncomplain. With Sentry, however, the team often finds out ",{"type":28,"tag":51,"props":15021,"children":15022},{},[15023],{"type":55,"value":15024},"immediately",{"type":55,"value":15026}," when an error happens – and can proactively\nrespond, ",{"type":28,"tag":51,"props":15028,"children":15029},{},[15030],{"type":55,"value":15031},"before",{"type":55,"value":15033}," all users are affected.",{"type":28,"tag":690,"props":15035,"children":15036},{},[15037,15044,15046,15051,15053,15058,15060,15065,15067,15072,15074,15079,15081,15086,15088,15093,15095,15100],{"type":28,"tag":520,"props":15038,"children":15039},{"href":14514},[15040],{"type":28,"tag":51,"props":15041,"children":15042},{},[15043],{"type":55,"value":14520},{"type":55,"value":15045},", on the other hand, addresses ",{"type":28,"tag":51,"props":15047,"children":15048},{},[15049],{"type":55,"value":15050},"performance monitoring and visualization",{"type":55,"value":15052}," of\nsystem metrics. Grafana\nitself is actually a dashboard tool that can integrate various data sources – from server CPU load\nto database performance to application-specific KPIs. In combination with e.g. ",{"type":28,"tag":51,"props":15054,"children":15055},{},[15056],{"type":55,"value":15057},"Prometheus",{"type":55,"value":15059}," (for\nmetric collection) or ",{"type":28,"tag":51,"props":15061,"children":15062},{},[15063],{"type":55,"value":15064},"Loki",{"type":55,"value":15066}," (for log collection), a powerful ",{"type":28,"tag":51,"props":15068,"children":15069},{},[15070],{"type":55,"value":15071},"monitoring cockpit",{"type":55,"value":15073}," is created. You want to be able\nto see ",{"type":28,"tag":14416,"props":15075,"children":15076},{},[15077],{"type":55,"value":15078},"at a glance",{"type":55,"value":15080}," whether all systems are green, where potential bottlenecks may be, or if unusual spikes occur.\nSpecifically, this means: Grafana & Co. help to recognize ",{"type":28,"tag":51,"props":15082,"children":15083},{},[15084],{"type":55,"value":15085},"trends",{"type":55,"value":15087}," (e.g., steadily increasing memory load), track\n",{"type":28,"tag":51,"props":15089,"children":15090},{},[15091],{"type":55,"value":15092},"anomalies",{"type":55,"value":15094}," (e.g., sudden traffic increase at midnight), and in the event of an error, quickly identify the ",{"type":28,"tag":51,"props":15096,"children":15097},{},[15098],{"type":55,"value":15099},"cause",{"type":55,"value":794},{"type":28,"tag":15102,"props":15103,"children":15104},"icons-dev-ops",{},[],{"type":28,"tag":47,"props":15106,"children":15107},{},[15108,15112,15114,15119,15121,15126,15128,15133,15135,15140,15142,15147],{"type":28,"tag":51,"props":15109,"children":15110},{},[15111],{"type":55,"value":14848},{"type":55,"value":15113}," Does every small web application need such an array of tools? Some smaller companies initially\ntry to get by without dedicated monitoring, relying on simple logs or manual checking. However, our personal experience\nshows: ",{"type":28,"tag":51,"props":15115,"children":15116},{},[15117],{"type":55,"value":15118},"As soon as the first major problem arises, it becomes clear that monitoring is not a \"nice-to-have\", but a real\nadded value",{"type":55,"value":15120},". Without these tools, you can easily be left in the dark for a long time, sifting through log files.\nHowever, it's crucial to properly channel and interpret the ",{"type":28,"tag":51,"props":15122,"children":15123},{},[15124],{"type":55,"value":15125},"flood of data",{"type":55,"value":15127},". Setting up monitoring correctly takes\ntime initially (and requires some expertise), but it pays off many times over with the first incident. Well-configured\nmonitoring also avoids ",{"type":28,"tag":14416,"props":15129,"children":15130},{},[15131],{"type":55,"value":15132},"alert fatigue",{"type":55,"value":15134}," – too many false alarms. Here, ",{"type":28,"tag":51,"props":15136,"children":15137},{},[15138],{"type":55,"value":15139},"quality over quantity",{"type":55,"value":15141}," is key. Better a few,\nbut meaningful metrics and alerts. We strongly advise all our customers: ",{"type":28,"tag":14416,"props":15143,"children":15144},{},[15145],{"type":55,"value":15146},"the investment in monitoring and logging tools\nis essential",{"type":55,"value":15148}," in order to remain capable of action in the event of an error!",{"type":28,"tag":79,"props":15150,"children":15152},{"id":15151},"automatic-alerts-zabbix-and-co-as-the-guardians-of-the-systems",[15153],{"type":55,"value":15154},"Automatic Alerts: Zabbix and Co. as the Guardians of the Systems",{"type":28,"tag":47,"props":15156,"children":15157},{},[15158,15162],{"type":28,"tag":51,"props":15159,"children":15160},{},[15161],{"type":55,"value":14565},{"type":55,"value":15163}," Monitoring tools like Zabbix are necessary for alerts during critical system conditions.",{"type":28,"tag":47,"props":15165,"children":15166},{},[15167,15169,15174,15176,15180,15181,15186,15187,15192,15194,15201,15203,15208,15209,15214],{"type":55,"value":15168},"In addition to just observing metrics, of course, we want to be ",{"type":28,"tag":51,"props":15170,"children":15171},{},[15172],{"type":55,"value":15173},"automatically alerted",{"type":55,"value":15175}," when something goes awry. This\nis where system monitoring tools like ",{"type":28,"tag":51,"props":15177,"children":15178},{},[15179],{"type":55,"value":314},{"type":55,"value":10047},{"type":28,"tag":51,"props":15182,"children":15183},{},[15184],{"type":55,"value":15185},"Nagios",{"type":55,"value":10047},{"type":28,"tag":51,"props":15188,"children":15189},{},[15190],{"type":55,"value":15191},"Icinga",{"type":55,"value":15193},", etc., come into play. Let's stick with\n",{"type":28,"tag":520,"props":15195,"children":15196},{"href":14525},[15197],{"type":28,"tag":51,"props":15198,"children":15199},{},[15200],{"type":55,"value":314},{"type":55,"value":15202}," as an example: Zabbix is an open-source monitoring system that offers predefined\n",{"type":28,"tag":51,"props":15204,"children":15205},{},[15206],{"type":55,"value":15207},"triggers",{"type":55,"value":9548},{"type":28,"tag":51,"props":15210,"children":15211},{},[15212],{"type":55,"value":15213},"notifications",{"type":55,"value":15215},". You can set thresholds - e.g., \"CPU load > 90% over 5 minutes\" or \"less than 10% free\ndisk space\" - and as soon as these are reached, Zabbix sends an alarm (via email, SMS, Slack, etc.).",{"type":28,"tag":47,"props":15217,"children":15218},{},[15219,15221,15225,15227,15232,15234,15238,15240,15245],{"type":55,"value":15220},"Why do we need this, didn't we just praise Grafana & Co.? The difference: ",{"type":28,"tag":51,"props":15222,"children":15223},{},[15224],{"type":55,"value":14520},{"type":55,"value":15226}," is great for visualization and\nanalysis, but ",{"type":28,"tag":51,"props":15228,"children":15229},{},[15230],{"type":55,"value":15231},"active alerting",{"type":55,"value":15233}," is often taken over by a dedicated tool like Zabbix (or Grafana is combined with an\nalert manager). ",{"type":28,"tag":51,"props":15235,"children":15236},{},[15237],{"type":55,"value":314},{"type":55,"value":15239}," and similar tools are essentially the ",{"type":28,"tag":51,"props":15241,"children":15242},{},[15243],{"type":55,"value":15244},"night watchmen",{"type":55,"value":15246}," who tirelessly monitor for defined\nconditions.",{"type":28,"tag":47,"props":15248,"children":15249},{},[15250,15252,15257,15263,15265,15269],{"type":55,"value":15251},"The importance of such alerts cannot be overstated. A fitting quote from a Linux Journal article: ",{"type":28,"tag":14416,"props":15253,"children":15254},{},[15255],{"type":55,"value":15256},"\"Alerts and triggers\nare the heartbeat of monitoring. Zabbix lets you define specific conditions, upon the occurrence of which notifications\nare sent over various channels, so that you are immediately informed about critical events that could impact system\nperformance\"",{"type":28,"tag":520,"props":15258,"children":15260},{"href":15259},"https://www.linuxjournal.com/content/how-monitor-your-system-zabbix#:~:text=Alerts%20and%20triggers%20are%20the,that%20could%20impact%20system%20performance",[15261],{"type":55,"value":15262},"linuxjournal.com",{"type":55,"value":15264},"\n. Without an alerting system, a problem can go unnoticed for hours - in the worst case, you hear about it first from the\nirritated customer on the phone. With properly configured alerts, however, the team ",{"type":28,"tag":51,"props":15266,"children":15267},{},[15268],{"type":55,"value":15024},{"type":55,"value":15270}," knows, for example,\nif the web server has failed or if the response times are critically high.",{"type":28,"tag":47,"props":15272,"children":15273},{},[15274,15279,15281,15286,15288,15293,15295,15300],{"type":28,"tag":51,"props":15275,"children":15276},{},[15277],{"type":55,"value":15278},"Practical View:",{"type":55,"value":15280}," For medium-sized companies that may not have a 24/7 operating team, good alerting is even more\nimportant. It allows small teams to work efficiently because they can rely on the warning messages, instead of\nconstantly manually checking everything. However, even here, a poorly configured system that is constantly crying \"wolf,\nwolf, ...\" (keyword ",{"type":28,"tag":14416,"props":15282,"children":15283},{},[15284],{"type":55,"value":15285},"false positives",{"type":55,"value":15287},"), will quickly be ignored. The trick is to define ",{"type":28,"tag":51,"props":15289,"children":15290},{},[15291],{"type":55,"value":15292},"meaningful threshold values",{"type":55,"value":15294},"\nand send ",{"type":28,"tag":51,"props":15296,"children":15297},{},[15298],{"type":55,"value":15299},"context-rich alerts",{"type":55,"value":15301}," (e.g., directly with an indication of which component is affected, attach logs, etc.).",{"type":28,"tag":47,"props":15303,"children":15304},{},[15305,15312,15314,15319],{"type":28,"tag":520,"props":15306,"children":15307},{"href":14525},[15308],{"type":28,"tag":51,"props":15309,"children":15310},{},[15311],{"type":55,"value":314},{"type":55,"value":15313}," has proven itself in many of our projects and is often referred to internally as\nan ",{"type":28,"tag":51,"props":15315,"children":15316},{},[15317],{"type":55,"value":15318},"indispensable tool",{"type":55,"value":794},{"type":28,"tag":79,"props":15321,"children":15323},{"id":15322},"cicd-pipelines-standardized-deployments-also-for-beginners",[15324],{"type":55,"value":15325},"CI/CD Pipelines: Standardized Deployments - Also for Beginners",{"type":28,"tag":47,"props":15327,"children":15328},{},[15329,15333],{"type":28,"tag":51,"props":15330,"children":15331},{},[15332],{"type":55,"value":14565},{"type":55,"value":15334}," CI/CD Pipelines enable standardized, safe deployments even for less experienced developers.",{"type":28,"tag":47,"props":15336,"children":15337},{},[15338,15340,15344,15346,15351,15352,15357,15359,15364],{"type":55,"value":15339},"The terms ",{"type":28,"tag":51,"props":15341,"children":15342},{},[15343],{"type":55,"value":5142},{"type":55,"value":15345}," stand for ",{"type":28,"tag":14416,"props":15347,"children":15348},{},[15349],{"type":55,"value":15350},"Continuous Integration",{"type":55,"value":9548},{"type":28,"tag":14416,"props":15353,"children":15354},{},[15355],{"type":55,"value":15356},"Continuous Delivery/Deployment",{"type":55,"value":15358},". A ",{"type":28,"tag":51,"props":15360,"children":15361},{},[15362],{"type":55,"value":15363},"CI/CD pipeline",{"type":55,"value":15365}," is an\nautomated process chain that builds, tests, and eventually deploys code from commit to rollout. Why is this so\nimportant - and how does it help less experienced developers?",{"type":28,"tag":47,"props":15367,"children":15368},{},[15369,15371,15376,15378,15383],{"type":55,"value":15370},"In traditional development workflows, the ",{"type":28,"tag":51,"props":15372,"children":15373},{},[15374],{"type":55,"value":15375},"deployment",{"type":55,"value":15377}," was often manual work carried out by experienced admins or\nDevOps engineers because many things could go wrong (missing dependencies, incorrect configs, avoiding downtime, etc.).\nHowever, with a well-configured CI/CD pipeline, deployment becomes a ",{"type":28,"tag":51,"props":15379,"children":15380},{},[15381],{"type":55,"value":15382},"standardized, repeatable operation",{"type":55,"value":15384}," - ideally at\nthe push of a button. Even if a developer has never manually set up a Linux server before, he can make his code live\nthrough the functionality of the pipeline because the pipeline takes over the necessary steps for him.",{"type":28,"tag":47,"props":15386,"children":15387},{},[15388,15393,15395,15400,15401,15406,15408,15412,15414,15419],{"type":28,"tag":51,"props":15389,"children":15390},{},[15391],{"type":55,"value":15392},"Safety and quality",{"type":55,"value":15394}," are not neglected - on the contrary. Particularly less experienced developers benefit from the\nfact that the pipeline carries out automated ",{"type":28,"tag":51,"props":15396,"children":15397},{},[15398],{"type":55,"value":15399},"tests",{"type":55,"value":9548},{"type":28,"tag":51,"props":15402,"children":15403},{},[15404],{"type":55,"value":15405},"code checks",{"type":55,"value":15407}," ",{"type":28,"tag":14416,"props":15409,"children":15410},{},[15411],{"type":55,"value":15031},{"type":55,"value":15413}," the deployment. This way, errors are\nintercepted before they're released to the user base. Additionally, the pipeline ensures that deployments always happen\nin ",{"type":28,"tag":51,"props":15415,"children":15416},{},[15417],{"type":55,"value":15418},"the same way",{"type":55,"value":15420}," - there are no deviations that occur due to human forgetfulness (e.g., \"Oops, loaded the staging\nconfig on Prod\" - such mistakes are eliminated). For SMEs, this means: faster updates with a simultaneously lower error\nrate.",{"type":28,"tag":47,"props":15422,"children":15423},{},[15424,15426,15431,15433,15438],{"type":55,"value":15425},"Of course, setting up a CI/CD pipeline initially requires ",{"type":28,"tag":51,"props":15427,"children":15428},{},[15429],{"type":55,"value":15430},"know-how and effort",{"type":55,"value":15432},". This is where a DevOps specialist\noften comes into play, who sets up such a pipeline (for example, with Jenkins, GitLab CI, GitHub Actions, or Bitbucket\nPipelines). ",{"type":28,"tag":51,"props":15434,"children":15435},{},[15436],{"type":55,"value":15437},"Upon critical examination",{"type":55,"value":15439},", some argue that in a perfect DevOps team, this distinction between developers\nand DevOps would be unnecessary because everyone would be responsible for the process. However, in reality, it is\nespecially beneficial for less experienced developers when a robust CI/CD system exists - it takes the fear of\ndeployment away from them (that applies to me as well as a project manager). A junior developer can click \"Deploy\" in\ngood conscience because they know, when automated tests have been run and the rollout is controlled, there's a minimum\namount of safety that the production system won't be impacted.",{"type":28,"tag":47,"props":15441,"children":15442},{},[15443,15445,15450,15452,15457,15459,15464],{"type":55,"value":15444},"It's important that CI/CD brings not only technical but also ",{"type":28,"tag":51,"props":15446,"children":15447},{},[15448],{"type":55,"value":15449},"cultural changes",{"type":55,"value":15451},". Deployments become smaller but more\nfrequent. This reduces risk and the impact of errors. Teams get used to deployments being ",{"type":28,"tag":14416,"props":15453,"children":15454},{},[15455],{"type":55,"value":15456},"routine",{"type":55,"value":15458}," and not \"major\noperation days\". Especially in ",{"type":28,"tag":51,"props":15460,"children":15461},{},[15462],{"type":55,"value":15463},"Agile Development",{"type":55,"value":15465},", CI/CD is virtually the backbone to enable fast iterations.",{"type":28,"tag":47,"props":15467,"children":15468},{},[15469,15471,15476],{"type":55,"value":15470},"In summary: CI/CD pipelines are a game-changer that enables even less experienced developers to deliver ",{"type":28,"tag":51,"props":15472,"children":15473},{},[15474],{"type":55,"value":15475},"at the push of\na button",{"type":55,"value":15477}," – reliably and repeatably.",{"type":28,"tag":79,"props":15479,"children":15481},{"id":15480},"experience-counts-live-data-specific-errors-and-the-role-of-devops-experts",[15482],{"type":55,"value":15483},"Experience Counts: Live Data, Specific Errors, and the Role of DevOps Experts",{"type":28,"tag":47,"props":15485,"children":15486},{},[15487,15491],{"type":28,"tag":51,"props":15488,"children":15489},{},[15490],{"type":55,"value":14565},{"type":55,"value":15492}," Certain errors and performance problems only manifest with live data and require experienced DevOps\nspecialists.",{"type":28,"tag":47,"props":15494,"children":15495},{},[15496,15498,15503,15505,15510,15512,15517],{"type":55,"value":15497},"Despite all automation and testing, the ",{"type":28,"tag":51,"props":15499,"children":15500},{},[15501],{"type":55,"value":15502},"experience",{"type":55,"value":15504}," in dealing with production systems is irreplaceable. There are\nerror patterns that only occur with real ",{"type":28,"tag":51,"props":15506,"children":15507},{},[15508],{"type":55,"value":15509},"live data and loads",{"type":55,"value":15511}," - due to complex data constellations or simply scaling\neffects. A query that is lightning-fast with 100 test data sets can suddenly become a bottleneck with 100 million real\ndata sets. Or a ",{"type":28,"tag":51,"props":15513,"children":15514},{},[15515],{"type":55,"value":15516},"memory leak",{"type":55,"value":15518}," in a certain library only becomes apparent after weeks of continuous operation when the\nprocess increasingly occupies memory. Identifying and fixing such problems often requires an experienced eye.",{"type":28,"tag":47,"props":15520,"children":15521},{},[15522,15524,15529,15531,15537,15538,15544,15546,15552,15554,15559,15561,15566,15568,15573],{"type":55,"value":15523},"A DevOps engineer with a lot of operational experience usually has a repertoire of ",{"type":28,"tag":51,"props":15525,"children":15526},{},[15527],{"type":55,"value":15528},"diagnostic techniques",{"type":55,"value":15530},". For\nexample, experienced people know how to debug on Linux with tools like ",{"type":28,"tag":548,"props":15532,"children":15534},{"className":15533},[],[15535],{"type":55,"value":15536},"htop",{"type":55,"value":10047},{"type":28,"tag":548,"props":15539,"children":15541},{"className":15540},[],[15542],{"type":55,"value":15543},"iotop",{"type":55,"value":15545},", or ",{"type":28,"tag":548,"props":15547,"children":15549},{"className":15548},[],[15550],{"type":55,"value":15551},"strace",{"type":55,"value":15553},", which less routine\ndevelopers may never have needed. Experienced DevOps also know ",{"type":28,"tag":51,"props":15555,"children":15556},{},[15557],{"type":55,"value":15558},"duration load phenomena",{"type":55,"value":15560}," (keywords: ",{"type":28,"tag":14416,"props":15562,"children":15563},{},[15564],{"type":55,"value":15565},"floating-point\nprecision bugs",{"type":55,"value":15567},", memory-induced rounding errors, etc.) from practice. A drastic but real scenario: A memory error occurs\n",{"type":28,"tag":14416,"props":15569,"children":15570},{},[15571],{"type":55,"value":15572},"only",{"type":55,"value":15574}," under proper full load and only in combination with certain hardware conditions - here you need experts who may\nhave seen something similar before or know where to start.",{"type":28,"tag":79,"props":15576,"children":15578},{"id":15577},"conclusion",[15579],{"type":55,"value":15580},"Conclusion",{"type":28,"tag":47,"props":15582,"children":15583},{},[15584,15586,15591,15593,15598,15600,15607],{"type":55,"value":15585},"For (web) applications in productive use, ",{"type":28,"tag":51,"props":15587,"children":15588},{},[15589],{"type":55,"value":15590},"DevOps is not a luxury, but a necessity",{"type":55,"value":15592},". Development environments hit\ntheir limits, real users produce surprises, and without continuous monitoring, you're flying blind. Small and\nmedium-sized companies, which perhaps don't have huge IT departments, can benefit enormously from a DevOps approach.\nMore stable systems, quicker response times to problems, and more satisfied customers. However, you must be willing to\ninvest ",{"type":28,"tag":51,"props":15594,"children":15595},{},[15596],{"type":55,"value":15597},"time and resources",{"type":55,"value":15599}," even after the launch to analyze data and implement improvements. Tools like\n",{"type":28,"tag":520,"props":15601,"children":15602},{"href":14504},[15603],{"type":28,"tag":51,"props":15604,"children":15605},{},[15606],{"type":55,"value":14510},{"type":55,"value":15608},", Grafana, and Zabbix form the backbone of monitoring - they deliver the necessary data and\nsupporting mechanisms. Automation through CI/CD significantly reduces the risk of deployments and allows even less\nexperienced team members to safely implement changes live.",{"type":28,"tag":47,"props":15610,"children":15611},{},[15612,15614,15619],{"type":55,"value":15613},"In the end, it shows: ",{"type":28,"tag":51,"props":15615,"children":15616},{},[15617],{"type":55,"value":15618},"People",{"type":55,"value":15620}," make the difference. Experienced DevOps specialists can solve tricky live problems and\nbuild a bridge between developers and operations.",{"type":28,"tag":47,"props":15622,"children":15623},{},[15624,15629],{"type":28,"tag":51,"props":15625,"children":15626},{},[15627],{"type":55,"value":15628},"Note:",{"type":55,"value":15630}," This article was also generated with the support of AI (model: GPT-4).",{"title":7,"searchDepth":271,"depth":271,"links":15632},[15633,15634,15635,15636,15637,15638,15639,15640],{"id":14427,"depth":271,"text":14430},{"id":14554,"depth":271,"text":14557},{"id":14796,"depth":271,"text":14799},{"id":14938,"depth":271,"text":14941},{"id":15151,"depth":271,"text":15154},{"id":15322,"depth":271,"text":15325},{"id":15480,"depth":271,"text":15483},{"id":15577,"depth":271,"text":15580},{"_path":487,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":488,"description":489,"author":159,"image":490,"releaseDate":491,"blogCategories":15642,"articleTags":15643,"tags":15644,"body":15645,"_type":275,"_id":496,"_source":277,"_file":497,"_stem":498,"_extension":280},[398,399],[494],[23],{"type":25,"children":15646,"toc":16194},[15647,15653,15658,15663,15678,15691,15697,15724,15741,15747,15752,15765,15778,15809,15844,15865,15919,15936,15962,16005,16034,16084,16103,16116,16158,16170,16190],{"type":28,"tag":79,"props":15648,"children":15650},{"id":15649},"how-to-resolve-selected-domains-over-vpn-on-linux",[15651],{"type":55,"value":15652},"How to resolve selected domains over VPN on Linux",{"type":28,"tag":47,"props":15654,"children":15655},{},[15656],{"type":55,"value":15657},"In today's world, more people than ever use VPN services to work from remote. However, in some cases it's not desirable\nto route all traffic and all domain name resolutions over the VPN connection. Even if the VPN-Server wants the client to\nconfigure itself to work like this, the client can be configured to ignore the request to route all traffic over the VPN\nconnection.",{"type":28,"tag":47,"props":15659,"children":15660},{},[15661],{"type":55,"value":15662},"For example, with Openvpn the option",{"type":28,"tag":534,"props":15664,"children":15667},{"className":15665,"code":15666,"language":15,"meta":7,"style":7},"language-apache shiki shiki-themes github-dark github-dark monokai","pull-filter ignore redirect-gateway\n",[15668],{"type":28,"tag":548,"props":15669,"children":15670},{"__ignoreMap":7},[15671],{"type":28,"tag":116,"props":15672,"children":15673},{"class":553,"line":554},[15674],{"type":28,"tag":116,"props":15675,"children":15676},{"style":564},[15677],{"type":55,"value":15666},{"type":28,"tag":47,"props":15679,"children":15680},{},[15681,15683,15689],{"type":55,"value":15682},"can be used to tell the ",{"type":28,"tag":548,"props":15684,"children":15686},{"className":15685},[],[15687],{"type":55,"value":15688},"openvpn-client",{"type":55,"value":15690}," to ignore all \"route all\" requests from the server.",{"type":28,"tag":79,"props":15692,"children":15694},{"id":15693},"fritzbox-example",[15695],{"type":55,"value":15696},"FRITZ!Box example",{"type":28,"tag":47,"props":15698,"children":15699},{},[15700,15702,15707,15709,15715,15717,15723],{"type":55,"value":15701},"Recently I had to use a VPN-Connection to a ",{"type":28,"tag":51,"props":15703,"children":15704},{},[15705],{"type":55,"value":15706},"FRITZ!Box",{"type":55,"value":15708},". It's a very popular router in Germany that not only offers\neasy\nVPN-Connections but also adds all hosts on its network to its own dns. If you want to talk to a machine with the name ",{"type":28,"tag":548,"props":15710,"children":15712},{"className":15711},[],[15713],{"type":55,"value":15714}," workstation",{"type":55,"value":15716}," you can reach it using the \"workstation.fritz.box\" dns name. The fritz-box itself is also available on the\ndns name ",{"type":28,"tag":548,"props":15718,"children":15720},{"className":15719},[],[15721],{"type":55,"value":15722},"fritz.box",{"type":55,"value":794},{"type":28,"tag":47,"props":15725,"children":15726},{},[15727,15729,15734,15736,15740],{"type":55,"value":15728},"In my case, I prefer to use my own DNS server for all queries because of speed and privacy reasons - that means, I only\nwant the\ndomains with the ",{"type":28,"tag":548,"props":15730,"children":15732},{"className":15731},[],[15733],{"type":55,"value":15722},{"type":55,"value":15735}," suffix to resolve over the ",{"type":28,"tag":51,"props":15737,"children":15738},{},[15739],{"type":55,"value":15706},{"type":55,"value":794},{"type":28,"tag":79,"props":15742,"children":15744},{"id":15743},"solution-using-a-local-dns-server-dnsmasq",[15745],{"type":55,"value":15746},"Solution using a local DNS server - dnsmasq",{"type":28,"tag":47,"props":15748,"children":15749},{},[15750],{"type":55,"value":15751},"Dnsmasq is a lightweight DNS-Server that you can run on your machine to get control on how the name resolution works. A\nnice side effect is that it has its own dns cache, making recurring dns queries faster. Here is how I have set it up:",{"type":28,"tag":47,"props":15753,"children":15754},{},[15755,15757,15763],{"type":55,"value":15756},"Before you start you need to find out which DNS server is used on the VPN. It's usually the default gateway that usually\nhas a ",{"type":28,"tag":548,"props":15758,"children":15760},{"className":15759},[],[15761],{"type":55,"value":15762},".1",{"type":55,"value":15764}," at the end. You can watch the VPN logs closely to learn which DNS server gets pushed on connect.",{"type":28,"tag":47,"props":15766,"children":15767},{},[15768,15770,15776],{"type":55,"value":15769},"There is a tool called ",{"type":28,"tag":548,"props":15771,"children":15773},{"className":15772},[],[15774],{"type":55,"value":15775},"dig",{"type":55,"value":15777}," which can do dns queries over specified dns servers, for example",{"type":28,"tag":534,"props":15779,"children":15783},{"className":15780,"code":15781,"language":15782,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark github-dark monokai","dig @192.168.1.1 a fritz.box\n","bash",[15784],{"type":28,"tag":548,"props":15785,"children":15786},{"__ignoreMap":7},[15787],{"type":28,"tag":116,"props":15788,"children":15789},{"class":553,"line":554},[15790,15794,15799,15804],{"type":28,"tag":116,"props":15791,"children":15792},{"style":2900},[15793],{"type":55,"value":15775},{"type":28,"tag":116,"props":15795,"children":15796},{"style":596},[15797],{"type":55,"value":15798}," @192.168.1.1",{"type":28,"tag":116,"props":15800,"children":15801},{"style":596},[15802],{"type":55,"value":15803}," a",{"type":28,"tag":116,"props":15805,"children":15806},{"style":596},[15807],{"type":55,"value":15808}," fritz.box\n",{"type":28,"tag":47,"props":15810,"children":15811},{},[15812,15814,15820,15822,15827,15829,15835,15837,15843],{"type":55,"value":15813},"will ask the dns server ",{"type":28,"tag":548,"props":15815,"children":15817},{"className":15816},[],[15818],{"type":55,"value":15819},"192.168.1.1",{"type":55,"value":15821}," for the ip of ",{"type":28,"tag":548,"props":15823,"children":15825},{"className":15824},[],[15826],{"type":55,"value":15722},{"type":55,"value":15828},". ",{"type":28,"tag":548,"props":15830,"children":15832},{"className":15831},[],[15833],{"type":55,"value":15834},"Dig",{"type":55,"value":15836}," is very handy when debugging dns problems and to\ntest\nyour setup. You may have to install it on your System. On debian, it lives in a package called ",{"type":28,"tag":548,"props":15838,"children":15840},{"className":15839},[],[15841],{"type":55,"value":15842},"dnsutils",{"type":55,"value":794},{"type":28,"tag":47,"props":15845,"children":15846},{},[15847,15849,15855,15857,15863],{"type":55,"value":15848},"First install ",{"type":28,"tag":548,"props":15850,"children":15852},{"className":15851},[],[15853],{"type":55,"value":15854},"dnsmasq",{"type":55,"value":15856}," on your Linux and edit its configuration (usually lives in ",{"type":28,"tag":548,"props":15858,"children":15860},{"className":15859},[],[15861],{"type":55,"value":15862},"/etc/dnsmasq.conf",{"type":55,"value":15864},"). Add these lines\nhere:",{"type":28,"tag":534,"props":15866,"children":15868},{"className":15665,"code":15867,"language":15,"meta":7,"style":7},"resolv-file=/etc/resolv.dnsmasq.conf\nserver=/fritz.box/192.168.1.1\n",[15869],{"type":28,"tag":548,"props":15870,"children":15871},{"__ignoreMap":7},[15872,15880],{"type":28,"tag":116,"props":15873,"children":15874},{"class":553,"line":554},[15875],{"type":28,"tag":116,"props":15876,"children":15877},{"style":564},[15878],{"type":55,"value":15879},"resolv-file=/etc/resolv.dnsmasq.conf\n",{"type":28,"tag":116,"props":15881,"children":15882},{"class":553,"line":271},[15883,15888,15893,15897,15902,15906,15910,15914],{"type":28,"tag":116,"props":15884,"children":15885},{"style":564},[15886],{"type":55,"value":15887},"server=/fritz.box/",{"type":28,"tag":116,"props":15889,"children":15890},{"style":2170},[15891],{"type":55,"value":15892},"192",{"type":28,"tag":116,"props":15894,"children":15895},{"style":564},[15896],{"type":55,"value":794},{"type":28,"tag":116,"props":15898,"children":15899},{"style":2170},[15900],{"type":55,"value":15901},"168",{"type":28,"tag":116,"props":15903,"children":15904},{"style":564},[15905],{"type":55,"value":794},{"type":28,"tag":116,"props":15907,"children":15908},{"style":2170},[15909],{"type":55,"value":380},{"type":28,"tag":116,"props":15911,"children":15912},{"style":564},[15913],{"type":55,"value":794},{"type":28,"tag":116,"props":15915,"children":15916},{"style":2170},[15917],{"type":55,"value":15918},"1\n",{"type":28,"tag":47,"props":15920,"children":15921},{},[15922,15927,15929,15934],{"type":28,"tag":548,"props":15923,"children":15925},{"className":15924},[],[15926],{"type":55,"value":15722},{"type":55,"value":15928}," is the domain you want to resolve over the VPN-Dns-server, ",{"type":28,"tag":548,"props":15930,"children":15932},{"className":15931},[],[15933],{"type":55,"value":15819},{"type":55,"value":15935}," in this example.",{"type":28,"tag":47,"props":15937,"children":15938},{},[15939,15940,15945,15947,15952,15954,15960],{"type":55,"value":11042},{"type":28,"tag":51,"props":15941,"children":15942},{},[15943],{"type":55,"value":15944},"Resolv-File",{"type":55,"value":15946}," will tell ",{"type":28,"tag":548,"props":15948,"children":15950},{"className":15949},[],[15951],{"type":55,"value":15854},{"type":55,"value":15953}," how it should resolve its dns queries in case there are no other rules, so let's\ncreate\na ",{"type":28,"tag":548,"props":15955,"children":15957},{"className":15956},[],[15958],{"type":55,"value":15959},"/etc/resolv.dnsmasq.conf",{"type":55,"value":15961},"\nwith content",{"type":28,"tag":534,"props":15963,"children":15965},{"className":15665,"code":15964,"language":15,"meta":7,"style":7},"nameserver 1.1.1.1\n",[15966],{"type":28,"tag":548,"props":15967,"children":15968},{"__ignoreMap":7},[15969],{"type":28,"tag":116,"props":15970,"children":15971},{"class":553,"line":554},[15972,15977,15981,15985,15989,15993,15997,16001],{"type":28,"tag":116,"props":15973,"children":15974},{"style":564},[15975],{"type":55,"value":15976},"nameserver ",{"type":28,"tag":116,"props":15978,"children":15979},{"style":2170},[15980],{"type":55,"value":380},{"type":28,"tag":116,"props":15982,"children":15983},{"style":564},[15984],{"type":55,"value":794},{"type":28,"tag":116,"props":15986,"children":15987},{"style":2170},[15988],{"type":55,"value":380},{"type":28,"tag":116,"props":15990,"children":15991},{"style":564},[15992],{"type":55,"value":794},{"type":28,"tag":116,"props":15994,"children":15995},{"style":2170},[15996],{"type":55,"value":380},{"type":28,"tag":116,"props":15998,"children":15999},{"style":564},[16000],{"type":55,"value":794},{"type":28,"tag":116,"props":16002,"children":16003},{"style":2170},[16004],{"type":55,"value":15918},{"type":28,"tag":47,"props":16006,"children":16007},{},[16008,16010,16016,16018,16024,16026,16032],{"type":55,"value":16009},"If you use a static network configuration, you now can just edit it to use ",{"type":28,"tag":548,"props":16011,"children":16013},{"className":16012},[],[16014],{"type":55,"value":16015},"127.0.0.1",{"type":55,"value":16017}," as its nameserver. If you use\nautomatic ip configuration using dhcp, you need to configure your dhcp client use the new local dns server. On debian,\nthe default is ",{"type":28,"tag":548,"props":16019,"children":16021},{"className":16020},[],[16022],{"type":55,"value":16023},"dhclient",{"type":55,"value":16025},". In that case edit ",{"type":28,"tag":548,"props":16027,"children":16029},{"className":16028},[],[16030],{"type":55,"value":16031},"/etc/dhcp/dhclient.conf",{"type":55,"value":16033}," and add:",{"type":28,"tag":534,"props":16035,"children":16037},{"className":15665,"code":16036,"language":15,"meta":7,"style":7},"prepend domain-name-servers 127.0.0.1;\n",[16038],{"type":28,"tag":548,"props":16039,"children":16040},{"__ignoreMap":7},[16041],{"type":28,"tag":116,"props":16042,"children":16043},{"class":553,"line":554},[16044,16049,16054,16058,16063,16067,16071,16075,16079],{"type":28,"tag":116,"props":16045,"children":16046},{"style":564},[16047],{"type":55,"value":16048},"prepend domain-name-servers ",{"type":28,"tag":116,"props":16050,"children":16051},{"style":2170},[16052],{"type":55,"value":16053},"127",{"type":28,"tag":116,"props":16055,"children":16056},{"style":564},[16057],{"type":55,"value":794},{"type":28,"tag":116,"props":16059,"children":16060},{"style":2170},[16061],{"type":55,"value":16062},"0",{"type":28,"tag":116,"props":16064,"children":16065},{"style":564},[16066],{"type":55,"value":794},{"type":28,"tag":116,"props":16068,"children":16069},{"style":2170},[16070],{"type":55,"value":16062},{"type":28,"tag":116,"props":16072,"children":16073},{"style":564},[16074],{"type":55,"value":794},{"type":28,"tag":116,"props":16076,"children":16077},{"style":2170},[16078],{"type":55,"value":380},{"type":28,"tag":116,"props":16080,"children":16081},{"style":564},[16082],{"type":55,"value":16083},";\n",{"type":28,"tag":47,"props":16085,"children":16086},{},[16087,16089,16094,16096,16101],{"type":55,"value":16088},"That's it. All you have to do now is to restart ",{"type":28,"tag":548,"props":16090,"children":16092},{"className":16091},[],[16093],{"type":55,"value":15854},{"type":55,"value":16095}," so it reloads its config and reconnect/restart ",{"type":28,"tag":548,"props":16097,"children":16099},{"className":16098},[],[16100],{"type":55,"value":16023},{"type":55,"value":16102},"\n(disconnecting and reconnecting the network may work, reboot the machine when in doubt).",{"type":28,"tag":47,"props":16104,"children":16105},{},[16106,16108,16114],{"type":55,"value":16107},"Now you can check if the file ",{"type":28,"tag":548,"props":16109,"children":16111},{"className":16110},[],[16112],{"type":55,"value":16113},"/etc/resolv.conf",{"type":55,"value":16115}," has",{"type":28,"tag":534,"props":16117,"children":16119},{"className":15665,"code":16118,"language":15,"meta":7,"style":7},"nameserver 127.0.0.1\n",[16120],{"type":28,"tag":548,"props":16121,"children":16122},{"__ignoreMap":7},[16123],{"type":28,"tag":116,"props":16124,"children":16125},{"class":553,"line":554},[16126,16130,16134,16138,16142,16146,16150,16154],{"type":28,"tag":116,"props":16127,"children":16128},{"style":564},[16129],{"type":55,"value":15976},{"type":28,"tag":116,"props":16131,"children":16132},{"style":2170},[16133],{"type":55,"value":16053},{"type":28,"tag":116,"props":16135,"children":16136},{"style":564},[16137],{"type":55,"value":794},{"type":28,"tag":116,"props":16139,"children":16140},{"style":2170},[16141],{"type":55,"value":16062},{"type":28,"tag":116,"props":16143,"children":16144},{"style":564},[16145],{"type":55,"value":794},{"type":28,"tag":116,"props":16147,"children":16148},{"style":2170},[16149],{"type":55,"value":16062},{"type":28,"tag":116,"props":16151,"children":16152},{"style":564},[16153],{"type":55,"value":794},{"type":28,"tag":116,"props":16155,"children":16156},{"style":2170},[16157],{"type":55,"value":15918},{"type":28,"tag":47,"props":16159,"children":16160},{},[16161,16163,16168],{"type":55,"value":16162},"as first nameserver. If it has, the selected domain (",{"type":28,"tag":548,"props":16164,"children":16166},{"className":16165},[],[16167],{"type":55,"value":15722},{"type":55,"value":16169}," in my example) should now resolve.",{"type":28,"tag":47,"props":16171,"children":16172},{},[16173,16175,16180,16182,16188],{"type":55,"value":16174},"On ",{"type":28,"tag":548,"props":16176,"children":16178},{"className":16177},[],[16179],{"type":55,"value":15854},{"type":55,"value":16181},", you can add multiple ",{"type":28,"tag":548,"props":16183,"children":16185},{"className":16184},[],[16186],{"type":55,"value":16187},"server=",{"type":55,"value":16189}," lines, which comes in handy if you have multiple domains that need to be\nresolved over different DNS servers.",{"type":28,"tag":1705,"props":16191,"children":16192},{},[16193],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":16195},[16196,16197,16198],{"id":15649,"depth":271,"text":15652},{"id":15693,"depth":271,"text":15696},{"id":15743,"depth":271,"text":15746},{"_path":500,"_dir":391,"_draft":6,"_partial":6,"_locale":7,"title":501,"description":502,"author":159,"image":503,"releaseDate":504,"blogCategories":16200,"tags":16201,"body":16202,"_type":275,"_id":507,"_source":277,"_file":508,"_stem":509,"_extension":280},[398,467],[23],{"type":25,"children":16203,"toc":16659},[16204,16210,16222,16228,16233,16239,16244,16282,16288,16293,16299,16311,16429,16447,16453,16609,16614,16620,16649,16655],{"type":28,"tag":79,"props":16205,"children":16207},{"id":16206},"what-is-btrfs-fragmentation",[16208],{"type":55,"value":16209},"What is BTRFS fragmentation?",{"type":28,"tag":47,"props":16211,"children":16212},{},[16213,16215,16220],{"type":55,"value":16214},"Most of the best BTRFS features are powered by the ",{"type":28,"tag":14416,"props":16216,"children":16217},{},[16218],{"type":55,"value":16219},"copy-on-write technology",{"type":55,"value":16221},". If a application wants to rewrite a part of a file, like the first megabyte, the data is not written in-place but in an so-called extend. This enables BTRFS to keep multiple versions of partially rewritten files with only claiming disk space assigned to the changes and not multiple full copies of a file. The old data can be discarded at some point (i.e. if its not used by any snapshots anymore) and the extend will serve the files current version.",{"type":28,"tag":79,"props":16223,"children":16225},{"id":16224},"btrfs-fragmentation-can-hurt-the-performance-of-your-system",[16226],{"type":55,"value":16227},"BTRFS fragmentation can hurt the performance of your System",{"type":28,"tag":47,"props":16229,"children":16230},{},[16231],{"type":55,"value":16232},"You can guess, reading a file with 100k+ extends and adding more extends requires a lot of bookkeeping and storage seeks from your system. That 10GB file there is internally shattered into 100k parts that need to be collected if you want to read the whole file. This clearly adds complexity - and decreases performance.",{"type":28,"tag":79,"props":16234,"children":16236},{"id":16235},"btrfs-fragmentation-can-block-huge-amounts-of-disk-space",[16237],{"type":55,"value":16238},"BTRFS fragmentation can block huge amounts of disk space",{"type":28,"tag":47,"props":16240,"children":16241},{},[16242],{"type":55,"value":16243},"Yes, BTRFS has to store the locations of these 100k extends somewhere, easily adding some extra GB of used disk space to your system. The bad thing is that BTRFS does not tell you that",{"type":28,"tag":47,"props":16245,"children":16246},{},[16247,16249,16254,16255,16260,16261,16266,16268,16273,16275,16280],{"type":55,"value":16248},"If you see your btrfs filesystem using ",{"type":28,"tag":51,"props":16250,"children":16251},{},[16252],{"type":55,"value":16253},"80GB",{"type":55,"value":3144},{"type":28,"tag":14416,"props":16256,"children":16257},{},[16258],{"type":55,"value":16259},"df",{"type":55,"value":9548},{"type":28,"tag":14416,"props":16262,"children":16263},{},[16264],{"type":55,"value":16265},"btrfs fi show",{"type":55,"value":16267}," while ",{"type":28,"tag":14416,"props":16269,"children":16270},{},[16271],{"type":55,"value":16272},"du -hsx",{"type":55,"value":16274}," only shows ",{"type":28,"tag":51,"props":16276,"children":16277},{},[16278],{"type":55,"value":16279},"54GB",{"type":55,"value":16281}," there are only two reasons i am aware of to cause this: either you have snapshots that keep old extends - or you have massive fragmentation.",{"type":28,"tag":79,"props":16283,"children":16285},{"id":16284},"btrfs-filesystem-defrag",[16286],{"type":55,"value":16287},"BTRFS filesystem defrag",{"type":28,"tag":47,"props":16289,"children":16290},{},[16291],{"type":55,"value":16292},"It is possible to use BTRFS filesystem defrag on your whole file system, but that causes all you snapshots to duplicate the data. it also causes a lot of IO so this is nothing you want to do on your production server without a reason. There is really no point in defrag'ing static files that are almost never changed.",{"type":28,"tag":79,"props":16294,"children":16296},{"id":16295},"find-the-most-fragmented-files-on-your-system",[16297],{"type":55,"value":16298},"Find the most fragmented files on your System",{"type":28,"tag":47,"props":16300,"children":16301},{},[16302,16304,16309],{"type":55,"value":16303},"There is a linux-tool called ",{"type":28,"tag":14416,"props":16305,"children":16306},{},[16307],{"type":55,"value":16308},"filefrag",{"type":55,"value":16310}," which reports how many fragments a file consists of. So i thought ... „why not try to find the most fragmented files and fix just these?“ here you go:",{"type":28,"tag":534,"props":16312,"children":16314},{"className":15780,"code":16313,"language":15782,"meta":7,"style":7},"find / -xdev -type f| xargs filefrag 2>/dev/null | sed 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/' | awk -F ' ' '$1 > 500' | sort -n -r\n",[16315],{"type":28,"tag":548,"props":16316,"children":16317},{"__ignoreMap":7},[16318],{"type":28,"tag":116,"props":16319,"children":16320},{"class":553,"line":554},[16321,16326,16331,16336,16341,16346,16351,16356,16361,16366,16371,16376,16381,16386,16390,16395,16400,16405,16410,16414,16419,16424],{"type":28,"tag":116,"props":16322,"children":16323},{"style":2900},[16324],{"type":55,"value":16325},"find",{"type":28,"tag":116,"props":16327,"children":16328},{"style":596},[16329],{"type":55,"value":16330}," /",{"type":28,"tag":116,"props":16332,"children":16333},{"style":2170},[16334],{"type":55,"value":16335}," -xdev",{"type":28,"tag":116,"props":16337,"children":16338},{"style":2170},[16339],{"type":55,"value":16340}," -type",{"type":28,"tag":116,"props":16342,"children":16343},{"style":596},[16344],{"type":55,"value":16345}," f",{"type":28,"tag":116,"props":16347,"children":16348},{"style":4807},[16349],{"type":55,"value":16350},"|",{"type":28,"tag":116,"props":16352,"children":16353},{"style":2900},[16354],{"type":55,"value":16355}," xargs",{"type":28,"tag":116,"props":16357,"children":16358},{"style":596},[16359],{"type":55,"value":16360}," filefrag",{"type":28,"tag":116,"props":16362,"children":16363},{"style":4807},[16364],{"type":55,"value":16365}," 2>",{"type":28,"tag":116,"props":16367,"children":16368},{"style":596},[16369],{"type":55,"value":16370},"/dev/null",{"type":28,"tag":116,"props":16372,"children":16373},{"style":4807},[16374],{"type":55,"value":16375}," |",{"type":28,"tag":116,"props":16377,"children":16378},{"style":2900},[16379],{"type":55,"value":16380}," sed",{"type":28,"tag":116,"props":16382,"children":16383},{"style":596},[16384],{"type":55,"value":16385}," 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/'",{"type":28,"tag":116,"props":16387,"children":16388},{"style":4807},[16389],{"type":55,"value":16375},{"type":28,"tag":116,"props":16391,"children":16392},{"style":2900},[16393],{"type":55,"value":16394}," awk",{"type":28,"tag":116,"props":16396,"children":16397},{"style":2170},[16398],{"type":55,"value":16399}," -F",{"type":28,"tag":116,"props":16401,"children":16402},{"style":596},[16403],{"type":55,"value":16404}," ' '",{"type":28,"tag":116,"props":16406,"children":16407},{"style":596},[16408],{"type":55,"value":16409}," '$1 > 500'",{"type":28,"tag":116,"props":16411,"children":16412},{"style":4807},[16413],{"type":55,"value":16375},{"type":28,"tag":116,"props":16415,"children":16416},{"style":2900},[16417],{"type":55,"value":16418}," sort",{"type":28,"tag":116,"props":16420,"children":16421},{"style":2170},[16422],{"type":55,"value":16423}," -n",{"type":28,"tag":116,"props":16425,"children":16426},{"style":2170},[16427],{"type":55,"value":16428}," -r\n",{"type":28,"tag":47,"props":16430,"children":16431},{},[16432,16434,16439,16441,16445],{"type":55,"value":16433},"You should review this list. If there is something with 10k+ extends, it is a candidate to be flagged as ",{"type":28,"tag":14416,"props":16435,"children":16436},{},[16437],{"type":55,"value":16438},"nodatacow",{"type":55,"value":16440},". In my case, I have discovered that the fail2ban sqlite database was using 170k extends which is a lot! If you have database-files with a high fragmentation while using ",{"type":28,"tag":14416,"props":16442,"children":16443},{},[16444],{"type":55,"value":16438},{"type":55,"value":16446},", it is better to run a \"optimize table\" on them, as this also cleans up the database-related fragmentation of frequently rewritten tables. If you use snapshots, make sure to have some free space, as the defrag does an in-place copy of the files while snapshots are blocking the old version from being released.",{"type":28,"tag":79,"props":16448,"children":16450},{"id":16449},"if-everything-is-fine-you-can-go-ahead-and-defrag-all-files-on-that-list",[16451],{"type":55,"value":16452},"If everything is fine, you can go ahead and defrag all files on that list",{"type":28,"tag":534,"props":16454,"children":16456},{"className":15780,"code":16455,"language":15782,"meta":7,"style":7},"find / -xdev -type f| xargs filefrag 2>/dev/null | sed 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/' |\nawk -F ' ' '$1 > 500' | cut -d ' ' -f2 2>/dev/null | xargs -r btrfs fi defrag -f -v\n",[16457],{"type":28,"tag":548,"props":16458,"children":16459},{"__ignoreMap":7},[16460,16520],{"type":28,"tag":116,"props":16461,"children":16462},{"class":553,"line":554},[16463,16467,16471,16475,16479,16483,16487,16491,16495,16499,16503,16507,16511,16515],{"type":28,"tag":116,"props":16464,"children":16465},{"style":2900},[16466],{"type":55,"value":16325},{"type":28,"tag":116,"props":16468,"children":16469},{"style":596},[16470],{"type":55,"value":16330},{"type":28,"tag":116,"props":16472,"children":16473},{"style":2170},[16474],{"type":55,"value":16335},{"type":28,"tag":116,"props":16476,"children":16477},{"style":2170},[16478],{"type":55,"value":16340},{"type":28,"tag":116,"props":16480,"children":16481},{"style":596},[16482],{"type":55,"value":16345},{"type":28,"tag":116,"props":16484,"children":16485},{"style":4807},[16486],{"type":55,"value":16350},{"type":28,"tag":116,"props":16488,"children":16489},{"style":2900},[16490],{"type":55,"value":16355},{"type":28,"tag":116,"props":16492,"children":16493},{"style":596},[16494],{"type":55,"value":16360},{"type":28,"tag":116,"props":16496,"children":16497},{"style":4807},[16498],{"type":55,"value":16365},{"type":28,"tag":116,"props":16500,"children":16501},{"style":596},[16502],{"type":55,"value":16370},{"type":28,"tag":116,"props":16504,"children":16505},{"style":4807},[16506],{"type":55,"value":16375},{"type":28,"tag":116,"props":16508,"children":16509},{"style":2900},[16510],{"type":55,"value":16380},{"type":28,"tag":116,"props":16512,"children":16513},{"style":596},[16514],{"type":55,"value":16385},{"type":28,"tag":116,"props":16516,"children":16517},{"style":4807},[16518],{"type":55,"value":16519}," |\n",{"type":28,"tag":116,"props":16521,"children":16522},{"class":553,"line":271},[16523,16528,16532,16536,16540,16544,16549,16554,16558,16563,16567,16571,16575,16579,16584,16589,16594,16599,16604],{"type":28,"tag":116,"props":16524,"children":16525},{"style":2900},[16526],{"type":55,"value":16527},"awk",{"type":28,"tag":116,"props":16529,"children":16530},{"style":2170},[16531],{"type":55,"value":16399},{"type":28,"tag":116,"props":16533,"children":16534},{"style":596},[16535],{"type":55,"value":16404},{"type":28,"tag":116,"props":16537,"children":16538},{"style":596},[16539],{"type":55,"value":16409},{"type":28,"tag":116,"props":16541,"children":16542},{"style":4807},[16543],{"type":55,"value":16375},{"type":28,"tag":116,"props":16545,"children":16546},{"style":2900},[16547],{"type":55,"value":16548}," cut",{"type":28,"tag":116,"props":16550,"children":16551},{"style":2170},[16552],{"type":55,"value":16553}," -d",{"type":28,"tag":116,"props":16555,"children":16556},{"style":596},[16557],{"type":55,"value":16404},{"type":28,"tag":116,"props":16559,"children":16560},{"style":2170},[16561],{"type":55,"value":16562}," -f2",{"type":28,"tag":116,"props":16564,"children":16565},{"style":4807},[16566],{"type":55,"value":16365},{"type":28,"tag":116,"props":16568,"children":16569},{"style":596},[16570],{"type":55,"value":16370},{"type":28,"tag":116,"props":16572,"children":16573},{"style":4807},[16574],{"type":55,"value":16375},{"type":28,"tag":116,"props":16576,"children":16577},{"style":2900},[16578],{"type":55,"value":16355},{"type":28,"tag":116,"props":16580,"children":16581},{"style":2170},[16582],{"type":55,"value":16583}," -r",{"type":28,"tag":116,"props":16585,"children":16586},{"style":596},[16587],{"type":55,"value":16588}," btrfs",{"type":28,"tag":116,"props":16590,"children":16591},{"style":596},[16592],{"type":55,"value":16593}," fi",{"type":28,"tag":116,"props":16595,"children":16596},{"style":596},[16597],{"type":55,"value":16598}," defrag",{"type":28,"tag":116,"props":16600,"children":16601},{"style":2170},[16602],{"type":55,"value":16603}," -f",{"type":28,"tag":116,"props":16605,"children":16606},{"style":2170},[16607],{"type":55,"value":16608}," -v\n",{"type":28,"tag":47,"props":16610,"children":16611},{},[16612],{"type":55,"value":16613},"This will print out all filenames that are processed.",{"type":28,"tag":79,"props":16615,"children":16617},{"id":16616},"a-short-explanation-of-the-command",[16618],{"type":55,"value":16619},"A short explanation of the command",{"type":28,"tag":47,"props":16621,"children":16622},{},[16623,16627,16629,16633,16635,16640,16642,16647],{"type":28,"tag":14416,"props":16624,"children":16625},{},[16626],{"type":55,"value":16325},{"type":55,"value":16628}," gets all files on the specified path (/) without descending into other mounted filesystems (-xdev). Then ",{"type":28,"tag":14416,"props":16630,"children":16631},{},[16632],{"type":55,"value":16308},{"type":55,"value":16634}," determines the fragmentation, the ",{"type":28,"tag":14416,"props":16636,"children":16637},{},[16638],{"type":55,"value":16639},"sed",{"type":55,"value":16641}," command reformats the output so that the extent count is on first position followed by the filename. Then awk parses that list filtering only files that have more than 500 extends. After that is done, the output is „cut“ to only contain the filenames and passed to btrfs defrag for defragmentation. -v on the ",{"type":28,"tag":14416,"props":16643,"children":16644},{},[16645],{"type":55,"value":16646},"defrag",{"type":55,"value":16648}," command prints out all processed files. Also take a look on the longterm IO usage before and after the defrag to see how big the difference in the real world is.",{"type":28,"tag":79,"props":16650,"children":16652},{"id":16651},"have-fun",[16653],{"type":55,"value":16654},"Have fun!",{"type":28,"tag":1705,"props":16656,"children":16657},{},[16658],{"type":55,"value":1709},{"title":7,"searchDepth":271,"depth":271,"links":16660},[16661,16662,16663,16664,16665,16666,16667,16668],{"id":16206,"depth":271,"text":16209},{"id":16224,"depth":271,"text":16227},{"id":16235,"depth":271,"text":16238},{"id":16284,"depth":271,"text":16287},{"id":16295,"depth":271,"text":16298},{"id":16449,"depth":271,"text":16452},{"id":16616,"depth":271,"text":16619},{"id":16651,"depth":271,"text":16654},{"_path":16670,"_dir":283,"_draft":6,"_partial":6,"_locale":7,"slug":394,"teams":16671,"primaryTeam":286,"firstName":16673,"lastName":16674,"prefixTitle":7,"suffixTitle":16675,"education":16676,"role":16681,"workingSince":16683,"inTheCompanySince":16684,"techSkills":16685,"skills":16708,"projects":16721,"contactDetails":16730,"_image":16733,"image":16734,"_id":16735,"_type":384,"title":16736,"_source":283,"_file":16737,"_stem":16738,"_extension":384},"/employees/robert-juzak",[16672,286],"appDev","Robert","Juzak","B.Sc.",[16677],[16678,16679,16680],"Bachelor of Computer Science","Technische Universität Breslau","2016",[300,16682,299,302],"fullstackDeveloper","2015","2018",[16686,16687,16688,16691,16694,16697,16698,16701,16702,16703,16704,16705,16706],{"name":307,"level":308,"icon":309},{"name":9564,"level":308},{"name":16689,"level":308,"icon":16690},"Kubernetes","/images/Kubernetes.svg",{"name":16692,"level":308,"icon":16693},"PHPUnit","/images/PHP-Unit.svg",{"name":16695,"level":308,"icon":16696},"Portainer","/images/Portainer.svg",{"name":14510,"level":308},{"name":16699,"level":308,"icon":16700},"Sonarqube","/images/Sonarqube.svg",{"name":311,"level":308,"icon":312},{"name":340,"level":334,"icon":341},{"name":343,"level":334,"icon":344},{"name":324,"level":334},{"name":330,"level":334,"icon":331},{"name":16707,"level":334,"icon":350},"VueJS",[16709,16710,16711,16712,16714,16716,16718,16719,16720],{"name":5142,"level":308},{"name":363,"level":308},{"name":286,"level":308},{"name":16713,"level":308},"testDrivenBugfix",{"name":16715,"level":308},"testDrivenDevelopment",{"name":16717,"level":334},"accessibility",{"name":357,"level":334},{"name":359,"level":334},{"name":361,"level":334},[16722,16726,16728],{"project":369,"position":16723},[16724,16725],"Dev-Ops","Frontend Developer",{"project":16727,"position":16725},"Huawei-Calibration-aaS",{"project":16729,"position":16725},"Huawei-Inspect-3D",{"eMail":16731,"phone":16732,"visibility":380},"robert.juzak@helmundwalter.de","+49 351 799 035 26","images/employees/Portraits/robert_juzak.webp","images/employees/Portraits/RobertJuzak_MS.webp","employees:employees:6.robert-juzak.json","Robert Juzak","employees/6.robert-juzak.json","employees/6.robert-juzak",{"_path":16740,"_dir":283,"_draft":6,"_partial":6,"_locale":7,"slug":477,"teams":16741,"primaryTeam":16672,"firstName":16742,"lastName":16743,"prefixTitle":16744,"suffixTitle":7,"executiveRole":16745,"education":16746,"role":16753,"workingSince":293,"inTheCompanySince":16750,"techSkills":16756,"skills":16774,"projects":16786,"contactDetails":16790,"certifications":16793,"image":16799,"_id":16800,"_type":384,"title":16801,"_source":283,"_file":16802,"_stem":16803,"_extension":384},"/employees/jens-bornschein",[16672],"Jens","Bornschein","Dr. Ing.","Projektmanager | Consultant",[16747,16751],[16748,16749,16750],"Doktor-Ingenieur der Informatik","TU Dresden","2020",[16752,16749,293],"Diplom-Medieninformatiker (TU)",[16754,300,16682,16755,16717,302],"projectManager","UI/UX",[16757,16758,16759,16760,16761,16762,16763,16766,16769,16772],{"name":324,"level":308},{"name":337,"level":308,"icon":338},{"name":340,"level":334,"icon":341},{"name":343,"level":334,"icon":344},{"name":349,"level":334,"icon":350},{"name":326,"level":334},{"name":16764,"level":308,"icon":16765},"Adobe Photoshop","/images/adobeps-logo.svg",{"name":16767,"level":308,"icon":16768},"Adobe Illustrator","/images/adobeai-logo.svg",{"name":16770,"level":334,"icon":16771},"Adobe XD","/images/adobexd-logo.svg",{"name":16773,"level":334},"Gitlab",[16775,16777,16778,16779,16781,16783,16784],{"name":16776,"level":308},"projectManagement",{"name":16717,"level":308},{"name":16755,"level":308},{"name":16780,"level":334},"consulting",{"name":16782,"level":334},"scrum",{"name":361,"level":334},{"name":16785,"level":334},"training",[16787,16789],{"project":371,"position":16788},"project manager",{"project":376,"position":16788},{"eMail":16791,"phone":16792,"visibility":380},"jens.bornschein@helmundwalter.de","+49 351 799 035 24",[16794],{"image":16795,"link":16796,"title":16797,"pdf":16798},"/images/certifications/KHZG_Badge.svg","https://www.bundesamtsozialesicherung.de/de/themen/innovationsfonds-und-krankenhausstrukturfonds/krankenhausstrukturfonds/","Berechtigung nach § 21 Absatz 5 Satz 1 KHSFV - Management für KHZG geförderte Vorhaben","/certificates/jb_KHSFV_Zertifikat.pdf","images/employees/Portraits/JensBornschein_MS.webp","employees:employees:5.jens-bornschein.json","Jens Bornschein","employees/5.jens-bornschein.json","employees/5.jens-bornschein",{"_path":282,"_dir":283,"_draft":6,"_partial":6,"_locale":7,"slug":159,"teams":16805,"primaryTeam":286,"firstName":287,"lastName":288,"prefixTitle":7,"suffixTitle":7,"education":16806,"executiveRole":294,"role":16808,"workingSince":303,"inTheCompanySince":304,"techSkills":16809,"skills":16826,"projects":16833,"contactDetails":16839,"_image":381,"image":382,"_id":383,"_type":384,"title":385,"_source":283,"_file":386,"_stem":387,"_extension":384},[285,286],[16807],[291,292,293],[296,297,286,298,299,300,301,302],[16810,16811,16812,16813,16814,16815,16816,16817,16818,16819,16820,16821,16822,16823,16824,16825],{"name":307,"level":308,"icon":309},{"name":311,"level":308,"icon":312},{"name":314,"level":308},{"name":316,"level":308,"icon":317},{"name":319,"level":308},{"name":321,"level":308,"icon":322},{"name":324,"level":308},{"name":326,"level":308},{"name":328,"level":308},{"name":330,"level":308,"icon":331},{"name":333,"level":334,"icon":335},{"name":337,"level":334,"icon":338},{"name":340,"level":334,"icon":341},{"name":343,"level":334,"icon":344},{"name":346,"level":334,"icon":347},{"name":349,"level":334,"icon":350},[16827,16828,16829,16830,16831,16832],{"name":353,"level":308},{"name":355,"level":308},{"name":357,"level":308},{"name":359,"level":308},{"name":361,"level":308},{"name":363,"level":334},[16834,16835,16836,16837,16838],{"project":366,"position":367},{"project":369,"position":367},{"project":371,"position":367},{"project":373,"position":374},{"project":376,"position":367},{"eMail":378,"phone":379,"visibility":380},[16841],{"_path":16842,"_dir":16843,"_draft":6,"_partial":1271,"_locale":7,"name":16844,"slug":16843,"text":16845,"hoverText":16846,"image":16847,"customer":16844,"tags":16848,"_id":16849,"_type":544,"title":16850,"_source":277,"_file":16851,"_stem":16852,"_extension":544},"/en/portfolio/slimspots/_teaser","slimspots","SlimSpots","Processing large amounts of data in real-time","For SlimSpots, a global provider of ad marketing solutions, we developed a highly scalable infrastructure that enables the processing of trillions of data records in real-time.","/images/portfolio/slimspots/slim_spots_prtfolio.png",[357,23],"common:en:portfolio:9020.slimspots:_teaser.yaml","Teaser","en/portfolio/9020.slimspots/_teaser.yaml","en/portfolio/9020.slimspots/_teaser",1782284065311]