[{"data":1,"prerenderedAt":16958},["ShallowReactive",2],{"portfolio-en-slimspots":3,"employee-bernd-helm":352,"employee-daniel-walter":458,"related-refs-databases_devops-slimspots-en":496,"related-blog-databases_devops--en":512,"content-query-GCsGFnjSrZ":633,"content-query-lDWCmQfCc3":1841,"content-query-pY5GjeCLfZ":6242,"content-query-DexhC6jnXN":7323,"content-query-TPh1lFGN9c":9602,"content-query-AVfm838iln":11072,"content-query-8xB9vY4DHX":11603,"content-query-yliWk2uBx7":14514,"content-query-t20WiKE4uI":15761,"content-query-Fqgo9f8ijK":16320,"content-query-KtO3wftRle":16790,"content-query-vhr2h3d1hs":16859,"content-query-1PFeYVQSzn":16922},{"_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":20,"budget":21,"tags":22,"body":25,"_type":346,"_id":347,"_source":348,"_file":349,"_stem":350,"_extension":351},"/en/portfolio/slimspots","portfolio",false,"","SlimSpots","PROCESSING TRILLIONS OF DATA SETS IN REAL-TIME","/images/portfolio/slimspots/slim_spots_prtfolio_phone.png","Ad-Marketing & High-Availability Systems","Online Advertising and Marketing",[14,15,16],"linux","mariadb","php",{"from":18,"to":19},"September 2014","present","2 developers, 1 project manager, 1 DevOps","six-figure",[23,24],"databases","devops",{"type":26,"children":27,"toc":341},"root",[28,86,223,334],{"type":29,"tag":30,"props":31,"children":34},"element","section-component",{"className":32},[33],"no-pattern",[35,80],{"type":29,"tag":36,"props":37,"children":46},"v-card",{"className":38,"style":45},[39,40,41,42,43,44],"description__card","text-justify","px-4","px-md-18","py-4","py-md-14","background-color: rgba(var(--v-theme-primary), 0.1)",[47,60,70],{"type":29,"tag":48,"props":49,"children":50},"p",{},[51,58],{"type":29,"tag":52,"props":53,"children":54},"strong",{},[55],{"type":56,"value":57},"text","In today's data-driven business world, the ability to process large amounts of data in real-time is\na decisive competitive advantage.",{"type":56,"value":59}," SlimSpots, a globally operating provider of ad-marketing solutions, brings\ntraffic suppliers and advertisers together and requires an infrastructure that not only can handle enormous data volumes\nbut also meets the highest requirements for scalability, availability, and speed.",{"type":29,"tag":61,"props":62,"children":69},"img",{"alt":63,"aspect-ratio":64,"className":65,"object-fit":67,"src":68},"Slimspots Phone with KPIs","3",[66],"my-5","contain","/images/portfolio/slimspots/slim_spots_prtfolio.png",[],{"type":29,"tag":48,"props":71,"children":72},{},[73,78],{"type":29,"tag":52,"props":74,"children":75},{},[76],{"type":56,"value":77},"Our task was to develop and maintain a robust, scalable infrastructure that can make\ndecisions about advertising delivery in milliseconds while simultaneously providing trillions of\ndata sets for detailed analysis.",{"type":56,"value":79}," SlimSpots decides for every click and banner view\nwhich advertising is displayed – based on criteria such as browser, device, country, internet provider, time,\nprevious interactions, and many other factors. At the same time, traffic suppliers and advertisers\nmust be able to track the performance of their campaigns in real-time to react quickly to changes.",{"type":29,"tag":81,"props":82,"children":85},"v-divider",{"className":83},[84],"hw-my",[],{"type":29,"tag":30,"props":87,"children":88},{},[89,102,172],{"type":29,"tag":90,"props":91,"children":99},"h2",{"className":92,"id":98},[93,94,95,96,97],"justify-center","mt-12","mb-4","mb-md-8","pt-0","our-services",[100],{"type":56,"value":101}," Our Services ",{"type":29,"tag":36,"props":103,"children":109},{"className":104},[105,106,41,42,43,44,107,108],"background","transparent-4","mb-8","mb-md-12",[110,141],{"type":29,"tag":111,"props":112,"children":114},"v-row",{":no-gutters":113,"no-gutters":7},"true",[115,137],{"type":29,"tag":116,"props":117,"children":120},"v-col",{"cols":118,"md":119},12,"8",[121],{"type":29,"tag":122,"props":123,"children":125},"h3",{"id":124},"database-and-server-administration",[126],{"type":29,"tag":127,"props":128,"children":134},"span",{"className":129},[130,131,132,133],"w-100","text-center","mt-sm-n5","mt-md-n6",[135],{"type":56,"value":136},"Database and Server Administration",{"type":29,"tag":116,"props":138,"children":140},{"cols":118,"md":139},"4",[],{"type":29,"tag":111,"props":142,"children":145},{"className":143},[144],"mt-0",[146,164],{"type":29,"tag":116,"props":147,"children":148},{"cols":118,"md":119},[149,154,159],{"type":29,"tag":48,"props":150,"children":151},{},[152],{"type":56,"value":153},"For SlimSpots, we implemented a comprehensive database and server administration system\ndesigned for maximum availability and performance. At the center of our solution is the use of\nMariaDB ColumnStore, a column-based database specifically designed for processing enormous data volumes.\nThis technology makes it possible to distribute queries across multiple servers and all available CPU cores,\nensuring exceptional scalability.",{"type":29,"tag":48,"props":155,"children":156},{},[157],{"type":56,"value":158},"The implementation of a column-based database brings specific challenges that we mastered through\ncareful optimization of the database structure, queries, and software. We designed the data models\nto be optimally suited for analytical queries while ensuring real-time processing.\nThis balance is crucial for SlimSpots, as the system must both make lightning-fast decisions\nand enable comprehensive historical data analysis.",{"type":29,"tag":48,"props":160,"children":161},{},[162],{"type":56,"value":163},"In addition to database optimization, we also took over the management of the entire server infrastructure,\nwhich at its peak consisted of 40 servers. This included the configuration, monitoring, and maintenance\nof the servers as well as the implementation of high-availability solutions to minimize downtime.\nThrough continuous performance analysis and proactive optimizations, we were able to continuously\nadapt the infrastructure to growing requirements.",{"type":29,"tag":116,"props":165,"children":166},{"cols":118,"md":139},[167],{"type":29,"tag":168,"props":169,"children":171},"employees-card",{":showExecutiveRole":113,"name":170},"bernd-helm",[],{"type":29,"tag":36,"props":173,"children":175},{"className":174},[105,106,41,42,43,44],[176,195],{"type":29,"tag":111,"props":177,"children":178},{":no-gutters":113,"no-gutters":7},[179,182],{"type":29,"tag":116,"props":180,"children":181},{"cols":118,"md":139},[],{"type":29,"tag":116,"props":183,"children":184},{"cols":118,"md":119},[185],{"type":29,"tag":122,"props":186,"children":188},{"id":187},"optimization-of-delivery-software",[189],{"type":29,"tag":127,"props":190,"children":192},{"className":191},[130,131,132,133],[193],{"type":56,"value":194},"Optimization of Delivery Software",{"type":29,"tag":111,"props":196,"children":197},{},[198,205],{"type":29,"tag":116,"props":199,"children":200},{"cols":118,"md":139},[201],{"type":29,"tag":168,"props":202,"children":204},{":showExecutiveRole":113,"name":203},"daniel-walter",[],{"type":29,"tag":116,"props":206,"children":207},{"cols":118,"md":119},[208,213,218],{"type":29,"tag":48,"props":209,"children":210},{},[211],{"type":56,"value":212},"An essential part of our work for SlimSpots was improving the delivery software responsible\nfor real-time decisions in advertising placement. This software must decide in milliseconds\nwhich advertising is shown to a specific user, based on numerous criteria such as device,\nlocation, browser, and previous interactions.",{"type":29,"tag":48,"props":214,"children":215},{},[216],{"type":56,"value":217},"We fundamentally revised and optimized the existing software to increase processing speed\nwhile improving the precision of decision-making. Through the use of efficient\ncaching mechanisms, optimization of database queries, and implementation of intelligent algorithms,\nwe were able to significantly reduce response times and increase system scalability.",{"type":29,"tag":48,"props":219,"children":220},{},[221],{"type":56,"value":222},"We placed special emphasis on real-time analysis and visualization of campaign performance. Advertisers\nand traffic suppliers need immediate feedback on the effectiveness of their measures. Our optimized\nsoftware enables real-time data processing and generation of meaningful dashboards that allow\nimmediate evaluation of campaign performance.",{"type":29,"tag":30,"props":224,"children":225},{},[226,233,330],{"type":29,"tag":90,"props":227,"children":230},{"className":228,"id":229},[93,94,95,96,97],"special-challenges",[231],{"type":56,"value":232}," Special Challenges ",{"type":29,"tag":36,"props":234,"children":236},{"className":235},[105,106,41,42,43,44],[237],{"type":29,"tag":111,"props":238,"children":239},{},[240,260,290,302],{"type":29,"tag":116,"props":241,"children":243},{"cols":118,"md":242,"sm":64},"2",[244],{"type":29,"tag":245,"props":246,"children":254},"v-responsive",{"aspect-ratio":247,"className":248,"content-class":252,"style":253},"0.921",[249,250,251],"bg-primary-lighten-3","hw-hexagon","mx-auto","d-flex justify-center align-center","width: 100%; max-width: 120px;",[255],{"type":29,"tag":256,"props":257,"children":259},"hw-image",{"src":258},"/images/scalability-logo.svg",[],{"type":29,"tag":116,"props":261,"children":264},{"cols":118,"md":262,"sm":263},"10","9",[265,275,280,285],{"type":29,"tag":122,"props":266,"children":268},{"id":267},"extreme-scalability-with-constant-performance",[269],{"type":29,"tag":127,"props":270,"children":272},{"className":271},[132,133],[273],{"type":56,"value":274},"Extreme Scalability with Constant Performance",{"type":29,"tag":48,"props":276,"children":277},{},[278],{"type":56,"value":279},"One of the biggest challenges in this project was ensuring extreme scalability while maintaining\nconstant performance. The data volumes that SlimSpots processes are continuously growing, and the infrastructure\nmust be able to keep pace with this growth without performance degradation.",{"type":29,"tag":48,"props":281,"children":282},{},[283],{"type":56,"value":284},"We mastered this challenge through the use of MariaDB ColumnStore, a column-based\ndatabase specifically developed for big data analytics. We carefully coordinated the database structure,\nqueries, and application logic to enable both lightning-fast decisions and comprehensive historical analysis.",{"type":29,"tag":48,"props":286,"children":287},{},[288],{"type":56,"value":289},"Scaling to up to 40 servers also required a well-thought-out architectural concept that includes efficient\nload distribution and fault tolerance mechanisms.\nThrough the use of intelligent caching mechanisms and optimization of index structures, we were able to ensure\nthat the system functions reliably even with sudden spikes in query volumes.",{"type":29,"tag":116,"props":291,"children":292},{"cols":118,"md":242,"sm":64},[293],{"type":29,"tag":245,"props":294,"children":297},{"aspect-ratio":247,"className":295,"content-class":252,"style":253},[296,250,251],"bg-primary-lighten-1",[298],{"type":29,"tag":256,"props":299,"children":301},{"src":300},"/images/data-processing-logo.svg",[],{"type":29,"tag":116,"props":303,"children":304},{"cols":118,"md":262,"sm":263},[305,315,320,325],{"type":29,"tag":122,"props":306,"children":308},{"id":307},"global-availability-and-data-analysis",[309],{"type":29,"tag":127,"props":310,"children":312},{"className":311},[132,133],[313],{"type":56,"value":314},"Global Availability and Data Analysis",{"type":29,"tag":48,"props":316,"children":317},{},[318],{"type":56,"value":319},"As a globally operating company, SlimSpots needs an infrastructure that is globally available yet\nprovides low latency times. At the same time, data must be stored and analyzable for years\nto identify long-term trends and evaluate campaign effectiveness.",{"type":29,"tag":48,"props":321,"children":322},{},[323],{"type":56,"value":324},"We implemented a distributed system that combines local processing with global data consistency.\nThe challenge was to create a consistent data foundation for analysis despite global distribution.",{"type":29,"tag":48,"props":326,"children":327},{},[328],{"type":56,"value":329},"Particularly demanding was the requirement to keep historical data available and efficiently queryable\nover years. Our system architecture enables SlimSpots and its customers to perform\ndetailed evaluations over long periods, gaining valuable insights for optimizing their campaigns.",{"type":29,"tag":81,"props":331,"children":333},{"className":332},[84],[],{"type":29,"tag":30,"props":335,"children":336},{},[337],{"type":29,"tag":338,"props":339,"children":340},"contact-form",{},[],{"title":7,"searchDepth":342,"depth":342,"links":343},2,[344,345],{"id":98,"depth":342,"text":101},{"id":229,"depth":342,"text":232},"markdown","common:en:portfolio:9020.slimspots:index.md","common","en/portfolio/9020.slimspots/index.md","en/portfolio/9020.slimspots/index","md",{"_path":353,"_dir":354,"_draft":6,"_partial":6,"_locale":7,"slug":170,"teams":355,"primaryTeam":357,"firstName":358,"lastName":359,"prefixTitle":7,"suffixTitle":7,"education":360,"executiveRole":365,"role":366,"workingSince":374,"inTheCompanySince":375,"techSkills":376,"skills":422,"projects":434,"contactDetails":447,"_image":451,"image":452,"_id":453,"_type":454,"title":455,"_source":354,"_file":456,"_stem":457,"_extension":454},"/employees/bernd-helm","employees",[356,357],"ai","devOps","Bernd","Helm",[361],[362,363,364],"B. Sc. Angewandte Informatik","FHDW Dresden","2010","CTO",[367,368,357,369,370,371,372,373],"founder","chiefTechnologyOfficer","databaseSpecialist","admin","softwareDeveloper","backendDeveloper","consultant","2005","2008",[377,381,384,386,389,391,394,396,398,400,403,407,410,413,416,419],{"name":378,"level":379,"icon":380},"Docker","expert","/images/Docker.svg",{"name":382,"level":379,"icon":383},"Linux","/images/linux_os-mono.svg",{"name":385,"level":379},"Zabbix",{"name":387,"level":379,"icon":388},"MariaDB ColumnStore","/images/maria-db-logo.svg",{"name":390,"level":379},"OpenAI",{"name":392,"level":379,"icon":393},"Pytorch","/images/PyTorch.svg",{"name":395,"level":379},"PHP",{"name":397,"level":379},"Java",{"name":399,"level":379},"Python",{"name":401,"level":379,"icon":402},"SQL","/images/SQL.svg",{"name":404,"level":405,"icon":406},"C++","advanced","/images/cpp-logo.svg",{"name":408,"level":405,"icon":409},"C#","/images/csharp.svg",{"name":411,"level":405,"icon":412},"CSS","/images/css.svg",{"name":414,"level":405,"icon":415},"HTML","/images/html.svg",{"name":417,"level":405,"icon":418},"OpenCV","/images/OpenCV.svg",{"name":420,"level":405,"icon":421},"Vue.js","/images/vuejs.svg",[423,425,427,428,430,432],{"name":424,"level":379},"artificialIntelligence",{"name":426,"level":379},"codingGuidelines",{"name":23,"level":379},{"name":429,"level":379},"linuxServerAdministration",{"name":431,"level":379},"softwareArchitect",{"name":433,"level":405},"qualityAssurance",[435,438,440,442,445],{"project":436,"position":437},"Gridside","Technical Consultant",{"project":439,"position":437},"Herole",{"project":441,"position":437},"Montagespezis",{"project":443,"position":444},"Orsee","Technical Manager",{"project":446,"position":437},"Vipr",{"eMail":448,"phone":449,"visibility":450},"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",{"_path":459,"_dir":354,"_draft":6,"_partial":6,"_locale":7,"slug":203,"teams":460,"primaryTeam":461,"firstName":462,"lastName":463,"prefixTitle":7,"suffixTitle":7,"education":464,"executiveRole":467,"role":468,"workingSince":375,"inTheCompanySince":375,"techSkills":472,"skills":479,"projects":486,"contactDetails":487,"_image":490,"image":491,"_id":492,"_type":454,"title":493,"_source":354,"_file":494,"_stem":495,"_extension":454},"/employees/daniel-walter",[461,357],"shopware","Daniel","Walter",[465],[362,466,364],"FHDW","CEO",[367,469,470,371,471,370,373],"chiefExecutiveOfficer","projectManager","fullstackDeveloper",[473,474,475,476],{"name":404,"level":379,"icon":406},{"name":408,"level":379,"icon":409},{"name":401,"level":379,"icon":402},{"name":477,"level":405,"icon":478},"Flutter","/images/Flutter.svg",[480,481,482,484,485],{"name":23,"level":379},{"name":429,"level":379},{"name":483,"level":379},"projectManagement",{"name":461,"level":379},{"name":431,"level":405},[],{"eMail":488,"phone":489,"visibility":450},"daniel.walter@helmundwalter.de","+49 351 799 035 21","images/employees/Portraits/daniel_walter.webp","images/employees/Portraits/DanielWalter_MS.webp","employees:employees:2.daniel-walter.json","Daniel Walter","employees/2.daniel-walter.json","employees/2.daniel-walter",[497],{"_path":498,"_dir":499,"_draft":6,"_partial":500,"_locale":7,"name":501,"slug":499,"text":502,"hoverText":503,"image":504,"customer":501,"tags":505,"_id":507,"_type":508,"title":509,"_source":348,"_file":510,"_stem":511,"_extension":508},"/en/portfolio/pixelx/_teaser","pixelx",true,"PixelX","IT Security with Precision and Expertise","For PixelX, we conducted a targeted security analysis where, thanks to our deep technical understanding, we were able to identify a critical SQL injection vulnerability. With minimal time investment, we achieved maximum security gain.","/images/portfolio/pixelx/pixelx_secured.png",[506,24],"security","common:en:portfolio:9010.pixelx:_teaser.yaml","yaml","Teaser","en/portfolio/9010.pixelx/_teaser.yaml","en/portfolio/9010.pixelx/_teaser",[513,529,542,552,562,573,584,596,609,622],{"_path":514,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":516,"description":517,"author":518,"image":519,"releaseDate":520,"blogCategories":521,"articleTags":524,"tags":525,"_type":346,"_id":526,"_source":348,"_file":527,"_stem":528,"_extension":351},"/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",[522,523],"What moves us","DevOps",[523],[24],"common:en:blog:21.traefik-magic.md","en/blog/21.traefik-magic.md","en/blog/21.traefik-magic",{"_path":530,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":531,"description":532,"author":518,"image":519,"releaseDate":533,"blogCategories":534,"articleTags":535,"tags":538,"_type":346,"_id":539,"_source":348,"_file":540,"_stem":541,"_extension":351},"/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",[522,523],[523,536,537],"Open Source","Shopware",[461,24],"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":543,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":544,"description":545,"author":518,"image":519,"releaseDate":533,"blogCategories":546,"articleTags":547,"tags":548,"_type":346,"_id":549,"_source":348,"_file":550,"_stem":551,"_extension":351},"/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",[522,523],[523,536,537],[461,24],"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":553,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":554,"description":555,"author":518,"image":519,"releaseDate":533,"blogCategories":556,"articleTags":557,"tags":558,"_type":346,"_id":559,"_source":348,"_file":560,"_stem":561,"_extension":351},"/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",[522,523],[523,536,537],[461,24],"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":563,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":564,"description":565,"author":518,"image":519,"releaseDate":566,"blogCategories":567,"articleTags":568,"tags":569,"_type":346,"_id":570,"_source":348,"_file":571,"_stem":572,"_extension":351},"/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",[522,523],[523,536],[24],"common:en:blog:17.gitops-docker-renovate.md","en/blog/17.gitops-docker-renovate.md","en/blog/17.gitops-docker-renovate",{"_path":574,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":575,"description":576,"author":518,"image":519,"releaseDate":577,"blogCategories":578,"articleTags":579,"tags":580,"_type":346,"_id":581,"_source":348,"_file":582,"_stem":583,"_extension":351},"/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",[522,523],[523,536],[461,24],"common:en:blog:16.shopware-renovate-bot.md","en/blog/16.shopware-renovate-bot.md","en/blog/16.shopware-renovate-bot",{"_path":585,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":586,"description":587,"author":518,"image":519,"releaseDate":588,"blogCategories":589,"articleTags":591,"tags":592,"_type":346,"_id":593,"_source":348,"_file":594,"_stem":595,"_extension":351},"/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",[522,590],"Infrastructure",[523],[24],"common:en:blog:14.gitlab-behind-traefik.md","en/blog/14.gitlab-behind-traefik.md","en/blog/14.gitlab-behind-traefik",{"_path":597,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":598,"description":599,"author":600,"image":519,"releaseDate":601,"blogCategories":602,"articleTags":604,"tags":605,"_type":346,"_id":606,"_source":348,"_file":607,"_stem":608,"_extension":351},"/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",[603],"What Moves Us",[523],[24],"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":610,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":611,"description":612,"author":170,"image":613,"releaseDate":614,"blogCategories":615,"articleTags":616,"tags":618,"_type":346,"_id":619,"_source":348,"_file":620,"_stem":621,"_extension":351},"/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",[522,523],[617],"VPN",[24],"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":623,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":624,"description":625,"author":170,"image":626,"releaseDate":627,"blogCategories":628,"tags":629,"_type":346,"_id":630,"_source":348,"_file":631,"_stem":632,"_extension":351},"/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",[522,590],[24],"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":514,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":516,"description":517,"author":518,"image":519,"releaseDate":520,"blogCategories":634,"articleTags":635,"tags":636,"body":637,"_type":346,"_id":526,"_source":348,"_file":527,"_stem":528,"_extension":351},[522,523],[523],[24],{"type":26,"children":638,"toc":1831},[639,651,656,802,807,882,888,917,922,946,959,978,984,1001,1102,1107,1112,1137,1183,1187,1192,1556,1561,1597,1603,1611,1662,1666,1673,1701,1707,1712,1718,1723,1735,1743,1749,1761,1825],{"type":29,"tag":48,"props":640,"children":641},{},[642,649],{"type":29,"tag":643,"props":644,"children":646},"a",{"href":645},"https://doc.traefik.io/traefik/",[647],{"type":56,"value":648},"Traefik",{"type":56,"value":650}," is a reverse proxy with excellent docker integration. It uses labeln attached to containers to route traffic to them.",{"type":29,"tag":48,"props":652,"children":653},{},[654],{"type":56,"value":655},"A common label set looks similar to this:",{"type":29,"tag":657,"props":658,"children":668},"pre",{"code":659,"filename":660,"highlights":661,"language":508,"meta":7,"className":667,"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",[662,663,664,665,666],5,6,7,8,9,"language-yaml shiki shiki-themes github-dark github-dark monokai",[669],{"type":29,"tag":670,"props":671,"children":672},"code",{"__ignoreMap":7},[673,690,702,722,735,750,763,776,789],{"type":29,"tag":127,"props":674,"children":677},{"class":675,"line":676},"line",1,[678,684],{"type":29,"tag":127,"props":679,"children":681},{"style":680},"--shiki-default:#85E89D;--shiki-dark:#85E89D;--shiki-sepia:#F92672",[682],{"type":56,"value":683},"services",{"type":29,"tag":127,"props":685,"children":687},{"style":686},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2",[688],{"type":56,"value":689},":\n",{"type":29,"tag":127,"props":691,"children":692},{"class":675,"line":342},[693,698],{"type":29,"tag":127,"props":694,"children":695},{"style":680},[696],{"type":56,"value":697},"  whoami",{"type":29,"tag":127,"props":699,"children":700},{"style":686},[701],{"type":56,"value":689},{"type":29,"tag":127,"props":703,"children":705},{"class":675,"line":704},3,[706,711,716],{"type":29,"tag":127,"props":707,"children":708},{"style":680},[709],{"type":56,"value":710},"    image",{"type":29,"tag":127,"props":712,"children":713},{"style":686},[714],{"type":56,"value":715},": ",{"type":29,"tag":127,"props":717,"children":719},{"style":718},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74",[720],{"type":56,"value":721},"traefik/whoami\n",{"type":29,"tag":127,"props":723,"children":725},{"class":675,"line":724},4,[726,731],{"type":29,"tag":127,"props":727,"children":728},{"style":680},[729],{"type":56,"value":730},"    labels",{"type":29,"tag":127,"props":732,"children":733},{"style":686},[734],{"type":56,"value":689},{"type":29,"tag":127,"props":736,"children":739},{"class":737,"line":662},[675,738],"highlight",[740,745],{"type":29,"tag":127,"props":741,"children":742},{"style":686},[743],{"type":56,"value":744},"      - ",{"type":29,"tag":127,"props":746,"children":747},{"style":718},[748],{"type":56,"value":749},"\"traefik.enable=true\"\n",{"type":29,"tag":127,"props":751,"children":753},{"class":752,"line":663},[675,738],[754,758],{"type":29,"tag":127,"props":755,"children":756},{"style":686},[757],{"type":56,"value":744},{"type":29,"tag":127,"props":759,"children":760},{"style":718},[761],{"type":56,"value":762},"\"traefik.http.routers.whoami.rule=Host(`whoami.example.com`)\"\n",{"type":29,"tag":127,"props":764,"children":766},{"class":765,"line":664},[675,738],[767,771],{"type":29,"tag":127,"props":768,"children":769},{"style":686},[770],{"type":56,"value":744},{"type":29,"tag":127,"props":772,"children":773},{"style":718},[774],{"type":56,"value":775},"\"traefik.http.routers.whoami.entrypoints=websecure\"\n",{"type":29,"tag":127,"props":777,"children":779},{"class":778,"line":665},[675,738],[780,784],{"type":29,"tag":127,"props":781,"children":782},{"style":686},[783],{"type":56,"value":744},{"type":29,"tag":127,"props":785,"children":786},{"style":718},[787],{"type":56,"value":788},"\"traefik.http.routers.whoami.tls=true\"\n",{"type":29,"tag":127,"props":790,"children":792},{"class":791,"line":666},[675,738],[793,797],{"type":29,"tag":127,"props":794,"children":795},{"style":686},[796],{"type":56,"value":744},{"type":29,"tag":127,"props":798,"children":799},{"style":718},[800],{"type":56,"value":801},"\"traefik.http.routers.whoami.tls.certresolver=letsencrypt\"\n",{"type":29,"tag":48,"props":803,"children":804},{},[805],{"type":56,"value":806},"In this example:",{"type":29,"tag":808,"props":809,"children":810},"ul",{},[811,823,839,844,856,861],{"type":29,"tag":812,"props":813,"children":814},"li",{},[815,821],{"type":29,"tag":670,"props":816,"children":818},{"className":817},[],[819],{"type":56,"value":820},"whoami",{"type":56,"value":822}," the name of the \"main\" service (2)",{"type":29,"tag":812,"props":824,"children":825},{},[826,831,833],{"type":29,"tag":670,"props":827,"children":829},{"className":828},[],[830],{"type":56,"value":820},{"type":56,"value":832}," the also the default ",{"type":29,"tag":643,"props":834,"children":836},{"href":835},"https://docs.docker.com/compose/how-tos/project-name/",[837],{"type":56,"value":838},"compose project name",{"type":29,"tag":812,"props":840,"children":841},{},[842],{"type":56,"value":843},"Traefik is activated (5)",{"type":29,"tag":812,"props":845,"children":846},{},[847,849,854],{"type":56,"value":848},"It is exposed under ",{"type":29,"tag":670,"props":850,"children":852},{"className":851},[],[853],{"type":56,"value":820},{"type":56,"value":855}," subdomain (6)",{"type":29,"tag":812,"props":857,"children":858},{},[859],{"type":56,"value":860},"It is served over https (7)",{"type":29,"tag":812,"props":862,"children":863},{},[864,866,872,874,880],{"type":56,"value":865},"A preconfigured certresolver named ",{"type":29,"tag":670,"props":867,"children":869},{"className":868},[],[870],{"type":56,"value":871},"letsencrypt",{"type":56,"value":873}," is used for ",{"type":29,"tag":670,"props":875,"children":877},{"className":876},[],[878],{"type":56,"value":879},"tls",{"type":56,"value":881}," (8-9)",{"type":29,"tag":90,"props":883,"children":885},{"id":884},"the-problem",[886],{"type":56,"value":887},"The problem",{"type":29,"tag":48,"props":889,"children":890},{},[891,893,899,901,907,909,915],{"type":56,"value":892},"In my ",{"type":29,"tag":643,"props":894,"children":896},{"href":895},"/blog/gitops-docker-renovate",[897],{"type":56,"value":898},"other post about gitops with docker",{"type":56,"value":900}," I introduced a concept of using ",{"type":29,"tag":670,"props":902,"children":904},{"className":903},[],[905],{"type":56,"value":906},"git",{"type":56,"value":908},"\nas the sources of truth for docker deployments using ",{"type":29,"tag":643,"props":910,"children":912},{"href":911},"https://docs.docker.com/compose/",[913],{"type":56,"value":914},"docker compose",{"type":56,"value":916},".",{"type":29,"tag":48,"props":918,"children":919},{},[920],{"type":56,"value":921},"Now there are some requirements to this approach:",{"type":29,"tag":808,"props":923,"children":924},{},[925,936],{"type":29,"tag":812,"props":926,"children":927},{},[928,930],{"type":56,"value":929},"every stack is exposer under ",{"type":29,"tag":670,"props":931,"children":933},{"className":932},[],[934],{"type":56,"value":935},"\u003Cstack_name>.\u003Cyour_domain>",{"type":29,"tag":812,"props":937,"children":938},{},[939,941],{"type":56,"value":940},"every stack is protected with ",{"type":29,"tag":670,"props":942,"children":944},{"className":943},[],[945],{"type":56,"value":879},{"type":29,"tag":48,"props":947,"children":948},{},[949,951,957],{"type":56,"value":950},"We could of course edit every ",{"type":29,"tag":670,"props":952,"children":954},{"className":953},[],[955],{"type":56,"value":956},"docker-compose.yaml",{"type":56,"value":958}," file and add the required labels, but it quickly becomes obvious,\nthat all the labels are the same!",{"type":29,"tag":960,"props":961,"children":962},"ol",{},[963,968,973],{"type":29,"tag":812,"props":964,"children":965},{},[966],{"type":56,"value":967},"Enable Traefik",{"type":29,"tag":812,"props":969,"children":970},{},[971],{"type":56,"value":972},"Assign a subdomain",{"type":29,"tag":812,"props":974,"children":975},{},[976],{"type":56,"value":977},"Enable HTTPS",{"type":29,"tag":90,"props":979,"children":981},{"id":980},"the-solution",[982],{"type":56,"value":983},"The solution",{"type":29,"tag":48,"props":985,"children":986},{},[987,989,999],{"type":56,"value":988},"By using ",{"type":29,"tag":643,"props":990,"children":992},{"href":991},"https://docs.docker.com/compose/how-tos/environment-variables/envvars/#compose_project_name",[993],{"type":29,"tag":670,"props":994,"children":996},{"className":995},[],[997],{"type":56,"value":998},"$COMPOSE_PROJECT_NAME",{"type":56,"value":1000},"\nvariable we can create a more generic template.\nThis ensures that the Traefik rules are consistent.",{"type":29,"tag":657,"props":1002,"children":1005},{"code":1003,"filename":1004,"language":508,"meta":7,"className":667,"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",[1006],{"type":29,"tag":670,"props":1007,"children":1008},{"__ignoreMap":7},[1009,1020,1032,1043,1054,1066,1078,1090],{"type":29,"tag":127,"props":1010,"children":1011},{"class":675,"line":676},[1012,1016],{"type":29,"tag":127,"props":1013,"children":1014},{"style":680},[1015],{"type":56,"value":683},{"type":29,"tag":127,"props":1017,"children":1018},{"style":686},[1019],{"type":56,"value":689},{"type":29,"tag":127,"props":1021,"children":1022},{"class":675,"line":342},[1023,1028],{"type":29,"tag":127,"props":1024,"children":1025},{"style":680},[1026],{"type":56,"value":1027},"  \u003Cmain_service>",{"type":29,"tag":127,"props":1029,"children":1030},{"style":686},[1031],{"type":56,"value":689},{"type":29,"tag":127,"props":1033,"children":1034},{"class":675,"line":704},[1035,1039],{"type":29,"tag":127,"props":1036,"children":1037},{"style":680},[1038],{"type":56,"value":730},{"type":29,"tag":127,"props":1040,"children":1041},{"style":686},[1042],{"type":56,"value":689},{"type":29,"tag":127,"props":1044,"children":1045},{"class":675,"line":724},[1046,1050],{"type":29,"tag":127,"props":1047,"children":1048},{"style":686},[1049],{"type":56,"value":744},{"type":29,"tag":127,"props":1051,"children":1052},{"style":718},[1053],{"type":56,"value":749},{"type":29,"tag":127,"props":1055,"children":1056},{"class":675,"line":662},[1057,1061],{"type":29,"tag":127,"props":1058,"children":1059},{"style":686},[1060],{"type":56,"value":744},{"type":29,"tag":127,"props":1062,"children":1063},{"style":718},[1064],{"type":56,"value":1065},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`\u003Cstack_name>.example.com`)\"\n",{"type":29,"tag":127,"props":1067,"children":1068},{"class":675,"line":663},[1069,1073],{"type":29,"tag":127,"props":1070,"children":1071},{"style":686},[1072],{"type":56,"value":744},{"type":29,"tag":127,"props":1074,"children":1075},{"style":718},[1076],{"type":56,"value":1077},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure\"\n",{"type":29,"tag":127,"props":1079,"children":1080},{"class":675,"line":664},[1081,1085],{"type":29,"tag":127,"props":1082,"children":1083},{"style":686},[1084],{"type":56,"value":744},{"type":29,"tag":127,"props":1086,"children":1087},{"style":718},[1088],{"type":56,"value":1089},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true\"\n",{"type":29,"tag":127,"props":1091,"children":1092},{"class":675,"line":665},[1093,1097],{"type":29,"tag":127,"props":1094,"children":1095},{"style":686},[1096],{"type":56,"value":744},{"type":29,"tag":127,"props":1098,"children":1099},{"style":718},[1100],{"type":56,"value":1101},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt\"\n",{"type":29,"tag":48,"props":1103,"children":1104},{},[1105],{"type":56,"value":1106},"The good news is that Traefik lets us configure some defaults that will cover the above boilerplate!",{"type":29,"tag":48,"props":1108,"children":1109},{},[1110],{"type":56,"value":1111},"Let's us define two simple conventions:",{"type":29,"tag":960,"props":1113,"children":1114},{},[1115,1126],{"type":29,"tag":812,"props":1116,"children":1117},{},[1118,1124],{"type":29,"tag":670,"props":1119,"children":1121},{"className":1120},[],[1122],{"type":56,"value":1123},"app",{"type":56,"value":1125}," is the main container, where Traefik will route the traffic",{"type":29,"tag":812,"props":1127,"children":1128},{},[1129,1135],{"type":29,"tag":670,"props":1130,"children":1132},{"className":1131},[],[1133],{"type":56,"value":1134},"\u003Cstack_name>",{"type":56,"value":1136}," (the compose project name) is the subdomain",{"type":29,"tag":657,"props":1138,"children":1141},{"code":1139,"filename":660,"language":508,"meta":1140,"className":667,"style":7},"services:\n  app:\n    image: traefik/whoami\n","(1)",[1142],{"type":29,"tag":670,"props":1143,"children":1144},{"__ignoreMap":7},[1145,1156,1168],{"type":29,"tag":127,"props":1146,"children":1147},{"class":675,"line":676},[1148,1152],{"type":29,"tag":127,"props":1149,"children":1150},{"style":680},[1151],{"type":56,"value":683},{"type":29,"tag":127,"props":1153,"children":1154},{"style":686},[1155],{"type":56,"value":689},{"type":29,"tag":127,"props":1157,"children":1158},{"class":675,"line":342},[1159,1164],{"type":29,"tag":127,"props":1160,"children":1161},{"style":680},[1162],{"type":56,"value":1163},"  app",{"type":29,"tag":127,"props":1165,"children":1166},{"style":686},[1167],{"type":56,"value":689},{"type":29,"tag":127,"props":1169,"children":1170},{"class":675,"line":704},[1171,1175,1179],{"type":29,"tag":127,"props":1172,"children":1173},{"style":680},[1174],{"type":56,"value":710},{"type":29,"tag":127,"props":1176,"children":1177},{"style":686},[1178],{"type":56,"value":715},{"type":29,"tag":127,"props":1180,"children":1181},{"style":718},[1182],{"type":56,"value":721},{"type":29,"tag":1184,"props":1185,"children":1186},"hr",{},[],{"type":29,"tag":48,"props":1188,"children":1189},{},[1190],{"type":56,"value":1191},"Now let's configure traefik to do \"the magic\"",{"type":29,"tag":657,"props":1193,"children":1197},{"code":1194,"filename":1195,"language":508,"meta":1196,"className":667,"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)",[1198],{"type":29,"tag":670,"props":1199,"children":1200},{"__ignoreMap":7},[1201,1213,1225,1233,1244,1256,1273,1290,1306,1323,1336,1349,1361,1374,1387,1396,1409,1422,1431,1444,1457,1470,1478,1491,1504,1517,1530,1543],{"type":29,"tag":127,"props":1202,"children":1203},{"class":675,"line":676},[1204,1209],{"type":29,"tag":127,"props":1205,"children":1206},{"style":680},[1207],{"type":56,"value":1208},"volumes",{"type":29,"tag":127,"props":1210,"children":1211},{"style":686},[1212],{"type":56,"value":689},{"type":29,"tag":127,"props":1214,"children":1215},{"class":675,"line":342},[1216,1221],{"type":29,"tag":127,"props":1217,"children":1218},{"style":680},[1219],{"type":56,"value":1220},"  letsencrypt",{"type":29,"tag":127,"props":1222,"children":1223},{"style":686},[1224],{"type":56,"value":689},{"type":29,"tag":127,"props":1226,"children":1227},{"class":675,"line":704},[1228],{"type":29,"tag":127,"props":1229,"children":1230},{"style":686},[1231],{"type":56,"value":1232},"    \n",{"type":29,"tag":127,"props":1234,"children":1235},{"class":675,"line":724},[1236,1240],{"type":29,"tag":127,"props":1237,"children":1238},{"style":680},[1239],{"type":56,"value":683},{"type":29,"tag":127,"props":1241,"children":1242},{"style":686},[1243],{"type":56,"value":689},{"type":29,"tag":127,"props":1245,"children":1246},{"class":675,"line":662},[1247,1252],{"type":29,"tag":127,"props":1248,"children":1249},{"style":680},[1250],{"type":56,"value":1251},"  traefik",{"type":29,"tag":127,"props":1253,"children":1254},{"style":686},[1255],{"type":56,"value":689},{"type":29,"tag":127,"props":1257,"children":1258},{"class":675,"line":663},[1259,1264,1268],{"type":29,"tag":127,"props":1260,"children":1261},{"style":680},[1262],{"type":56,"value":1263},"    container_name",{"type":29,"tag":127,"props":1265,"children":1266},{"style":686},[1267],{"type":56,"value":715},{"type":29,"tag":127,"props":1269,"children":1270},{"style":718},[1271],{"type":56,"value":1272},"traefik\n",{"type":29,"tag":127,"props":1274,"children":1275},{"class":675,"line":664},[1276,1281,1285],{"type":29,"tag":127,"props":1277,"children":1278},{"style":680},[1279],{"type":56,"value":1280},"    restart",{"type":29,"tag":127,"props":1282,"children":1283},{"style":686},[1284],{"type":56,"value":715},{"type":29,"tag":127,"props":1286,"children":1287},{"style":718},[1288],{"type":56,"value":1289},"always\n",{"type":29,"tag":127,"props":1291,"children":1292},{"class":675,"line":665},[1293,1297,1301],{"type":29,"tag":127,"props":1294,"children":1295},{"style":680},[1296],{"type":56,"value":710},{"type":29,"tag":127,"props":1298,"children":1299},{"style":686},[1300],{"type":56,"value":715},{"type":29,"tag":127,"props":1302,"children":1303},{"style":718},[1304],{"type":56,"value":1305},"traefik:3\n",{"type":29,"tag":127,"props":1307,"children":1308},{"class":675,"line":666},[1309,1314,1318],{"type":29,"tag":127,"props":1310,"children":1311},{"style":680},[1312],{"type":56,"value":1313},"    network_mode",{"type":29,"tag":127,"props":1315,"children":1316},{"style":686},[1317],{"type":56,"value":715},{"type":29,"tag":127,"props":1319,"children":1320},{"style":718},[1321],{"type":56,"value":1322},"host\n",{"type":29,"tag":127,"props":1324,"children":1326},{"class":675,"line":1325},10,[1327,1332],{"type":29,"tag":127,"props":1328,"children":1329},{"style":680},[1330],{"type":56,"value":1331},"    command",{"type":29,"tag":127,"props":1333,"children":1334},{"style":686},[1335],{"type":56,"value":689},{"type":29,"tag":127,"props":1337,"children":1339},{"class":675,"line":1338},11,[1340,1344],{"type":29,"tag":127,"props":1341,"children":1342},{"style":686},[1343],{"type":56,"value":744},{"type":29,"tag":127,"props":1345,"children":1346},{"style":718},[1347],{"type":56,"value":1348},"--certificatesresolvers.letsencrypt.acme.httpchallenge=true\n",{"type":29,"tag":127,"props":1350,"children":1351},{"class":675,"line":118},[1352,1356],{"type":29,"tag":127,"props":1353,"children":1354},{"style":686},[1355],{"type":56,"value":744},{"type":29,"tag":127,"props":1357,"children":1358},{"style":718},[1359],{"type":56,"value":1360},"--certificatesresolvers.letsencrypt.acme.email=\u003Cyour_email_here>\n",{"type":29,"tag":127,"props":1362,"children":1364},{"class":675,"line":1363},13,[1365,1369],{"type":29,"tag":127,"props":1366,"children":1367},{"style":686},[1368],{"type":56,"value":744},{"type":29,"tag":127,"props":1370,"children":1371},{"style":718},[1372],{"type":56,"value":1373},"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n",{"type":29,"tag":127,"props":1375,"children":1377},{"class":675,"line":1376},14,[1378,1382],{"type":29,"tag":127,"props":1379,"children":1380},{"style":686},[1381],{"type":56,"value":744},{"type":29,"tag":127,"props":1383,"children":1384},{"style":718},[1385],{"type":56,"value":1386},"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n",{"type":29,"tag":127,"props":1388,"children":1390},{"class":675,"line":1389},15,[1391],{"type":29,"tag":127,"props":1392,"children":1393},{"emptyLinePlaceholder":500},[1394],{"type":56,"value":1395},"\n",{"type":29,"tag":127,"props":1397,"children":1399},{"class":675,"line":1398},16,[1400,1404],{"type":29,"tag":127,"props":1401,"children":1402},{"style":686},[1403],{"type":56,"value":744},{"type":29,"tag":127,"props":1405,"children":1406},{"style":718},[1407],{"type":56,"value":1408},"--entrypoints.web.address=:80\n",{"type":29,"tag":127,"props":1410,"children":1412},{"class":675,"line":1411},17,[1413,1417],{"type":29,"tag":127,"props":1414,"children":1415},{"style":686},[1416],{"type":56,"value":744},{"type":29,"tag":127,"props":1418,"children":1419},{"style":718},[1420],{"type":56,"value":1421},"--entrypoints.websecure.address=:443\n",{"type":29,"tag":127,"props":1423,"children":1425},{"class":675,"line":1424},18,[1426],{"type":29,"tag":127,"props":1427,"children":1428},{"style":686},[1429],{"type":56,"value":1430},"      \n",{"type":29,"tag":127,"props":1432,"children":1434},{"class":675,"line":1433},19,[1435,1439],{"type":29,"tag":127,"props":1436,"children":1437},{"style":686},[1438],{"type":56,"value":744},{"type":29,"tag":127,"props":1440,"children":1441},{"style":718},[1442],{"type":56,"value":1443},"--entrypoints.web.http.redirections.entrypoint.to=websecure\n",{"type":29,"tag":127,"props":1445,"children":1447},{"class":675,"line":1446},20,[1448,1452],{"type":29,"tag":127,"props":1449,"children":1450},{"style":686},[1451],{"type":56,"value":744},{"type":29,"tag":127,"props":1453,"children":1454},{"style":718},[1455],{"type":56,"value":1456},"--entrypoints.web.http.redirections.entrypoint.scheme=https\n",{"type":29,"tag":127,"props":1458,"children":1460},{"class":675,"line":1459},21,[1461,1465],{"type":29,"tag":127,"props":1462,"children":1463},{"style":686},[1464],{"type":56,"value":744},{"type":29,"tag":127,"props":1466,"children":1467},{"style":718},[1468],{"type":56,"value":1469},"--entrypoints.websecure.http.tls.certresolver=letsencrypt\n",{"type":29,"tag":127,"props":1471,"children":1473},{"class":675,"line":1472},22,[1474],{"type":29,"tag":127,"props":1475,"children":1476},{"emptyLinePlaceholder":500},[1477],{"type":56,"value":1395},{"type":29,"tag":127,"props":1479,"children":1481},{"class":675,"line":1480},23,[1482,1486],{"type":29,"tag":127,"props":1483,"children":1484},{"style":686},[1485],{"type":56,"value":744},{"type":29,"tag":127,"props":1487,"children":1488},{"style":718},[1489],{"type":56,"value":1490},"--providers.docker\n",{"type":29,"tag":127,"props":1492,"children":1494},{"class":675,"line":1493},24,[1495,1499],{"type":29,"tag":127,"props":1496,"children":1497},{"style":686},[1498],{"type":56,"value":744},{"type":29,"tag":127,"props":1500,"children":1501},{"style":718},[1502],{"type":56,"value":1503},"--providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)\n",{"type":29,"tag":127,"props":1505,"children":1507},{"class":675,"line":1506},25,[1508,1512],{"type":29,"tag":127,"props":1509,"children":1510},{"style":686},[1511],{"type":56,"value":744},{"type":29,"tag":127,"props":1513,"children":1514},{"style":718},[1515],{"type":56,"value":1516},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`)\n",{"type":29,"tag":127,"props":1518,"children":1520},{"class":675,"line":1519},26,[1521,1526],{"type":29,"tag":127,"props":1522,"children":1523},{"style":680},[1524],{"type":56,"value":1525},"    volumes",{"type":29,"tag":127,"props":1527,"children":1528},{"style":686},[1529],{"type":56,"value":689},{"type":29,"tag":127,"props":1531,"children":1533},{"class":675,"line":1532},27,[1534,1538],{"type":29,"tag":127,"props":1535,"children":1536},{"style":686},[1537],{"type":56,"value":744},{"type":29,"tag":127,"props":1539,"children":1540},{"style":718},[1541],{"type":56,"value":1542},"/var/run/docker.sock:/var/run/docker.sock:ro\n",{"type":29,"tag":127,"props":1544,"children":1546},{"class":675,"line":1545},28,[1547,1551],{"type":29,"tag":127,"props":1548,"children":1549},{"style":686},[1550],{"type":56,"value":744},{"type":29,"tag":127,"props":1552,"children":1553},{"style":718},[1554],{"type":56,"value":1555},"/letsencrypt:/letsencrypt\n",{"type":29,"tag":48,"props":1557,"children":1558},{},[1559],{"type":56,"value":1560},"Let's explain this a little",{"type":29,"tag":960,"props":1562,"children":1563},{},[1564,1577,1582,1587,1592],{"type":29,"tag":812,"props":1565,"children":1566},{},[1567,1569,1575],{"type":56,"value":1568},"We configure a ",{"type":29,"tag":643,"props":1570,"children":1572},{"href":1571},"https://letsencrypt.org/",[1573],{"type":56,"value":1574},"Let's Encrypt",{"type":56,"value":1576}," certificates resolvers (11-14)",{"type":29,"tag":812,"props":1578,"children":1579},{},[1580],{"type":56,"value":1581},"We listen on port 80 and 443 (16-17)",{"type":29,"tag":812,"props":1583,"children":1584},{},[1585],{"type":56,"value":1586},"We redirect all http traffic to https (19-20)",{"type":29,"tag":812,"props":1588,"children":1589},{},[1590],{"type":56,"value":1591},"and attach the configured certificates resolvers to it (21)",{"type":29,"tag":812,"props":1593,"children":1594},{},[1595],{"type":56,"value":1596},"We setup the docker provider (23-25)",{"type":29,"tag":122,"props":1598,"children":1600},{"id":1599},"explanation-for-lines-24-25",[1601],{"type":56,"value":1602},"Explanation for lines 24-25",{"type":29,"tag":657,"props":1604,"children":1606},{"code":1605},"--providers.docker.defaultrule=Host(`{{ trimPrefix 'app-'.Name }}.example.com`)\n",[1607],{"type":29,"tag":670,"props":1608,"children":1609},{"__ignoreMap":7},[1610],{"type":56,"value":1605},{"type":29,"tag":808,"props":1612,"children":1613},{},[1614,1646],{"type":29,"tag":812,"props":1615,"children":1616},{},[1617,1623,1625,1631,1633,1638,1640],{"type":29,"tag":670,"props":1618,"children":1620},{"className":1619},[],[1621],{"type":56,"value":1622},".Name",{"type":56,"value":1624}," is autogenerated as ",{"type":29,"tag":670,"props":1626,"children":1628},{"className":1627},[],[1629],{"type":56,"value":1630},"\u003Cservice-name>-\u003Cstack_name>",{"type":56,"value":1632}," so for your ",{"type":29,"tag":670,"props":1634,"children":1636},{"className":1635},[],[1637],{"type":56,"value":820},{"type":56,"value":1639}," example it would be ",{"type":29,"tag":670,"props":1641,"children":1643},{"className":1642},[],[1644],{"type":56,"value":1645},"app-whoami",{"type":29,"tag":812,"props":1647,"children":1648},{},[1649,1655,1657],{"type":29,"tag":670,"props":1650,"children":1652},{"className":1651},[],[1653],{"type":56,"value":1654},"trimPrefix 'app-'.Name",{"type":56,"value":1656}," resolves in ",{"type":29,"tag":670,"props":1658,"children":1660},{"className":1659},[],[1661],{"type":56,"value":820},{"type":29,"tag":1663,"props":1664,"children":1665},"br",{},[],{"type":29,"tag":657,"props":1667,"children":1668},{"code":1516},[1669],{"type":29,"tag":670,"props":1670,"children":1671},{"__ignoreMap":7},[1672],{"type":56,"value":1516},{"type":29,"tag":48,"props":1674,"children":1675},{},[1676,1678,1683,1685,1691,1693,1699],{"type":56,"value":1677},"All services should be exposed by default but should be filtered down, only to ",{"type":29,"tag":670,"props":1679,"children":1681},{"className":1680},[],[1682],{"type":56,"value":1123},{"type":56,"value":1684}," services. The label ",{"type":29,"tag":670,"props":1686,"children":1688},{"className":1687},[],[1689],{"type":56,"value":1690},"com.docker.compose.service",{"type":56,"value":1692}," is added by ",{"type":29,"tag":670,"props":1694,"children":1696},{"className":1695},[],[1697],{"type":56,"value":1698},"docker-compose",{"type":56,"value":1700}," to all containers .",{"type":29,"tag":90,"props":1702,"children":1704},{"id":1703},"bonus-configuration",[1705],{"type":56,"value":1706},"Bonus configuration",{"type":29,"tag":48,"props":1708,"children":1709},{},[1710],{"type":56,"value":1711},"We can tweak this configuration even more.",{"type":29,"tag":122,"props":1713,"children":1715},{"id":1714},"exposing-other-services-in-the-stack",[1716],{"type":56,"value":1717},"Exposing other services in the stack",{"type":29,"tag":48,"props":1719,"children":1720},{},[1721],{"type":56,"value":1722},"Sometimes you want to expose more than just the app container.",{"type":29,"tag":48,"props":1724,"children":1725},{},[1726,1728,1733],{"type":56,"value":1727},"The current configuration won't route traffic to any other services other than ",{"type":29,"tag":670,"props":1729,"children":1731},{"className":1730},[],[1732],{"type":56,"value":1123},{"type":56,"value":1734},".\nTo still be able to use the default configuration method, we need to re-enable it.",{"type":29,"tag":657,"props":1736,"children":1738},{"code":1737},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`) || Label(`traefik.enable`, `true`)\n",[1739],{"type":29,"tag":670,"props":1740,"children":1741},{"__ignoreMap":7},[1742],{"type":56,"value":1737},{"type":29,"tag":122,"props":1744,"children":1746},{"id":1745},"stack-name-other-than-directory-name",[1747],{"type":56,"value":1748},"Stack name other than directory name",{"type":29,"tag":48,"props":1750,"children":1751},{},[1752,1754,1759],{"type":56,"value":1753},"When deploying the stacks, the name is generated based on directory name where the ",{"type":29,"tag":670,"props":1755,"children":1757},{"className":1756},[],[1758],{"type":56,"value":956},{"type":56,"value":1760}," file is located.\nWe can change the make in several ways, but here is the easiest one:",{"type":29,"tag":657,"props":1762,"children":1766},{"code":1763,"filename":1764,"highlights":1765,"language":508,"meta":7,"className":667,"style":7},"name: whoami\nservices:\n  app:\n    image: traefik/whoami\n","whoami-example/docker-compose.yaml",[676],[1767],{"type":29,"tag":670,"props":1768,"children":1769},{"__ignoreMap":7},[1770,1788,1799,1810],{"type":29,"tag":127,"props":1771,"children":1773},{"class":1772,"line":676},[675,738],[1774,1779,1783],{"type":29,"tag":127,"props":1775,"children":1776},{"style":680},[1777],{"type":56,"value":1778},"name",{"type":29,"tag":127,"props":1780,"children":1781},{"style":686},[1782],{"type":56,"value":715},{"type":29,"tag":127,"props":1784,"children":1785},{"style":718},[1786],{"type":56,"value":1787},"whoami\n",{"type":29,"tag":127,"props":1789,"children":1790},{"class":675,"line":342},[1791,1795],{"type":29,"tag":127,"props":1792,"children":1793},{"style":680},[1794],{"type":56,"value":683},{"type":29,"tag":127,"props":1796,"children":1797},{"style":686},[1798],{"type":56,"value":689},{"type":29,"tag":127,"props":1800,"children":1801},{"class":675,"line":704},[1802,1806],{"type":29,"tag":127,"props":1803,"children":1804},{"style":680},[1805],{"type":56,"value":1163},{"type":29,"tag":127,"props":1807,"children":1808},{"style":686},[1809],{"type":56,"value":689},{"type":29,"tag":127,"props":1811,"children":1812},{"class":675,"line":724},[1813,1817,1821],{"type":29,"tag":127,"props":1814,"children":1815},{"style":680},[1816],{"type":56,"value":710},{"type":29,"tag":127,"props":1818,"children":1819},{"style":686},[1820],{"type":56,"value":715},{"type":29,"tag":127,"props":1822,"children":1823},{"style":718},[1824],{"type":56,"value":721},{"type":29,"tag":1826,"props":1827,"children":1828},"style",{},[1829],{"type":56,"value":1830},"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":342,"depth":342,"links":1832},[1833,1834,1837],{"id":884,"depth":342,"text":887},{"id":980,"depth":342,"text":983,"children":1835},[1836],{"id":1599,"depth":704,"text":1602},{"id":1703,"depth":342,"text":1706,"children":1838},[1839,1840],{"id":1714,"depth":704,"text":1717},{"id":1745,"depth":704,"text":1748},{"_path":530,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":531,"description":532,"author":518,"image":519,"releaseDate":533,"blogCategories":1842,"articleTags":1843,"tags":1844,"body":1845,"_type":346,"_id":539,"_source":348,"_file":540,"_stem":541,"_extension":351},[522,523],[523,536,537],[461,24],{"type":26,"children":1846,"toc":6230},[1847,1854,1859,1871,1876,1881,1917,1922,1928,1933,1939,1951,3001,3006,3033,3043,3046,3059,3082,3217,3229,3234,3240,3252,3272,3674,3715,3720,3741,3883,3895,3901,3912,3917,3929,3964,3969,4896,4901,5000,5005,5064,5075,5080,5101,5236,5246,5252,5273,5276,5279,5285,5291,5296,5312,5362,5518,5524,5529,5540,5553,5776,6181,6186,6226],{"type":29,"tag":61,"props":1848,"children":1853},{"alt":7,"aspect-ratio":1849,"height":1850,"object-fit":1851,"src":1852},"1.78",300,"fill","/blog/shopware-plugin-release.png",[],{"type":29,"tag":48,"props":1855,"children":1856},{},[1857],{"type":56,"value":1858},"There are many ways to install Shopware 6 plugins. You can download them directly in the admin panel or install them with composer.",{"type":29,"tag":48,"props":1860,"children":1861},{},[1862,1864,1870],{"type":56,"value":1863},"There is a detailed comparison in the ",{"type":29,"tag":643,"props":1865,"children":1867},{"href":1866},"https://developer.shopware.com/docs/guides/plugins/plugins/",[1868],{"type":56,"value":1869},"official documentation",{"type":56,"value":916},{"type":29,"tag":48,"props":1872,"children":1873},{},[1874],{"type":56,"value":1875},"As a developer and maintainer of themes, customizations, third part API's, etc., I'm focused on Static Plugins.",{"type":29,"tag":48,"props":1877,"children":1878},{},[1879],{"type":56,"value":1880},"The workflow is simple:",{"type":29,"tag":960,"props":1882,"children":1883},{},[1884,1895,1906],{"type":29,"tag":812,"props":1885,"children":1886},{},[1887,1889],{"type":56,"value":1888},"Create a plugin with ",{"type":29,"tag":670,"props":1890,"children":1892},{"className":1891},[],[1893],{"type":56,"value":1894},"bin/console plugin:create --static",{"type":29,"tag":812,"props":1896,"children":1897},{},[1898,1900],{"type":56,"value":1899},"Require it with ",{"type":29,"tag":643,"props":1901,"children":1903},{"href":1902},"https://developer.shopware.com/docs/guides/plugins/plugins/#static-plugins",[1904],{"type":56,"value":1905},"composer",{"type":29,"tag":812,"props":1907,"children":1908},{},[1909,1911],{"type":56,"value":1910},"Build the project with ",{"type":29,"tag":643,"props":1912,"children":1914},{"href":1913},"https://developer.shopware.com/docs/products/cli/project-commands/build.html#example-docker-image",[1915],{"type":56,"value":1916},"shopware-cli",{"type":29,"tag":48,"props":1918,"children":1919},{},[1920],{"type":56,"value":1921},"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":29,"tag":90,"props":1923,"children":1925},{"id":1924},"extracting-the-plugin",[1926],{"type":56,"value":1927},"Extracting the plugin",{"type":29,"tag":48,"props":1929,"children":1930},{},[1931],{"type":56,"value":1932},"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":29,"tag":122,"props":1934,"children":1936},{"id":1935},"download-with-git",[1937],{"type":56,"value":1938},"Download with git",{"type":29,"tag":48,"props":1940,"children":1941},{},[1942,1944,1949],{"type":56,"value":1943},"We just need to tell ",{"type":29,"tag":670,"props":1945,"children":1947},{"className":1946},[],[1948],{"type":56,"value":1905},{"type":56,"value":1950}," where to find our plugin",{"type":29,"tag":657,"props":1952,"children":1961},{"className":1953,"code":1954,"filename":1955,"highlights":1956,"language":454,"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",[1957,1958,1959,1960],36,37,38,39,[1962],{"type":29,"tag":670,"props":1963,"children":1964},{"__ignoreMap":7},[1965,1973,1997,2018,2039,2052,2073,2094,2115,2136,2156,2176,2193,2201,2214,2222,2243,2264,2276,2294,2302,2310,2317,2336,2356,2367,2382,2389,2396,2404,2424,2445,2457,2473,2481,2489,2497,2518,2535,2544,2553,2566,2579,2608,2616,2624,2645,2658,2671,2692,2709,2717,2738,2755,2763,2776,2789,2807,2815,2828,2837,2846,2859,2867,2876,2884,2897,2910,2931,2944,2957,2966,2975,2983,2992],{"type":29,"tag":127,"props":1966,"children":1967},{"class":675,"line":676},[1968],{"type":29,"tag":127,"props":1969,"children":1970},{"style":686},[1971],{"type":56,"value":1972},"{\n",{"type":29,"tag":127,"props":1974,"children":1975},{"class":675,"line":342},[1976,1982,1986,1992],{"type":29,"tag":127,"props":1977,"children":1979},{"style":1978},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic",[1980],{"type":56,"value":1981},"  \"name\"",{"type":29,"tag":127,"props":1983,"children":1984},{"style":686},[1985],{"type":56,"value":715},{"type":29,"tag":127,"props":1987,"children":1989},{"style":1988},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#CFCFC2",[1990],{"type":56,"value":1991},"\"shopware/production\"",{"type":29,"tag":127,"props":1993,"children":1994},{"style":686},[1995],{"type":56,"value":1996},",\n",{"type":29,"tag":127,"props":1998,"children":1999},{"class":675,"line":704},[2000,2005,2009,2014],{"type":29,"tag":127,"props":2001,"children":2002},{"style":1978},[2003],{"type":56,"value":2004},"  \"license\"",{"type":29,"tag":127,"props":2006,"children":2007},{"style":686},[2008],{"type":56,"value":715},{"type":29,"tag":127,"props":2010,"children":2011},{"style":1988},[2012],{"type":56,"value":2013},"\"MIT\"",{"type":29,"tag":127,"props":2015,"children":2016},{"style":686},[2017],{"type":56,"value":1996},{"type":29,"tag":127,"props":2019,"children":2020},{"class":675,"line":724},[2021,2026,2030,2035],{"type":29,"tag":127,"props":2022,"children":2023},{"style":1978},[2024],{"type":56,"value":2025},"  \"type\"",{"type":29,"tag":127,"props":2027,"children":2028},{"style":686},[2029],{"type":56,"value":715},{"type":29,"tag":127,"props":2031,"children":2032},{"style":1988},[2033],{"type":56,"value":2034},"\"project\"",{"type":29,"tag":127,"props":2036,"children":2037},{"style":686},[2038],{"type":56,"value":1996},{"type":29,"tag":127,"props":2040,"children":2041},{"class":675,"line":662},[2042,2047],{"type":29,"tag":127,"props":2043,"children":2044},{"style":1978},[2045],{"type":56,"value":2046},"  \"require\"",{"type":29,"tag":127,"props":2048,"children":2049},{"style":686},[2050],{"type":56,"value":2051},": {\n",{"type":29,"tag":127,"props":2053,"children":2054},{"class":675,"line":663},[2055,2060,2064,2069],{"type":29,"tag":127,"props":2056,"children":2057},{"style":1978},[2058],{"type":56,"value":2059},"    \"composer-runtime-api\"",{"type":29,"tag":127,"props":2061,"children":2062},{"style":686},[2063],{"type":56,"value":715},{"type":29,"tag":127,"props":2065,"children":2066},{"style":1988},[2067],{"type":56,"value":2068},"\"^2.0\"",{"type":29,"tag":127,"props":2070,"children":2071},{"style":686},[2072],{"type":56,"value":1996},{"type":29,"tag":127,"props":2074,"children":2075},{"class":675,"line":664},[2076,2081,2085,2090],{"type":29,"tag":127,"props":2077,"children":2078},{"style":1978},[2079],{"type":56,"value":2080},"    \"acme/sample-plugin\"",{"type":29,"tag":127,"props":2082,"children":2083},{"style":686},[2084],{"type":56,"value":715},{"type":29,"tag":127,"props":2086,"children":2087},{"style":1988},[2088],{"type":56,"value":2089},"\"^1.0\"",{"type":29,"tag":127,"props":2091,"children":2092},{"style":686},[2093],{"type":56,"value":1996},{"type":29,"tag":127,"props":2095,"children":2096},{"class":675,"line":665},[2097,2102,2106,2111],{"type":29,"tag":127,"props":2098,"children":2099},{"style":1978},[2100],{"type":56,"value":2101},"    \"shopware/administration\"",{"type":29,"tag":127,"props":2103,"children":2104},{"style":686},[2105],{"type":56,"value":715},{"type":29,"tag":127,"props":2107,"children":2108},{"style":1988},[2109],{"type":56,"value":2110},"\"*\"",{"type":29,"tag":127,"props":2112,"children":2113},{"style":686},[2114],{"type":56,"value":1996},{"type":29,"tag":127,"props":2116,"children":2117},{"class":675,"line":666},[2118,2123,2127,2132],{"type":29,"tag":127,"props":2119,"children":2120},{"style":1978},[2121],{"type":56,"value":2122},"    \"shopware/core\"",{"type":29,"tag":127,"props":2124,"children":2125},{"style":686},[2126],{"type":56,"value":715},{"type":29,"tag":127,"props":2128,"children":2129},{"style":1988},[2130],{"type":56,"value":2131},"\"6.6.10.2\"",{"type":29,"tag":127,"props":2133,"children":2134},{"style":686},[2135],{"type":56,"value":1996},{"type":29,"tag":127,"props":2137,"children":2138},{"class":675,"line":1325},[2139,2144,2148,2152],{"type":29,"tag":127,"props":2140,"children":2141},{"style":1978},[2142],{"type":56,"value":2143},"    \"shopware/elasticsearch\"",{"type":29,"tag":127,"props":2145,"children":2146},{"style":686},[2147],{"type":56,"value":715},{"type":29,"tag":127,"props":2149,"children":2150},{"style":1988},[2151],{"type":56,"value":2110},{"type":29,"tag":127,"props":2153,"children":2154},{"style":686},[2155],{"type":56,"value":1996},{"type":29,"tag":127,"props":2157,"children":2158},{"class":675,"line":1338},[2159,2164,2168,2172],{"type":29,"tag":127,"props":2160,"children":2161},{"style":1978},[2162],{"type":56,"value":2163},"    \"shopware/storefront\"",{"type":29,"tag":127,"props":2165,"children":2166},{"style":686},[2167],{"type":56,"value":715},{"type":29,"tag":127,"props":2169,"children":2170},{"style":1988},[2171],{"type":56,"value":2110},{"type":29,"tag":127,"props":2173,"children":2174},{"style":686},[2175],{"type":56,"value":1996},{"type":29,"tag":127,"props":2177,"children":2178},{"class":675,"line":118},[2179,2184,2188],{"type":29,"tag":127,"props":2180,"children":2181},{"style":1978},[2182],{"type":56,"value":2183},"    \"symfony/flex\"",{"type":29,"tag":127,"props":2185,"children":2186},{"style":686},[2187],{"type":56,"value":715},{"type":29,"tag":127,"props":2189,"children":2190},{"style":1988},[2191],{"type":56,"value":2192},"\"~2\"\n",{"type":29,"tag":127,"props":2194,"children":2195},{"class":675,"line":1363},[2196],{"type":29,"tag":127,"props":2197,"children":2198},{"style":686},[2199],{"type":56,"value":2200},"  },\n",{"type":29,"tag":127,"props":2202,"children":2203},{"class":675,"line":1376},[2204,2209],{"type":29,"tag":127,"props":2205,"children":2206},{"style":1978},[2207],{"type":56,"value":2208},"  \"repositories\"",{"type":29,"tag":127,"props":2210,"children":2211},{"style":686},[2212],{"type":56,"value":2213},": [\n",{"type":29,"tag":127,"props":2215,"children":2216},{"class":675,"line":1389},[2217],{"type":29,"tag":127,"props":2218,"children":2219},{"style":686},[2220],{"type":56,"value":2221},"    {\n",{"type":29,"tag":127,"props":2223,"children":2224},{"class":675,"line":1398},[2225,2230,2234,2239],{"type":29,"tag":127,"props":2226,"children":2227},{"style":1978},[2228],{"type":56,"value":2229},"      \"type\"",{"type":29,"tag":127,"props":2231,"children":2232},{"style":686},[2233],{"type":56,"value":715},{"type":29,"tag":127,"props":2235,"children":2236},{"style":1988},[2237],{"type":56,"value":2238},"\"path\"",{"type":29,"tag":127,"props":2240,"children":2241},{"style":686},[2242],{"type":56,"value":1996},{"type":29,"tag":127,"props":2244,"children":2245},{"class":675,"line":1411},[2246,2251,2255,2260],{"type":29,"tag":127,"props":2247,"children":2248},{"style":1978},[2249],{"type":56,"value":2250},"      \"url\"",{"type":29,"tag":127,"props":2252,"children":2253},{"style":686},[2254],{"type":56,"value":715},{"type":29,"tag":127,"props":2256,"children":2257},{"style":1988},[2258],{"type":56,"value":2259},"\"custom/plugins/*\"",{"type":29,"tag":127,"props":2261,"children":2262},{"style":686},[2263],{"type":56,"value":1996},{"type":29,"tag":127,"props":2265,"children":2266},{"class":675,"line":1424},[2267,2272],{"type":29,"tag":127,"props":2268,"children":2269},{"style":1978},[2270],{"type":56,"value":2271},"      \"options\"",{"type":29,"tag":127,"props":2273,"children":2274},{"style":686},[2275],{"type":56,"value":2051},{"type":29,"tag":127,"props":2277,"children":2278},{"class":675,"line":1433},[2279,2284,2288],{"type":29,"tag":127,"props":2280,"children":2281},{"style":1978},[2282],{"type":56,"value":2283},"        \"symlink\"",{"type":29,"tag":127,"props":2285,"children":2286},{"style":686},[2287],{"type":56,"value":715},{"type":29,"tag":127,"props":2289,"children":2291},{"style":2290},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF",[2292],{"type":56,"value":2293},"true\n",{"type":29,"tag":127,"props":2295,"children":2296},{"class":675,"line":1446},[2297],{"type":29,"tag":127,"props":2298,"children":2299},{"style":686},[2300],{"type":56,"value":2301},"      }\n",{"type":29,"tag":127,"props":2303,"children":2304},{"class":675,"line":1459},[2305],{"type":29,"tag":127,"props":2306,"children":2307},{"style":686},[2308],{"type":56,"value":2309},"    },\n",{"type":29,"tag":127,"props":2311,"children":2312},{"class":675,"line":1472},[2313],{"type":29,"tag":127,"props":2314,"children":2315},{"style":686},[2316],{"type":56,"value":2221},{"type":29,"tag":127,"props":2318,"children":2319},{"class":675,"line":1480},[2320,2324,2328,2332],{"type":29,"tag":127,"props":2321,"children":2322},{"style":1978},[2323],{"type":56,"value":2229},{"type":29,"tag":127,"props":2325,"children":2326},{"style":686},[2327],{"type":56,"value":715},{"type":29,"tag":127,"props":2329,"children":2330},{"style":1988},[2331],{"type":56,"value":2238},{"type":29,"tag":127,"props":2333,"children":2334},{"style":686},[2335],{"type":56,"value":1996},{"type":29,"tag":127,"props":2337,"children":2338},{"class":675,"line":1493},[2339,2343,2347,2352],{"type":29,"tag":127,"props":2340,"children":2341},{"style":1978},[2342],{"type":56,"value":2250},{"type":29,"tag":127,"props":2344,"children":2345},{"style":686},[2346],{"type":56,"value":715},{"type":29,"tag":127,"props":2348,"children":2349},{"style":1988},[2350],{"type":56,"value":2351},"\"custom/plugins/*/packages/*\"",{"type":29,"tag":127,"props":2353,"children":2354},{"style":686},[2355],{"type":56,"value":1996},{"type":29,"tag":127,"props":2357,"children":2358},{"class":675,"line":1506},[2359,2363],{"type":29,"tag":127,"props":2360,"children":2361},{"style":1978},[2362],{"type":56,"value":2271},{"type":29,"tag":127,"props":2364,"children":2365},{"style":686},[2366],{"type":56,"value":2051},{"type":29,"tag":127,"props":2368,"children":2369},{"class":675,"line":1519},[2370,2374,2378],{"type":29,"tag":127,"props":2371,"children":2372},{"style":1978},[2373],{"type":56,"value":2283},{"type":29,"tag":127,"props":2375,"children":2376},{"style":686},[2377],{"type":56,"value":715},{"type":29,"tag":127,"props":2379,"children":2380},{"style":2290},[2381],{"type":56,"value":2293},{"type":29,"tag":127,"props":2383,"children":2384},{"class":675,"line":1532},[2385],{"type":29,"tag":127,"props":2386,"children":2387},{"style":686},[2388],{"type":56,"value":2301},{"type":29,"tag":127,"props":2390,"children":2391},{"class":675,"line":1545},[2392],{"type":29,"tag":127,"props":2393,"children":2394},{"style":686},[2395],{"type":56,"value":2309},{"type":29,"tag":127,"props":2397,"children":2399},{"class":675,"line":2398},29,[2400],{"type":29,"tag":127,"props":2401,"children":2402},{"style":686},[2403],{"type":56,"value":2221},{"type":29,"tag":127,"props":2405,"children":2407},{"class":675,"line":2406},30,[2408,2412,2416,2420],{"type":29,"tag":127,"props":2409,"children":2410},{"style":1978},[2411],{"type":56,"value":2229},{"type":29,"tag":127,"props":2413,"children":2414},{"style":686},[2415],{"type":56,"value":715},{"type":29,"tag":127,"props":2417,"children":2418},{"style":1988},[2419],{"type":56,"value":2238},{"type":29,"tag":127,"props":2421,"children":2422},{"style":686},[2423],{"type":56,"value":1996},{"type":29,"tag":127,"props":2425,"children":2427},{"class":675,"line":2426},31,[2428,2432,2436,2441],{"type":29,"tag":127,"props":2429,"children":2430},{"style":1978},[2431],{"type":56,"value":2250},{"type":29,"tag":127,"props":2433,"children":2434},{"style":686},[2435],{"type":56,"value":715},{"type":29,"tag":127,"props":2437,"children":2438},{"style":1988},[2439],{"type":56,"value":2440},"\"custom/static-plugins/*\"",{"type":29,"tag":127,"props":2442,"children":2443},{"style":686},[2444],{"type":56,"value":1996},{"type":29,"tag":127,"props":2446,"children":2448},{"class":675,"line":2447},32,[2449,2453],{"type":29,"tag":127,"props":2450,"children":2451},{"style":1978},[2452],{"type":56,"value":2271},{"type":29,"tag":127,"props":2454,"children":2455},{"style":686},[2456],{"type":56,"value":2051},{"type":29,"tag":127,"props":2458,"children":2460},{"class":675,"line":2459},33,[2461,2465,2469],{"type":29,"tag":127,"props":2462,"children":2463},{"style":1978},[2464],{"type":56,"value":2283},{"type":29,"tag":127,"props":2466,"children":2467},{"style":686},[2468],{"type":56,"value":715},{"type":29,"tag":127,"props":2470,"children":2471},{"style":2290},[2472],{"type":56,"value":2293},{"type":29,"tag":127,"props":2474,"children":2476},{"class":675,"line":2475},34,[2477],{"type":29,"tag":127,"props":2478,"children":2479},{"style":686},[2480],{"type":56,"value":2301},{"type":29,"tag":127,"props":2482,"children":2484},{"class":675,"line":2483},35,[2485],{"type":29,"tag":127,"props":2486,"children":2487},{"style":686},[2488],{"type":56,"value":2309},{"type":29,"tag":127,"props":2490,"children":2492},{"class":2491,"line":1957},[675,738],[2493],{"type":29,"tag":127,"props":2494,"children":2495},{"style":686},[2496],{"type":56,"value":2221},{"type":29,"tag":127,"props":2498,"children":2500},{"class":2499,"line":1958},[675,738],[2501,2505,2509,2514],{"type":29,"tag":127,"props":2502,"children":2503},{"style":1978},[2504],{"type":56,"value":2229},{"type":29,"tag":127,"props":2506,"children":2507},{"style":686},[2508],{"type":56,"value":715},{"type":29,"tag":127,"props":2510,"children":2511},{"style":1988},[2512],{"type":56,"value":2513},"\"git\"",{"type":29,"tag":127,"props":2515,"children":2516},{"style":686},[2517],{"type":56,"value":1996},{"type":29,"tag":127,"props":2519,"children":2521},{"class":2520,"line":1959},[675,738],[2522,2526,2530],{"type":29,"tag":127,"props":2523,"children":2524},{"style":1978},[2525],{"type":56,"value":2250},{"type":29,"tag":127,"props":2527,"children":2528},{"style":686},[2529],{"type":56,"value":715},{"type":29,"tag":127,"props":2531,"children":2532},{"style":1988},[2533],{"type":56,"value":2534},"\"https://\u003CDOMAIN-NAME>/\u003Cgroup>/\u003Crepo>.git\"\n",{"type":29,"tag":127,"props":2536,"children":2538},{"class":2537,"line":1960},[675,738],[2539],{"type":29,"tag":127,"props":2540,"children":2541},{"style":686},[2542],{"type":56,"value":2543},"    }\n",{"type":29,"tag":127,"props":2545,"children":2547},{"class":675,"line":2546},40,[2548],{"type":29,"tag":127,"props":2549,"children":2550},{"style":686},[2551],{"type":56,"value":2552},"  ],\n",{"type":29,"tag":127,"props":2554,"children":2556},{"class":675,"line":2555},41,[2557,2562],{"type":29,"tag":127,"props":2558,"children":2559},{"style":1978},[2560],{"type":56,"value":2561},"  \"autoload\"",{"type":29,"tag":127,"props":2563,"children":2564},{"style":686},[2565],{"type":56,"value":2051},{"type":29,"tag":127,"props":2567,"children":2569},{"class":675,"line":2568},42,[2570,2575],{"type":29,"tag":127,"props":2571,"children":2572},{"style":1978},[2573],{"type":56,"value":2574},"    \"psr-4\"",{"type":29,"tag":127,"props":2576,"children":2577},{"style":686},[2578],{"type":56,"value":2051},{"type":29,"tag":127,"props":2580,"children":2582},{"class":675,"line":2581},43,[2583,2588,2594,2599,2603],{"type":29,"tag":127,"props":2584,"children":2585},{"style":1978},[2586],{"type":56,"value":2587},"      \"App",{"type":29,"tag":127,"props":2589,"children":2591},{"style":2590},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#AE81FF;--shiki-sepia-font-style:italic",[2592],{"type":56,"value":2593},"\\\\",{"type":29,"tag":127,"props":2595,"children":2596},{"style":1978},[2597],{"type":56,"value":2598},"\"",{"type":29,"tag":127,"props":2600,"children":2601},{"style":686},[2602],{"type":56,"value":715},{"type":29,"tag":127,"props":2604,"children":2605},{"style":1988},[2606],{"type":56,"value":2607},"\"src/\"\n",{"type":29,"tag":127,"props":2609,"children":2611},{"class":675,"line":2610},44,[2612],{"type":29,"tag":127,"props":2613,"children":2614},{"style":686},[2615],{"type":56,"value":2543},{"type":29,"tag":127,"props":2617,"children":2619},{"class":675,"line":2618},45,[2620],{"type":29,"tag":127,"props":2621,"children":2622},{"style":686},[2623],{"type":56,"value":2200},{"type":29,"tag":127,"props":2625,"children":2627},{"class":675,"line":2626},46,[2628,2633,2637,2641],{"type":29,"tag":127,"props":2629,"children":2630},{"style":1978},[2631],{"type":56,"value":2632},"  \"prefer-stable\"",{"type":29,"tag":127,"props":2634,"children":2635},{"style":686},[2636],{"type":56,"value":715},{"type":29,"tag":127,"props":2638,"children":2639},{"style":2290},[2640],{"type":56,"value":113},{"type":29,"tag":127,"props":2642,"children":2643},{"style":686},[2644],{"type":56,"value":1996},{"type":29,"tag":127,"props":2646,"children":2648},{"class":675,"line":2647},47,[2649,2654],{"type":29,"tag":127,"props":2650,"children":2651},{"style":1978},[2652],{"type":56,"value":2653},"  \"config\"",{"type":29,"tag":127,"props":2655,"children":2656},{"style":686},[2657],{"type":56,"value":2051},{"type":29,"tag":127,"props":2659,"children":2661},{"class":675,"line":2660},48,[2662,2667],{"type":29,"tag":127,"props":2663,"children":2664},{"style":1978},[2665],{"type":56,"value":2666},"    \"allow-plugins\"",{"type":29,"tag":127,"props":2668,"children":2669},{"style":686},[2670],{"type":56,"value":2051},{"type":29,"tag":127,"props":2672,"children":2674},{"class":675,"line":2673},49,[2675,2680,2684,2688],{"type":29,"tag":127,"props":2676,"children":2677},{"style":1978},[2678],{"type":56,"value":2679},"      \"symfony/flex\"",{"type":29,"tag":127,"props":2681,"children":2682},{"style":686},[2683],{"type":56,"value":715},{"type":29,"tag":127,"props":2685,"children":2686},{"style":2290},[2687],{"type":56,"value":113},{"type":29,"tag":127,"props":2689,"children":2690},{"style":686},[2691],{"type":56,"value":1996},{"type":29,"tag":127,"props":2693,"children":2695},{"class":675,"line":2694},50,[2696,2701,2705],{"type":29,"tag":127,"props":2697,"children":2698},{"style":1978},[2699],{"type":56,"value":2700},"      \"symfony/runtime\"",{"type":29,"tag":127,"props":2702,"children":2703},{"style":686},[2704],{"type":56,"value":715},{"type":29,"tag":127,"props":2706,"children":2707},{"style":2290},[2708],{"type":56,"value":2293},{"type":29,"tag":127,"props":2710,"children":2712},{"class":675,"line":2711},51,[2713],{"type":29,"tag":127,"props":2714,"children":2715},{"style":686},[2716],{"type":56,"value":2309},{"type":29,"tag":127,"props":2718,"children":2720},{"class":675,"line":2719},52,[2721,2726,2730,2734],{"type":29,"tag":127,"props":2722,"children":2723},{"style":1978},[2724],{"type":56,"value":2725},"    \"optimize-autoloader\"",{"type":29,"tag":127,"props":2727,"children":2728},{"style":686},[2729],{"type":56,"value":715},{"type":29,"tag":127,"props":2731,"children":2732},{"style":2290},[2733],{"type":56,"value":113},{"type":29,"tag":127,"props":2735,"children":2736},{"style":686},[2737],{"type":56,"value":1996},{"type":29,"tag":127,"props":2739,"children":2741},{"class":675,"line":2740},53,[2742,2747,2751],{"type":29,"tag":127,"props":2743,"children":2744},{"style":1978},[2745],{"type":56,"value":2746},"    \"sort-packages\"",{"type":29,"tag":127,"props":2748,"children":2749},{"style":686},[2750],{"type":56,"value":715},{"type":29,"tag":127,"props":2752,"children":2753},{"style":2290},[2754],{"type":56,"value":2293},{"type":29,"tag":127,"props":2756,"children":2758},{"class":675,"line":2757},54,[2759],{"type":29,"tag":127,"props":2760,"children":2761},{"style":686},[2762],{"type":56,"value":2200},{"type":29,"tag":127,"props":2764,"children":2766},{"class":675,"line":2765},55,[2767,2772],{"type":29,"tag":127,"props":2768,"children":2769},{"style":1978},[2770],{"type":56,"value":2771},"  \"scripts\"",{"type":29,"tag":127,"props":2773,"children":2774},{"style":686},[2775],{"type":56,"value":2051},{"type":29,"tag":127,"props":2777,"children":2779},{"class":675,"line":2778},56,[2780,2785],{"type":29,"tag":127,"props":2781,"children":2782},{"style":1978},[2783],{"type":56,"value":2784},"    \"auto-scripts\"",{"type":29,"tag":127,"props":2786,"children":2787},{"style":686},[2788],{"type":56,"value":2051},{"type":29,"tag":127,"props":2790,"children":2792},{"class":675,"line":2791},57,[2793,2798,2802],{"type":29,"tag":127,"props":2794,"children":2795},{"style":1978},[2796],{"type":56,"value":2797},"      \"assets:install\"",{"type":29,"tag":127,"props":2799,"children":2800},{"style":686},[2801],{"type":56,"value":715},{"type":29,"tag":127,"props":2803,"children":2804},{"style":1988},[2805],{"type":56,"value":2806},"\"symfony-cmd\"\n",{"type":29,"tag":127,"props":2808,"children":2810},{"class":675,"line":2809},58,[2811],{"type":29,"tag":127,"props":2812,"children":2813},{"style":686},[2814],{"type":56,"value":2309},{"type":29,"tag":127,"props":2816,"children":2818},{"class":675,"line":2817},59,[2819,2824],{"type":29,"tag":127,"props":2820,"children":2821},{"style":1978},[2822],{"type":56,"value":2823},"    \"post-install-cmd\"",{"type":29,"tag":127,"props":2825,"children":2826},{"style":686},[2827],{"type":56,"value":2213},{"type":29,"tag":127,"props":2829,"children":2831},{"class":675,"line":2830},60,[2832],{"type":29,"tag":127,"props":2833,"children":2834},{"style":1988},[2835],{"type":56,"value":2836},"      \"@auto-scripts\"\n",{"type":29,"tag":127,"props":2838,"children":2840},{"class":675,"line":2839},61,[2841],{"type":29,"tag":127,"props":2842,"children":2843},{"style":686},[2844],{"type":56,"value":2845},"    ],\n",{"type":29,"tag":127,"props":2847,"children":2849},{"class":675,"line":2848},62,[2850,2855],{"type":29,"tag":127,"props":2851,"children":2852},{"style":1978},[2853],{"type":56,"value":2854},"    \"post-update-cmd\"",{"type":29,"tag":127,"props":2856,"children":2857},{"style":686},[2858],{"type":56,"value":2213},{"type":29,"tag":127,"props":2860,"children":2862},{"class":675,"line":2861},63,[2863],{"type":29,"tag":127,"props":2864,"children":2865},{"style":1988},[2866],{"type":56,"value":2836},{"type":29,"tag":127,"props":2868,"children":2870},{"class":675,"line":2869},64,[2871],{"type":29,"tag":127,"props":2872,"children":2873},{"style":686},[2874],{"type":56,"value":2875},"    ]\n",{"type":29,"tag":127,"props":2877,"children":2879},{"class":675,"line":2878},65,[2880],{"type":29,"tag":127,"props":2881,"children":2882},{"style":686},[2883],{"type":56,"value":2200},{"type":29,"tag":127,"props":2885,"children":2887},{"class":675,"line":2886},66,[2888,2893],{"type":29,"tag":127,"props":2889,"children":2890},{"style":1978},[2891],{"type":56,"value":2892},"  \"extra\"",{"type":29,"tag":127,"props":2894,"children":2895},{"style":686},[2896],{"type":56,"value":2051},{"type":29,"tag":127,"props":2898,"children":2900},{"class":675,"line":2899},67,[2901,2906],{"type":29,"tag":127,"props":2902,"children":2903},{"style":1978},[2904],{"type":56,"value":2905},"    \"symfony\"",{"type":29,"tag":127,"props":2907,"children":2908},{"style":686},[2909],{"type":56,"value":2051},{"type":29,"tag":127,"props":2911,"children":2913},{"class":675,"line":2912},68,[2914,2919,2923,2927],{"type":29,"tag":127,"props":2915,"children":2916},{"style":1978},[2917],{"type":56,"value":2918},"      \"allow-contrib\"",{"type":29,"tag":127,"props":2920,"children":2921},{"style":686},[2922],{"type":56,"value":715},{"type":29,"tag":127,"props":2924,"children":2925},{"style":2290},[2926],{"type":56,"value":113},{"type":29,"tag":127,"props":2928,"children":2929},{"style":686},[2930],{"type":56,"value":1996},{"type":29,"tag":127,"props":2932,"children":2934},{"class":675,"line":2933},69,[2935,2940],{"type":29,"tag":127,"props":2936,"children":2937},{"style":1978},[2938],{"type":56,"value":2939},"      \"endpoint\"",{"type":29,"tag":127,"props":2941,"children":2942},{"style":686},[2943],{"type":56,"value":2213},{"type":29,"tag":127,"props":2945,"children":2947},{"class":675,"line":2946},70,[2948,2953],{"type":29,"tag":127,"props":2949,"children":2950},{"style":1988},[2951],{"type":56,"value":2952},"        \"https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json\"",{"type":29,"tag":127,"props":2954,"children":2955},{"style":686},[2956],{"type":56,"value":1996},{"type":29,"tag":127,"props":2958,"children":2960},{"class":675,"line":2959},71,[2961],{"type":29,"tag":127,"props":2962,"children":2963},{"style":1988},[2964],{"type":56,"value":2965},"        \"flex://defaults\"\n",{"type":29,"tag":127,"props":2967,"children":2969},{"class":675,"line":2968},72,[2970],{"type":29,"tag":127,"props":2971,"children":2972},{"style":686},[2973],{"type":56,"value":2974},"      ]\n",{"type":29,"tag":127,"props":2976,"children":2978},{"class":675,"line":2977},73,[2979],{"type":29,"tag":127,"props":2980,"children":2981},{"style":686},[2982],{"type":56,"value":2543},{"type":29,"tag":127,"props":2984,"children":2986},{"class":675,"line":2985},74,[2987],{"type":29,"tag":127,"props":2988,"children":2989},{"style":686},[2990],{"type":56,"value":2991},"  }\n",{"type":29,"tag":127,"props":2993,"children":2995},{"class":675,"line":2994},75,[2996],{"type":29,"tag":127,"props":2997,"children":2998},{"style":686},[2999],{"type":56,"value":3000},"}\n",{"type":29,"tag":48,"props":3002,"children":3003},{},[3004],{"type":56,"value":3005},"and require it with",{"type":29,"tag":657,"props":3007,"children":3011},{"className":3008,"code":3009,"language":3010,"meta":7,"style":7},"language-shell shiki shiki-themes github-dark github-dark monokai","composer req acme/sample-plugin\n","shell",[3012],{"type":29,"tag":670,"props":3013,"children":3014},{"__ignoreMap":7},[3015],{"type":29,"tag":127,"props":3016,"children":3017},{"class":675,"line":676},[3018,3023,3028],{"type":29,"tag":127,"props":3019,"children":3021},{"style":3020},"--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E",[3022],{"type":56,"value":1905},{"type":29,"tag":127,"props":3024,"children":3025},{"style":718},[3026],{"type":56,"value":3027}," req",{"type":29,"tag":127,"props":3029,"children":3030},{"style":718},[3031],{"type":56,"value":3032}," acme/sample-plugin\n",{"type":29,"tag":3034,"props":3035,"children":3037},"v-alert",{"type":3036},"error",[3038],{"type":29,"tag":48,"props":3039,"children":3040},{},[3041],{"type":56,"value":3042},"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":29,"tag":1663,"props":3044,"children":3045},{},[],{"type":29,"tag":48,"props":3047,"children":3048},{},[3049,3051,3057],{"type":56,"value":3050},"Yes... this is the downside. We need to use ",{"type":29,"tag":670,"props":3052,"children":3054},{"className":3053},[],[3055],{"type":56,"value":3056},"dev-master",{"type":56,"value":3058}," as a version",{"type":29,"tag":657,"props":3060,"children":3062},{"className":3008,"code":3061,"language":3010,"meta":7,"style":7},"composer req acme/sample-plugin:dev-master\n",[3063],{"type":29,"tag":670,"props":3064,"children":3065},{"__ignoreMap":7},[3066],{"type":29,"tag":127,"props":3067,"children":3068},{"class":675,"line":676},[3069,3073,3077],{"type":29,"tag":127,"props":3070,"children":3071},{"style":3020},[3072],{"type":56,"value":1905},{"type":29,"tag":127,"props":3074,"children":3075},{"style":718},[3076],{"type":56,"value":3027},{"type":29,"tag":127,"props":3078,"children":3079},{"style":718},[3080],{"type":56,"value":3081}," acme/sample-plugin:dev-master\n",{"type":29,"tag":657,"props":3083,"children":3087},{"className":3084,"code":3085,"language":3086,"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",[3088],{"type":29,"tag":670,"props":3089,"children":3090},{"__ignoreMap":7},[3091,3099,3107,3115,3123,3131,3139,3147,3155,3163,3171,3179,3187,3194,3202,3209],{"type":29,"tag":127,"props":3092,"children":3093},{"class":675,"line":676},[3094],{"type":29,"tag":127,"props":3095,"children":3096},{},[3097],{"type":56,"value":3098},"./composer.json has been updated\n",{"type":29,"tag":127,"props":3100,"children":3101},{"class":675,"line":342},[3102],{"type":29,"tag":127,"props":3103,"children":3104},{},[3105],{"type":56,"value":3106},"Running composer update acme/sample-plugin\n",{"type":29,"tag":127,"props":3108,"children":3109},{"class":675,"line":704},[3110],{"type":29,"tag":127,"props":3111,"children":3112},{},[3113],{"type":56,"value":3114},"Loading composer repositories with package information                                                                \n",{"type":29,"tag":127,"props":3116,"children":3117},{"class":675,"line":724},[3118],{"type":29,"tag":127,"props":3119,"children":3120},{},[3121],{"type":56,"value":3122},"Updating dependencies                                 \n",{"type":29,"tag":127,"props":3124,"children":3125},{"class":675,"line":662},[3126],{"type":29,"tag":127,"props":3127,"children":3128},{},[3129],{"type":56,"value":3130},"Lock file operations: 1 install, 0 updates, 0 removals\n",{"type":29,"tag":127,"props":3132,"children":3133},{"class":675,"line":663},[3134],{"type":29,"tag":127,"props":3135,"children":3136},{},[3137],{"type":56,"value":3138},"  - Locking acme/sample-plugin (dev-master 294414d)\n",{"type":29,"tag":127,"props":3140,"children":3141},{"class":675,"line":664},[3142],{"type":29,"tag":127,"props":3143,"children":3144},{},[3145],{"type":56,"value":3146},"Writing lock file\n",{"type":29,"tag":127,"props":3148,"children":3149},{"class":675,"line":665},[3150],{"type":29,"tag":127,"props":3151,"children":3152},{},[3153],{"type":56,"value":3154},"Installing dependencies from lock file (including require-dev)\n",{"type":29,"tag":127,"props":3156,"children":3157},{"class":675,"line":666},[3158],{"type":29,"tag":127,"props":3159,"children":3160},{},[3161],{"type":56,"value":3162},"Package operations: 1 install, 0 updates, 0 removals\n",{"type":29,"tag":127,"props":3164,"children":3165},{"class":675,"line":1325},[3166],{"type":29,"tag":127,"props":3167,"children":3168},{},[3169],{"type":56,"value":3170},"  - Syncing acme/sample-plugin (dev-master 294414d) into cache\n",{"type":29,"tag":127,"props":3172,"children":3173},{"class":675,"line":1338},[3174],{"type":29,"tag":127,"props":3175,"children":3176},{},[3177],{"type":56,"value":3178},"  - Installing acme/sample-plugin (dev-master 294414d): Cloning 294414deb2 from cache\n",{"type":29,"tag":127,"props":3180,"children":3181},{"class":675,"line":118},[3182],{"type":29,"tag":127,"props":3183,"children":3184},{},[3185],{"type":56,"value":3186},"Generating optimized autoload files\n",{"type":29,"tag":127,"props":3188,"children":3189},{"class":675,"line":1363},[3190],{"type":29,"tag":127,"props":3191,"children":3192},{"emptyLinePlaceholder":500},[3193],{"type":56,"value":1395},{"type":29,"tag":127,"props":3195,"children":3196},{"class":675,"line":1376},[3197],{"type":29,"tag":127,"props":3198,"children":3199},{},[3200],{"type":56,"value":3201},"Run composer recipes at any time to see the status of your Symfony recipes.\n",{"type":29,"tag":127,"props":3203,"children":3204},{"class":675,"line":1389},[3205],{"type":29,"tag":127,"props":3206,"children":3207},{"emptyLinePlaceholder":500},[3208],{"type":56,"value":1395},{"type":29,"tag":127,"props":3210,"children":3211},{"class":675,"line":1398},[3212],{"type":29,"tag":127,"props":3213,"children":3214},{},[3215],{"type":56,"value":3216},"Executing script assets:install [OK]\n",{"type":29,"tag":48,"props":3218,"children":3219},{},[3220,3222,3227],{"type":56,"value":3221},"Composer will use ",{"type":29,"tag":670,"props":3223,"children":3225},{"className":3224},[],[3226],{"type":56,"value":906},{"type":56,"value":3228}," to clone our repo and use the default branch and the commit hash to track the release.",{"type":29,"tag":48,"props":3230,"children":3231},{},[3232],{"type":56,"value":3233},"This works, but we can do better.",{"type":29,"tag":122,"props":3235,"children":3237},{"id":3236},"git-tags",[3238],{"type":56,"value":3239},"Git tags",{"type":29,"tag":48,"props":3241,"children":3242},{},[3243,3245,3251],{"type":56,"value":3244},"Let's tag our plugin with ",{"type":29,"tag":670,"props":3246,"children":3248},{"className":3247},[],[3249],{"type":56,"value":3250},"v1.0.0",{"type":56,"value":916},{"type":29,"tag":48,"props":3253,"children":3254},{},[3255,3257,3263,3265,3271],{"type":56,"value":3256},"Make sure to set the ",{"type":29,"tag":670,"props":3258,"children":3260},{"className":3259},[],[3261],{"type":56,"value":3262},"version",{"type":56,"value":3264}," in ",{"type":29,"tag":670,"props":3266,"children":3268},{"className":3267},[],[3269],{"type":56,"value":3270},"composer.json",{"type":56,"value":916},{"type":29,"tag":657,"props":3273,"children":3277},{"className":1953,"code":3274,"filename":3275,"highlights":3276,"language":454,"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",[662],[3278],{"type":29,"tag":670,"props":3279,"children":3280},{"__ignoreMap":7},[3281,3288,3309,3329,3350,3372,3392,3404,3421,3428,3440,3470,3482,3503,3520,3528,3535,3547,3559,3583,3590,3597,3609,3620,3653,3660,3667],{"type":29,"tag":127,"props":3282,"children":3283},{"class":675,"line":676},[3284],{"type":29,"tag":127,"props":3285,"children":3286},{"style":686},[3287],{"type":56,"value":1972},{"type":29,"tag":127,"props":3289,"children":3290},{"class":675,"line":342},[3291,3296,3300,3305],{"type":29,"tag":127,"props":3292,"children":3293},{"style":1978},[3294],{"type":56,"value":3295},"    \"name\"",{"type":29,"tag":127,"props":3297,"children":3298},{"style":686},[3299],{"type":56,"value":715},{"type":29,"tag":127,"props":3301,"children":3302},{"style":1988},[3303],{"type":56,"value":3304},"\"acme/sample-plugin\"",{"type":29,"tag":127,"props":3306,"children":3307},{"style":686},[3308],{"type":56,"value":1996},{"type":29,"tag":127,"props":3310,"children":3311},{"class":675,"line":704},[3312,3317,3321,3325],{"type":29,"tag":127,"props":3313,"children":3314},{"style":1978},[3315],{"type":56,"value":3316},"    \"description\"",{"type":29,"tag":127,"props":3318,"children":3319},{"style":686},[3320],{"type":56,"value":715},{"type":29,"tag":127,"props":3322,"children":3323},{"style":1988},[3324],{"type":56,"value":3304},{"type":29,"tag":127,"props":3326,"children":3327},{"style":686},[3328],{"type":56,"value":1996},{"type":29,"tag":127,"props":3330,"children":3331},{"class":675,"line":724},[3332,3337,3341,3346],{"type":29,"tag":127,"props":3333,"children":3334},{"style":1978},[3335],{"type":56,"value":3336},"    \"type\"",{"type":29,"tag":127,"props":3338,"children":3339},{"style":686},[3340],{"type":56,"value":715},{"type":29,"tag":127,"props":3342,"children":3343},{"style":1988},[3344],{"type":56,"value":3345},"\"shopware-platform-plugin\"",{"type":29,"tag":127,"props":3347,"children":3348},{"style":686},[3349],{"type":56,"value":1996},{"type":29,"tag":127,"props":3351,"children":3353},{"class":3352,"line":662},[675,738],[3354,3359,3363,3368],{"type":29,"tag":127,"props":3355,"children":3356},{"style":1978},[3357],{"type":56,"value":3358},"    \"version\"",{"type":29,"tag":127,"props":3360,"children":3361},{"style":686},[3362],{"type":56,"value":715},{"type":29,"tag":127,"props":3364,"children":3365},{"style":1988},[3366],{"type":56,"value":3367},"\"1.0.0\"",{"type":29,"tag":127,"props":3369,"children":3370},{"style":686},[3371],{"type":56,"value":1996},{"type":29,"tag":127,"props":3373,"children":3374},{"class":675,"line":663},[3375,3380,3384,3388],{"type":29,"tag":127,"props":3376,"children":3377},{"style":1978},[3378],{"type":56,"value":3379},"    \"license\"",{"type":29,"tag":127,"props":3381,"children":3382},{"style":686},[3383],{"type":56,"value":715},{"type":29,"tag":127,"props":3385,"children":3386},{"style":1988},[3387],{"type":56,"value":2013},{"type":29,"tag":127,"props":3389,"children":3390},{"style":686},[3391],{"type":56,"value":1996},{"type":29,"tag":127,"props":3393,"children":3394},{"class":675,"line":664},[3395,3400],{"type":29,"tag":127,"props":3396,"children":3397},{"style":1978},[3398],{"type":56,"value":3399},"    \"require\"",{"type":29,"tag":127,"props":3401,"children":3402},{"style":686},[3403],{"type":56,"value":2051},{"type":29,"tag":127,"props":3405,"children":3406},{"class":675,"line":665},[3407,3412,3416],{"type":29,"tag":127,"props":3408,"children":3409},{"style":1978},[3410],{"type":56,"value":3411},"        \"shopware/core\"",{"type":29,"tag":127,"props":3413,"children":3414},{"style":686},[3415],{"type":56,"value":715},{"type":29,"tag":127,"props":3417,"children":3418},{"style":1988},[3419],{"type":56,"value":3420},"\"~6.6.0\"\n",{"type":29,"tag":127,"props":3422,"children":3423},{"class":675,"line":666},[3424],{"type":29,"tag":127,"props":3425,"children":3426},{"style":686},[3427],{"type":56,"value":2309},{"type":29,"tag":127,"props":3429,"children":3430},{"class":675,"line":1325},[3431,3436],{"type":29,"tag":127,"props":3432,"children":3433},{"style":1978},[3434],{"type":56,"value":3435},"    \"extra\"",{"type":29,"tag":127,"props":3437,"children":3438},{"style":686},[3439],{"type":56,"value":2051},{"type":29,"tag":127,"props":3441,"children":3442},{"class":675,"line":1338},[3443,3448,3452,3457,3461,3466],{"type":29,"tag":127,"props":3444,"children":3445},{"style":1978},[3446],{"type":56,"value":3447},"        \"shopware-plugin-class\"",{"type":29,"tag":127,"props":3449,"children":3450},{"style":686},[3451],{"type":56,"value":715},{"type":29,"tag":127,"props":3453,"children":3454},{"style":1988},[3455],{"type":56,"value":3456},"\"Acme",{"type":29,"tag":127,"props":3458,"children":3459},{"style":2290},[3460],{"type":56,"value":2593},{"type":29,"tag":127,"props":3462,"children":3463},{"style":1988},[3464],{"type":56,"value":3465},"SamplePlugin\"",{"type":29,"tag":127,"props":3467,"children":3468},{"style":686},[3469],{"type":56,"value":1996},{"type":29,"tag":127,"props":3471,"children":3472},{"class":675,"line":118},[3473,3478],{"type":29,"tag":127,"props":3474,"children":3475},{"style":1978},[3476],{"type":56,"value":3477},"        \"label\"",{"type":29,"tag":127,"props":3479,"children":3480},{"style":686},[3481],{"type":56,"value":2051},{"type":29,"tag":127,"props":3483,"children":3484},{"class":675,"line":1363},[3485,3490,3494,3499],{"type":29,"tag":127,"props":3486,"children":3487},{"style":1978},[3488],{"type":56,"value":3489},"            \"de-DE\"",{"type":29,"tag":127,"props":3491,"children":3492},{"style":686},[3493],{"type":56,"value":715},{"type":29,"tag":127,"props":3495,"children":3496},{"style":1988},[3497],{"type":56,"value":3498},"\"Skeleton plugin\"",{"type":29,"tag":127,"props":3500,"children":3501},{"style":686},[3502],{"type":56,"value":1996},{"type":29,"tag":127,"props":3504,"children":3505},{"class":675,"line":1376},[3506,3511,3515],{"type":29,"tag":127,"props":3507,"children":3508},{"style":1978},[3509],{"type":56,"value":3510},"            \"en-GB\"",{"type":29,"tag":127,"props":3512,"children":3513},{"style":686},[3514],{"type":56,"value":715},{"type":29,"tag":127,"props":3516,"children":3517},{"style":1988},[3518],{"type":56,"value":3519},"\"Skeleton plugin\"\n",{"type":29,"tag":127,"props":3521,"children":3522},{"class":675,"line":1389},[3523],{"type":29,"tag":127,"props":3524,"children":3525},{"style":686},[3526],{"type":56,"value":3527},"        }\n",{"type":29,"tag":127,"props":3529,"children":3530},{"class":675,"line":1398},[3531],{"type":29,"tag":127,"props":3532,"children":3533},{"style":686},[3534],{"type":56,"value":2309},{"type":29,"tag":127,"props":3536,"children":3537},{"class":675,"line":1411},[3538,3543],{"type":29,"tag":127,"props":3539,"children":3540},{"style":1978},[3541],{"type":56,"value":3542},"    \"autoload\"",{"type":29,"tag":127,"props":3544,"children":3545},{"style":686},[3546],{"type":56,"value":2051},{"type":29,"tag":127,"props":3548,"children":3549},{"class":675,"line":1424},[3550,3555],{"type":29,"tag":127,"props":3551,"children":3552},{"style":1978},[3553],{"type":56,"value":3554},"        \"psr-4\"",{"type":29,"tag":127,"props":3556,"children":3557},{"style":686},[3558],{"type":56,"value":2051},{"type":29,"tag":127,"props":3560,"children":3561},{"class":675,"line":1433},[3562,3567,3571,3575,3579],{"type":29,"tag":127,"props":3563,"children":3564},{"style":1978},[3565],{"type":56,"value":3566},"            \"Acme",{"type":29,"tag":127,"props":3568,"children":3569},{"style":2590},[3570],{"type":56,"value":2593},{"type":29,"tag":127,"props":3572,"children":3573},{"style":1978},[3574],{"type":56,"value":2598},{"type":29,"tag":127,"props":3576,"children":3577},{"style":686},[3578],{"type":56,"value":715},{"type":29,"tag":127,"props":3580,"children":3581},{"style":1988},[3582],{"type":56,"value":2607},{"type":29,"tag":127,"props":3584,"children":3585},{"class":675,"line":1446},[3586],{"type":29,"tag":127,"props":3587,"children":3588},{"style":686},[3589],{"type":56,"value":3527},{"type":29,"tag":127,"props":3591,"children":3592},{"class":675,"line":1459},[3593],{"type":29,"tag":127,"props":3594,"children":3595},{"style":686},[3596],{"type":56,"value":2309},{"type":29,"tag":127,"props":3598,"children":3599},{"class":675,"line":1472},[3600,3605],{"type":29,"tag":127,"props":3601,"children":3602},{"style":1978},[3603],{"type":56,"value":3604},"    \"autoload-dev\"",{"type":29,"tag":127,"props":3606,"children":3607},{"style":686},[3608],{"type":56,"value":2051},{"type":29,"tag":127,"props":3610,"children":3611},{"class":675,"line":1480},[3612,3616],{"type":29,"tag":127,"props":3613,"children":3614},{"style":1978},[3615],{"type":56,"value":3554},{"type":29,"tag":127,"props":3617,"children":3618},{"style":686},[3619],{"type":56,"value":2051},{"type":29,"tag":127,"props":3621,"children":3622},{"class":675,"line":1493},[3623,3627,3631,3636,3640,3644,3648],{"type":29,"tag":127,"props":3624,"children":3625},{"style":1978},[3626],{"type":56,"value":3566},{"type":29,"tag":127,"props":3628,"children":3629},{"style":2590},[3630],{"type":56,"value":2593},{"type":29,"tag":127,"props":3632,"children":3633},{"style":1978},[3634],{"type":56,"value":3635},"Tests",{"type":29,"tag":127,"props":3637,"children":3638},{"style":2590},[3639],{"type":56,"value":2593},{"type":29,"tag":127,"props":3641,"children":3642},{"style":1978},[3643],{"type":56,"value":2598},{"type":29,"tag":127,"props":3645,"children":3646},{"style":686},[3647],{"type":56,"value":715},{"type":29,"tag":127,"props":3649,"children":3650},{"style":1988},[3651],{"type":56,"value":3652},"\"tests/\"\n",{"type":29,"tag":127,"props":3654,"children":3655},{"class":675,"line":1506},[3656],{"type":29,"tag":127,"props":3657,"children":3658},{"style":686},[3659],{"type":56,"value":3527},{"type":29,"tag":127,"props":3661,"children":3662},{"class":675,"line":1519},[3663],{"type":29,"tag":127,"props":3664,"children":3665},{"style":686},[3666],{"type":56,"value":2543},{"type":29,"tag":127,"props":3668,"children":3669},{"class":675,"line":1532},[3670],{"type":29,"tag":127,"props":3671,"children":3672},{"style":686},[3673],{"type":56,"value":3000},{"type":29,"tag":657,"props":3675,"children":3677},{"className":3008,"code":3676,"language":3010,"meta":7,"style":7},"git tag v1.0.0\ngit push --tags\n",[3678],{"type":29,"tag":670,"props":3679,"children":3680},{"__ignoreMap":7},[3681,3698],{"type":29,"tag":127,"props":3682,"children":3683},{"class":675,"line":676},[3684,3688,3693],{"type":29,"tag":127,"props":3685,"children":3686},{"style":3020},[3687],{"type":56,"value":906},{"type":29,"tag":127,"props":3689,"children":3690},{"style":718},[3691],{"type":56,"value":3692}," tag",{"type":29,"tag":127,"props":3694,"children":3695},{"style":718},[3696],{"type":56,"value":3697}," v1.0.0\n",{"type":29,"tag":127,"props":3699,"children":3700},{"class":675,"line":342},[3701,3705,3710],{"type":29,"tag":127,"props":3702,"children":3703},{"style":3020},[3704],{"type":56,"value":906},{"type":29,"tag":127,"props":3706,"children":3707},{"style":718},[3708],{"type":56,"value":3709}," push",{"type":29,"tag":127,"props":3711,"children":3712},{"style":2290},[3713],{"type":56,"value":3714}," --tags\n",{"type":29,"tag":48,"props":3716,"children":3717},{},[3718],{"type":56,"value":3719},"Now this will work:",{"type":29,"tag":657,"props":3721,"children":3722},{"className":3008,"code":3009,"language":3010,"meta":7,"style":7},[3723],{"type":29,"tag":670,"props":3724,"children":3725},{"__ignoreMap":7},[3726],{"type":29,"tag":127,"props":3727,"children":3728},{"class":675,"line":676},[3729,3733,3737],{"type":29,"tag":127,"props":3730,"children":3731},{"style":3020},[3732],{"type":56,"value":1905},{"type":29,"tag":127,"props":3734,"children":3735},{"style":718},[3736],{"type":56,"value":3027},{"type":29,"tag":127,"props":3738,"children":3739},{"style":718},[3740],{"type":56,"value":3032},{"type":29,"tag":657,"props":3742,"children":3746},{"className":3743,"code":3744,"language":3745,"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",[3747],{"type":29,"tag":670,"props":3748,"children":3749},{"__ignoreMap":7},[3750,3758,3765,3773,3781,3788,3796,3803,3810,3817,3825,3833,3840,3847,3854,3861,3868,3875],{"type":29,"tag":127,"props":3751,"children":3752},{"class":675,"line":676},[3753],{"type":29,"tag":127,"props":3754,"children":3755},{},[3756],{"type":56,"value":3757},"./composer.json has been updated                                                                                                            \n",{"type":29,"tag":127,"props":3759,"children":3760},{"class":675,"line":342},[3761],{"type":29,"tag":127,"props":3762,"children":3763},{},[3764],{"type":56,"value":3106},{"type":29,"tag":127,"props":3766,"children":3767},{"class":675,"line":704},[3768],{"type":29,"tag":127,"props":3769,"children":3770},{},[3771],{"type":56,"value":3772},"Loading composer repositories with package information\n",{"type":29,"tag":127,"props":3774,"children":3775},{"class":675,"line":724},[3776],{"type":29,"tag":127,"props":3777,"children":3778},{},[3779],{"type":56,"value":3780},"Updating dependencies\n",{"type":29,"tag":127,"props":3782,"children":3783},{"class":675,"line":662},[3784],{"type":29,"tag":127,"props":3785,"children":3786},{},[3787],{"type":56,"value":3130},{"type":29,"tag":127,"props":3789,"children":3790},{"class":675,"line":663},[3791],{"type":29,"tag":127,"props":3792,"children":3793},{},[3794],{"type":56,"value":3795},"  - Locking acme/sample-plugin (1.0.0)\n",{"type":29,"tag":127,"props":3797,"children":3798},{"class":675,"line":664},[3799],{"type":29,"tag":127,"props":3800,"children":3801},{},[3802],{"type":56,"value":3146},{"type":29,"tag":127,"props":3804,"children":3805},{"class":675,"line":665},[3806],{"type":29,"tag":127,"props":3807,"children":3808},{},[3809],{"type":56,"value":3154},{"type":29,"tag":127,"props":3811,"children":3812},{"class":675,"line":666},[3813],{"type":29,"tag":127,"props":3814,"children":3815},{},[3816],{"type":56,"value":3162},{"type":29,"tag":127,"props":3818,"children":3819},{"class":675,"line":1325},[3820],{"type":29,"tag":127,"props":3821,"children":3822},{},[3823],{"type":56,"value":3824},"  - Syncing acme/sample-plugin (1.0.0) into cache\n",{"type":29,"tag":127,"props":3826,"children":3827},{"class":675,"line":1338},[3828],{"type":29,"tag":127,"props":3829,"children":3830},{},[3831],{"type":56,"value":3832},"  - Installing acme/sample-plugin (1.0.0): Cloning 294414deb2 from cache\n",{"type":29,"tag":127,"props":3834,"children":3835},{"class":675,"line":118},[3836],{"type":29,"tag":127,"props":3837,"children":3838},{},[3839],{"type":56,"value":3186},{"type":29,"tag":127,"props":3841,"children":3842},{"class":675,"line":1363},[3843],{"type":29,"tag":127,"props":3844,"children":3845},{"emptyLinePlaceholder":500},[3846],{"type":56,"value":1395},{"type":29,"tag":127,"props":3848,"children":3849},{"class":675,"line":1376},[3850],{"type":29,"tag":127,"props":3851,"children":3852},{},[3853],{"type":56,"value":3201},{"type":29,"tag":127,"props":3855,"children":3856},{"class":675,"line":1389},[3857],{"type":29,"tag":127,"props":3858,"children":3859},{"emptyLinePlaceholder":500},[3860],{"type":56,"value":1395},{"type":29,"tag":127,"props":3862,"children":3863},{"class":675,"line":1398},[3864],{"type":29,"tag":127,"props":3865,"children":3866},{},[3867],{"type":56,"value":3216},{"type":29,"tag":127,"props":3869,"children":3870},{"class":675,"line":1411},[3871],{"type":29,"tag":127,"props":3872,"children":3873},{"emptyLinePlaceholder":500},[3874],{"type":56,"value":1395},{"type":29,"tag":127,"props":3876,"children":3877},{"class":675,"line":1424},[3878],{"type":29,"tag":127,"props":3879,"children":3880},{},[3881],{"type":56,"value":3882},"Using version ^1.0 for acme/sample-plugin\n",{"type":29,"tag":48,"props":3884,"children":3885},{},[3886,3888,3893],{"type":56,"value":3887},"This is better, but we are still using ",{"type":29,"tag":670,"props":3889,"children":3891},{"className":3890},[],[3892],{"type":56,"value":906},{"type":56,"value":3894}," to fetch the plugin. We can do better.",{"type":29,"tag":122,"props":3896,"children":3898},{"id":3897},"gitlab-package-registry",[3899],{"type":56,"value":3900},"GitLab Package registry",{"type":29,"tag":48,"props":3902,"children":3903},{},[3904,3906,3911],{"type":56,"value":3905},"Here is where the GitLab part starts. For more details refer to the ",{"type":29,"tag":643,"props":3907,"children":3909},{"href":3908},"https://docs.gitlab.com/18.3/user/packages/composer_repository/",[3910],{"type":56,"value":1869},{"type":56,"value":916},{"type":29,"tag":48,"props":3913,"children":3914},{},[3915],{"type":56,"value":3916},"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":29,"tag":48,"props":3918,"children":3919},{},[3920,3922,3927],{"type":56,"value":3921},"Let's release our ",{"type":29,"tag":670,"props":3923,"children":3925},{"className":3924},[],[3926],{"type":56,"value":3250},{"type":56,"value":3928}," tag as a composer package.",{"type":29,"tag":657,"props":3930,"children":3932},{"className":3008,"code":3931,"language":3010,"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",[3933],{"type":29,"tag":670,"props":3934,"children":3935},{"__ignoreMap":7},[3936],{"type":29,"tag":127,"props":3937,"children":3938},{"class":675,"line":676},[3939,3944,3949,3954,3959],{"type":29,"tag":127,"props":3940,"children":3941},{"style":3020},[3942],{"type":56,"value":3943},"curl",{"type":29,"tag":127,"props":3945,"children":3946},{"style":2290},[3947],{"type":56,"value":3948}," --fail-with-body",{"type":29,"tag":127,"props":3950,"children":3951},{"style":2290},[3952],{"type":56,"value":3953}," --data",{"type":29,"tag":127,"props":3955,"children":3956},{"style":718},[3957],{"type":56,"value":3958}," tag=v1.0.0",{"type":29,"tag":127,"props":3960,"children":3961},{"style":718},[3962],{"type":56,"value":3963}," \"https://__token__:\u003Cpersonal-access-token>@\u003CDOMAIN-NAME>/api/v4/projects/\u003Cproject_id>/packages/composer\"\n",{"type":29,"tag":48,"props":3965,"children":3966},{},[3967],{"type":56,"value":3968},"Now we need to update the repository information:",{"type":29,"tag":657,"props":3970,"children":3973},{"className":1953,"code":3971,"filename":1955,"highlights":3972,"language":454,"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",[1957,1958,1959,1960],[3974],{"type":29,"tag":670,"props":3975,"children":3976},{"__ignoreMap":7},[3977,3984,4003,4022,4041,4052,4071,4090,4109,4128,4147,4166,4181,4188,4199,4206,4225,4244,4255,4270,4277,4284,4291,4310,4329,4340,4355,4362,4369,4376,4395,4414,4425,4440,4447,4454,4462,4483,4500,4508,4515,4526,4537,4560,4567,4574,4593,4604,4615,4634,4649,4656,4675,4690,4697,4708,4719,4734,4741,4752,4759,4766,4777,4784,4791,4798,4809,4820,4839,4850,4861,4868,4875,4882,4889],{"type":29,"tag":127,"props":3978,"children":3979},{"class":675,"line":676},[3980],{"type":29,"tag":127,"props":3981,"children":3982},{"style":686},[3983],{"type":56,"value":1972},{"type":29,"tag":127,"props":3985,"children":3986},{"class":675,"line":342},[3987,3991,3995,3999],{"type":29,"tag":127,"props":3988,"children":3989},{"style":1978},[3990],{"type":56,"value":1981},{"type":29,"tag":127,"props":3992,"children":3993},{"style":686},[3994],{"type":56,"value":715},{"type":29,"tag":127,"props":3996,"children":3997},{"style":1988},[3998],{"type":56,"value":1991},{"type":29,"tag":127,"props":4000,"children":4001},{"style":686},[4002],{"type":56,"value":1996},{"type":29,"tag":127,"props":4004,"children":4005},{"class":675,"line":704},[4006,4010,4014,4018],{"type":29,"tag":127,"props":4007,"children":4008},{"style":1978},[4009],{"type":56,"value":2004},{"type":29,"tag":127,"props":4011,"children":4012},{"style":686},[4013],{"type":56,"value":715},{"type":29,"tag":127,"props":4015,"children":4016},{"style":1988},[4017],{"type":56,"value":2013},{"type":29,"tag":127,"props":4019,"children":4020},{"style":686},[4021],{"type":56,"value":1996},{"type":29,"tag":127,"props":4023,"children":4024},{"class":675,"line":724},[4025,4029,4033,4037],{"type":29,"tag":127,"props":4026,"children":4027},{"style":1978},[4028],{"type":56,"value":2025},{"type":29,"tag":127,"props":4030,"children":4031},{"style":686},[4032],{"type":56,"value":715},{"type":29,"tag":127,"props":4034,"children":4035},{"style":1988},[4036],{"type":56,"value":2034},{"type":29,"tag":127,"props":4038,"children":4039},{"style":686},[4040],{"type":56,"value":1996},{"type":29,"tag":127,"props":4042,"children":4043},{"class":675,"line":662},[4044,4048],{"type":29,"tag":127,"props":4045,"children":4046},{"style":1978},[4047],{"type":56,"value":2046},{"type":29,"tag":127,"props":4049,"children":4050},{"style":686},[4051],{"type":56,"value":2051},{"type":29,"tag":127,"props":4053,"children":4054},{"class":675,"line":663},[4055,4059,4063,4067],{"type":29,"tag":127,"props":4056,"children":4057},{"style":1978},[4058],{"type":56,"value":2059},{"type":29,"tag":127,"props":4060,"children":4061},{"style":686},[4062],{"type":56,"value":715},{"type":29,"tag":127,"props":4064,"children":4065},{"style":1988},[4066],{"type":56,"value":2068},{"type":29,"tag":127,"props":4068,"children":4069},{"style":686},[4070],{"type":56,"value":1996},{"type":29,"tag":127,"props":4072,"children":4073},{"class":675,"line":664},[4074,4078,4082,4086],{"type":29,"tag":127,"props":4075,"children":4076},{"style":1978},[4077],{"type":56,"value":2080},{"type":29,"tag":127,"props":4079,"children":4080},{"style":686},[4081],{"type":56,"value":715},{"type":29,"tag":127,"props":4083,"children":4084},{"style":1988},[4085],{"type":56,"value":2089},{"type":29,"tag":127,"props":4087,"children":4088},{"style":686},[4089],{"type":56,"value":1996},{"type":29,"tag":127,"props":4091,"children":4092},{"class":675,"line":665},[4093,4097,4101,4105],{"type":29,"tag":127,"props":4094,"children":4095},{"style":1978},[4096],{"type":56,"value":2101},{"type":29,"tag":127,"props":4098,"children":4099},{"style":686},[4100],{"type":56,"value":715},{"type":29,"tag":127,"props":4102,"children":4103},{"style":1988},[4104],{"type":56,"value":2110},{"type":29,"tag":127,"props":4106,"children":4107},{"style":686},[4108],{"type":56,"value":1996},{"type":29,"tag":127,"props":4110,"children":4111},{"class":675,"line":666},[4112,4116,4120,4124],{"type":29,"tag":127,"props":4113,"children":4114},{"style":1978},[4115],{"type":56,"value":2122},{"type":29,"tag":127,"props":4117,"children":4118},{"style":686},[4119],{"type":56,"value":715},{"type":29,"tag":127,"props":4121,"children":4122},{"style":1988},[4123],{"type":56,"value":2131},{"type":29,"tag":127,"props":4125,"children":4126},{"style":686},[4127],{"type":56,"value":1996},{"type":29,"tag":127,"props":4129,"children":4130},{"class":675,"line":1325},[4131,4135,4139,4143],{"type":29,"tag":127,"props":4132,"children":4133},{"style":1978},[4134],{"type":56,"value":2143},{"type":29,"tag":127,"props":4136,"children":4137},{"style":686},[4138],{"type":56,"value":715},{"type":29,"tag":127,"props":4140,"children":4141},{"style":1988},[4142],{"type":56,"value":2110},{"type":29,"tag":127,"props":4144,"children":4145},{"style":686},[4146],{"type":56,"value":1996},{"type":29,"tag":127,"props":4148,"children":4149},{"class":675,"line":1338},[4150,4154,4158,4162],{"type":29,"tag":127,"props":4151,"children":4152},{"style":1978},[4153],{"type":56,"value":2163},{"type":29,"tag":127,"props":4155,"children":4156},{"style":686},[4157],{"type":56,"value":715},{"type":29,"tag":127,"props":4159,"children":4160},{"style":1988},[4161],{"type":56,"value":2110},{"type":29,"tag":127,"props":4163,"children":4164},{"style":686},[4165],{"type":56,"value":1996},{"type":29,"tag":127,"props":4167,"children":4168},{"class":675,"line":118},[4169,4173,4177],{"type":29,"tag":127,"props":4170,"children":4171},{"style":1978},[4172],{"type":56,"value":2183},{"type":29,"tag":127,"props":4174,"children":4175},{"style":686},[4176],{"type":56,"value":715},{"type":29,"tag":127,"props":4178,"children":4179},{"style":1988},[4180],{"type":56,"value":2192},{"type":29,"tag":127,"props":4182,"children":4183},{"class":675,"line":1363},[4184],{"type":29,"tag":127,"props":4185,"children":4186},{"style":686},[4187],{"type":56,"value":2200},{"type":29,"tag":127,"props":4189,"children":4190},{"class":675,"line":1376},[4191,4195],{"type":29,"tag":127,"props":4192,"children":4193},{"style":1978},[4194],{"type":56,"value":2208},{"type":29,"tag":127,"props":4196,"children":4197},{"style":686},[4198],{"type":56,"value":2213},{"type":29,"tag":127,"props":4200,"children":4201},{"class":675,"line":1389},[4202],{"type":29,"tag":127,"props":4203,"children":4204},{"style":686},[4205],{"type":56,"value":2221},{"type":29,"tag":127,"props":4207,"children":4208},{"class":675,"line":1398},[4209,4213,4217,4221],{"type":29,"tag":127,"props":4210,"children":4211},{"style":1978},[4212],{"type":56,"value":2229},{"type":29,"tag":127,"props":4214,"children":4215},{"style":686},[4216],{"type":56,"value":715},{"type":29,"tag":127,"props":4218,"children":4219},{"style":1988},[4220],{"type":56,"value":2238},{"type":29,"tag":127,"props":4222,"children":4223},{"style":686},[4224],{"type":56,"value":1996},{"type":29,"tag":127,"props":4226,"children":4227},{"class":675,"line":1411},[4228,4232,4236,4240],{"type":29,"tag":127,"props":4229,"children":4230},{"style":1978},[4231],{"type":56,"value":2250},{"type":29,"tag":127,"props":4233,"children":4234},{"style":686},[4235],{"type":56,"value":715},{"type":29,"tag":127,"props":4237,"children":4238},{"style":1988},[4239],{"type":56,"value":2259},{"type":29,"tag":127,"props":4241,"children":4242},{"style":686},[4243],{"type":56,"value":1996},{"type":29,"tag":127,"props":4245,"children":4246},{"class":675,"line":1424},[4247,4251],{"type":29,"tag":127,"props":4248,"children":4249},{"style":1978},[4250],{"type":56,"value":2271},{"type":29,"tag":127,"props":4252,"children":4253},{"style":686},[4254],{"type":56,"value":2051},{"type":29,"tag":127,"props":4256,"children":4257},{"class":675,"line":1433},[4258,4262,4266],{"type":29,"tag":127,"props":4259,"children":4260},{"style":1978},[4261],{"type":56,"value":2283},{"type":29,"tag":127,"props":4263,"children":4264},{"style":686},[4265],{"type":56,"value":715},{"type":29,"tag":127,"props":4267,"children":4268},{"style":2290},[4269],{"type":56,"value":2293},{"type":29,"tag":127,"props":4271,"children":4272},{"class":675,"line":1446},[4273],{"type":29,"tag":127,"props":4274,"children":4275},{"style":686},[4276],{"type":56,"value":2301},{"type":29,"tag":127,"props":4278,"children":4279},{"class":675,"line":1459},[4280],{"type":29,"tag":127,"props":4281,"children":4282},{"style":686},[4283],{"type":56,"value":2309},{"type":29,"tag":127,"props":4285,"children":4286},{"class":675,"line":1472},[4287],{"type":29,"tag":127,"props":4288,"children":4289},{"style":686},[4290],{"type":56,"value":2221},{"type":29,"tag":127,"props":4292,"children":4293},{"class":675,"line":1480},[4294,4298,4302,4306],{"type":29,"tag":127,"props":4295,"children":4296},{"style":1978},[4297],{"type":56,"value":2229},{"type":29,"tag":127,"props":4299,"children":4300},{"style":686},[4301],{"type":56,"value":715},{"type":29,"tag":127,"props":4303,"children":4304},{"style":1988},[4305],{"type":56,"value":2238},{"type":29,"tag":127,"props":4307,"children":4308},{"style":686},[4309],{"type":56,"value":1996},{"type":29,"tag":127,"props":4311,"children":4312},{"class":675,"line":1493},[4313,4317,4321,4325],{"type":29,"tag":127,"props":4314,"children":4315},{"style":1978},[4316],{"type":56,"value":2250},{"type":29,"tag":127,"props":4318,"children":4319},{"style":686},[4320],{"type":56,"value":715},{"type":29,"tag":127,"props":4322,"children":4323},{"style":1988},[4324],{"type":56,"value":2351},{"type":29,"tag":127,"props":4326,"children":4327},{"style":686},[4328],{"type":56,"value":1996},{"type":29,"tag":127,"props":4330,"children":4331},{"class":675,"line":1506},[4332,4336],{"type":29,"tag":127,"props":4333,"children":4334},{"style":1978},[4335],{"type":56,"value":2271},{"type":29,"tag":127,"props":4337,"children":4338},{"style":686},[4339],{"type":56,"value":2051},{"type":29,"tag":127,"props":4341,"children":4342},{"class":675,"line":1519},[4343,4347,4351],{"type":29,"tag":127,"props":4344,"children":4345},{"style":1978},[4346],{"type":56,"value":2283},{"type":29,"tag":127,"props":4348,"children":4349},{"style":686},[4350],{"type":56,"value":715},{"type":29,"tag":127,"props":4352,"children":4353},{"style":2290},[4354],{"type":56,"value":2293},{"type":29,"tag":127,"props":4356,"children":4357},{"class":675,"line":1532},[4358],{"type":29,"tag":127,"props":4359,"children":4360},{"style":686},[4361],{"type":56,"value":2301},{"type":29,"tag":127,"props":4363,"children":4364},{"class":675,"line":1545},[4365],{"type":29,"tag":127,"props":4366,"children":4367},{"style":686},[4368],{"type":56,"value":2309},{"type":29,"tag":127,"props":4370,"children":4371},{"class":675,"line":2398},[4372],{"type":29,"tag":127,"props":4373,"children":4374},{"style":686},[4375],{"type":56,"value":2221},{"type":29,"tag":127,"props":4377,"children":4378},{"class":675,"line":2406},[4379,4383,4387,4391],{"type":29,"tag":127,"props":4380,"children":4381},{"style":1978},[4382],{"type":56,"value":2229},{"type":29,"tag":127,"props":4384,"children":4385},{"style":686},[4386],{"type":56,"value":715},{"type":29,"tag":127,"props":4388,"children":4389},{"style":1988},[4390],{"type":56,"value":2238},{"type":29,"tag":127,"props":4392,"children":4393},{"style":686},[4394],{"type":56,"value":1996},{"type":29,"tag":127,"props":4396,"children":4397},{"class":675,"line":2426},[4398,4402,4406,4410],{"type":29,"tag":127,"props":4399,"children":4400},{"style":1978},[4401],{"type":56,"value":2250},{"type":29,"tag":127,"props":4403,"children":4404},{"style":686},[4405],{"type":56,"value":715},{"type":29,"tag":127,"props":4407,"children":4408},{"style":1988},[4409],{"type":56,"value":2440},{"type":29,"tag":127,"props":4411,"children":4412},{"style":686},[4413],{"type":56,"value":1996},{"type":29,"tag":127,"props":4415,"children":4416},{"class":675,"line":2447},[4417,4421],{"type":29,"tag":127,"props":4418,"children":4419},{"style":1978},[4420],{"type":56,"value":2271},{"type":29,"tag":127,"props":4422,"children":4423},{"style":686},[4424],{"type":56,"value":2051},{"type":29,"tag":127,"props":4426,"children":4427},{"class":675,"line":2459},[4428,4432,4436],{"type":29,"tag":127,"props":4429,"children":4430},{"style":1978},[4431],{"type":56,"value":2283},{"type":29,"tag":127,"props":4433,"children":4434},{"style":686},[4435],{"type":56,"value":715},{"type":29,"tag":127,"props":4437,"children":4438},{"style":2290},[4439],{"type":56,"value":2293},{"type":29,"tag":127,"props":4441,"children":4442},{"class":675,"line":2475},[4443],{"type":29,"tag":127,"props":4444,"children":4445},{"style":686},[4446],{"type":56,"value":2301},{"type":29,"tag":127,"props":4448,"children":4449},{"class":675,"line":2483},[4450],{"type":29,"tag":127,"props":4451,"children":4452},{"style":686},[4453],{"type":56,"value":2309},{"type":29,"tag":127,"props":4455,"children":4457},{"class":4456,"line":1957},[675,738],[4458],{"type":29,"tag":127,"props":4459,"children":4460},{"style":686},[4461],{"type":56,"value":2221},{"type":29,"tag":127,"props":4463,"children":4465},{"class":4464,"line":1958},[675,738],[4466,4470,4474,4479],{"type":29,"tag":127,"props":4467,"children":4468},{"style":1978},[4469],{"type":56,"value":2229},{"type":29,"tag":127,"props":4471,"children":4472},{"style":686},[4473],{"type":56,"value":715},{"type":29,"tag":127,"props":4475,"children":4476},{"style":1988},[4477],{"type":56,"value":4478},"\"composer\"",{"type":29,"tag":127,"props":4480,"children":4481},{"style":686},[4482],{"type":56,"value":1996},{"type":29,"tag":127,"props":4484,"children":4486},{"class":4485,"line":1959},[675,738],[4487,4491,4495],{"type":29,"tag":127,"props":4488,"children":4489},{"style":1978},[4490],{"type":56,"value":2250},{"type":29,"tag":127,"props":4492,"children":4493},{"style":686},[4494],{"type":56,"value":715},{"type":29,"tag":127,"props":4496,"children":4497},{"style":1988},[4498],{"type":56,"value":4499},"\"https://\u003CDOMAIN-NAME>/api/v4/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\"\n",{"type":29,"tag":127,"props":4501,"children":4503},{"class":4502,"line":1960},[675,738],[4504],{"type":29,"tag":127,"props":4505,"children":4506},{"style":686},[4507],{"type":56,"value":2543},{"type":29,"tag":127,"props":4509,"children":4510},{"class":675,"line":2546},[4511],{"type":29,"tag":127,"props":4512,"children":4513},{"style":686},[4514],{"type":56,"value":2552},{"type":29,"tag":127,"props":4516,"children":4517},{"class":675,"line":2555},[4518,4522],{"type":29,"tag":127,"props":4519,"children":4520},{"style":1978},[4521],{"type":56,"value":2561},{"type":29,"tag":127,"props":4523,"children":4524},{"style":686},[4525],{"type":56,"value":2051},{"type":29,"tag":127,"props":4527,"children":4528},{"class":675,"line":2568},[4529,4533],{"type":29,"tag":127,"props":4530,"children":4531},{"style":1978},[4532],{"type":56,"value":2574},{"type":29,"tag":127,"props":4534,"children":4535},{"style":686},[4536],{"type":56,"value":2051},{"type":29,"tag":127,"props":4538,"children":4539},{"class":675,"line":2581},[4540,4544,4548,4552,4556],{"type":29,"tag":127,"props":4541,"children":4542},{"style":1978},[4543],{"type":56,"value":2587},{"type":29,"tag":127,"props":4545,"children":4546},{"style":2590},[4547],{"type":56,"value":2593},{"type":29,"tag":127,"props":4549,"children":4550},{"style":1978},[4551],{"type":56,"value":2598},{"type":29,"tag":127,"props":4553,"children":4554},{"style":686},[4555],{"type":56,"value":715},{"type":29,"tag":127,"props":4557,"children":4558},{"style":1988},[4559],{"type":56,"value":2607},{"type":29,"tag":127,"props":4561,"children":4562},{"class":675,"line":2610},[4563],{"type":29,"tag":127,"props":4564,"children":4565},{"style":686},[4566],{"type":56,"value":2543},{"type":29,"tag":127,"props":4568,"children":4569},{"class":675,"line":2618},[4570],{"type":29,"tag":127,"props":4571,"children":4572},{"style":686},[4573],{"type":56,"value":2200},{"type":29,"tag":127,"props":4575,"children":4576},{"class":675,"line":2626},[4577,4581,4585,4589],{"type":29,"tag":127,"props":4578,"children":4579},{"style":1978},[4580],{"type":56,"value":2632},{"type":29,"tag":127,"props":4582,"children":4583},{"style":686},[4584],{"type":56,"value":715},{"type":29,"tag":127,"props":4586,"children":4587},{"style":2290},[4588],{"type":56,"value":113},{"type":29,"tag":127,"props":4590,"children":4591},{"style":686},[4592],{"type":56,"value":1996},{"type":29,"tag":127,"props":4594,"children":4595},{"class":675,"line":2647},[4596,4600],{"type":29,"tag":127,"props":4597,"children":4598},{"style":1978},[4599],{"type":56,"value":2653},{"type":29,"tag":127,"props":4601,"children":4602},{"style":686},[4603],{"type":56,"value":2051},{"type":29,"tag":127,"props":4605,"children":4606},{"class":675,"line":2660},[4607,4611],{"type":29,"tag":127,"props":4608,"children":4609},{"style":1978},[4610],{"type":56,"value":2666},{"type":29,"tag":127,"props":4612,"children":4613},{"style":686},[4614],{"type":56,"value":2051},{"type":29,"tag":127,"props":4616,"children":4617},{"class":675,"line":2673},[4618,4622,4626,4630],{"type":29,"tag":127,"props":4619,"children":4620},{"style":1978},[4621],{"type":56,"value":2679},{"type":29,"tag":127,"props":4623,"children":4624},{"style":686},[4625],{"type":56,"value":715},{"type":29,"tag":127,"props":4627,"children":4628},{"style":2290},[4629],{"type":56,"value":113},{"type":29,"tag":127,"props":4631,"children":4632},{"style":686},[4633],{"type":56,"value":1996},{"type":29,"tag":127,"props":4635,"children":4636},{"class":675,"line":2694},[4637,4641,4645],{"type":29,"tag":127,"props":4638,"children":4639},{"style":1978},[4640],{"type":56,"value":2700},{"type":29,"tag":127,"props":4642,"children":4643},{"style":686},[4644],{"type":56,"value":715},{"type":29,"tag":127,"props":4646,"children":4647},{"style":2290},[4648],{"type":56,"value":2293},{"type":29,"tag":127,"props":4650,"children":4651},{"class":675,"line":2711},[4652],{"type":29,"tag":127,"props":4653,"children":4654},{"style":686},[4655],{"type":56,"value":2309},{"type":29,"tag":127,"props":4657,"children":4658},{"class":675,"line":2719},[4659,4663,4667,4671],{"type":29,"tag":127,"props":4660,"children":4661},{"style":1978},[4662],{"type":56,"value":2725},{"type":29,"tag":127,"props":4664,"children":4665},{"style":686},[4666],{"type":56,"value":715},{"type":29,"tag":127,"props":4668,"children":4669},{"style":2290},[4670],{"type":56,"value":113},{"type":29,"tag":127,"props":4672,"children":4673},{"style":686},[4674],{"type":56,"value":1996},{"type":29,"tag":127,"props":4676,"children":4677},{"class":675,"line":2740},[4678,4682,4686],{"type":29,"tag":127,"props":4679,"children":4680},{"style":1978},[4681],{"type":56,"value":2746},{"type":29,"tag":127,"props":4683,"children":4684},{"style":686},[4685],{"type":56,"value":715},{"type":29,"tag":127,"props":4687,"children":4688},{"style":2290},[4689],{"type":56,"value":2293},{"type":29,"tag":127,"props":4691,"children":4692},{"class":675,"line":2757},[4693],{"type":29,"tag":127,"props":4694,"children":4695},{"style":686},[4696],{"type":56,"value":2200},{"type":29,"tag":127,"props":4698,"children":4699},{"class":675,"line":2765},[4700,4704],{"type":29,"tag":127,"props":4701,"children":4702},{"style":1978},[4703],{"type":56,"value":2771},{"type":29,"tag":127,"props":4705,"children":4706},{"style":686},[4707],{"type":56,"value":2051},{"type":29,"tag":127,"props":4709,"children":4710},{"class":675,"line":2778},[4711,4715],{"type":29,"tag":127,"props":4712,"children":4713},{"style":1978},[4714],{"type":56,"value":2784},{"type":29,"tag":127,"props":4716,"children":4717},{"style":686},[4718],{"type":56,"value":2051},{"type":29,"tag":127,"props":4720,"children":4721},{"class":675,"line":2791},[4722,4726,4730],{"type":29,"tag":127,"props":4723,"children":4724},{"style":1978},[4725],{"type":56,"value":2797},{"type":29,"tag":127,"props":4727,"children":4728},{"style":686},[4729],{"type":56,"value":715},{"type":29,"tag":127,"props":4731,"children":4732},{"style":1988},[4733],{"type":56,"value":2806},{"type":29,"tag":127,"props":4735,"children":4736},{"class":675,"line":2809},[4737],{"type":29,"tag":127,"props":4738,"children":4739},{"style":686},[4740],{"type":56,"value":2309},{"type":29,"tag":127,"props":4742,"children":4743},{"class":675,"line":2817},[4744,4748],{"type":29,"tag":127,"props":4745,"children":4746},{"style":1978},[4747],{"type":56,"value":2823},{"type":29,"tag":127,"props":4749,"children":4750},{"style":686},[4751],{"type":56,"value":2213},{"type":29,"tag":127,"props":4753,"children":4754},{"class":675,"line":2830},[4755],{"type":29,"tag":127,"props":4756,"children":4757},{"style":1988},[4758],{"type":56,"value":2836},{"type":29,"tag":127,"props":4760,"children":4761},{"class":675,"line":2839},[4762],{"type":29,"tag":127,"props":4763,"children":4764},{"style":686},[4765],{"type":56,"value":2845},{"type":29,"tag":127,"props":4767,"children":4768},{"class":675,"line":2848},[4769,4773],{"type":29,"tag":127,"props":4770,"children":4771},{"style":1978},[4772],{"type":56,"value":2854},{"type":29,"tag":127,"props":4774,"children":4775},{"style":686},[4776],{"type":56,"value":2213},{"type":29,"tag":127,"props":4778,"children":4779},{"class":675,"line":2861},[4780],{"type":29,"tag":127,"props":4781,"children":4782},{"style":1988},[4783],{"type":56,"value":2836},{"type":29,"tag":127,"props":4785,"children":4786},{"class":675,"line":2869},[4787],{"type":29,"tag":127,"props":4788,"children":4789},{"style":686},[4790],{"type":56,"value":2875},{"type":29,"tag":127,"props":4792,"children":4793},{"class":675,"line":2878},[4794],{"type":29,"tag":127,"props":4795,"children":4796},{"style":686},[4797],{"type":56,"value":2200},{"type":29,"tag":127,"props":4799,"children":4800},{"class":675,"line":2886},[4801,4805],{"type":29,"tag":127,"props":4802,"children":4803},{"style":1978},[4804],{"type":56,"value":2892},{"type":29,"tag":127,"props":4806,"children":4807},{"style":686},[4808],{"type":56,"value":2051},{"type":29,"tag":127,"props":4810,"children":4811},{"class":675,"line":2899},[4812,4816],{"type":29,"tag":127,"props":4813,"children":4814},{"style":1978},[4815],{"type":56,"value":2905},{"type":29,"tag":127,"props":4817,"children":4818},{"style":686},[4819],{"type":56,"value":2051},{"type":29,"tag":127,"props":4821,"children":4822},{"class":675,"line":2912},[4823,4827,4831,4835],{"type":29,"tag":127,"props":4824,"children":4825},{"style":1978},[4826],{"type":56,"value":2918},{"type":29,"tag":127,"props":4828,"children":4829},{"style":686},[4830],{"type":56,"value":715},{"type":29,"tag":127,"props":4832,"children":4833},{"style":2290},[4834],{"type":56,"value":113},{"type":29,"tag":127,"props":4836,"children":4837},{"style":686},[4838],{"type":56,"value":1996},{"type":29,"tag":127,"props":4840,"children":4841},{"class":675,"line":2933},[4842,4846],{"type":29,"tag":127,"props":4843,"children":4844},{"style":1978},[4845],{"type":56,"value":2939},{"type":29,"tag":127,"props":4847,"children":4848},{"style":686},[4849],{"type":56,"value":2213},{"type":29,"tag":127,"props":4851,"children":4852},{"class":675,"line":2946},[4853,4857],{"type":29,"tag":127,"props":4854,"children":4855},{"style":1988},[4856],{"type":56,"value":2952},{"type":29,"tag":127,"props":4858,"children":4859},{"style":686},[4860],{"type":56,"value":1996},{"type":29,"tag":127,"props":4862,"children":4863},{"class":675,"line":2959},[4864],{"type":29,"tag":127,"props":4865,"children":4866},{"style":1988},[4867],{"type":56,"value":2965},{"type":29,"tag":127,"props":4869,"children":4870},{"class":675,"line":2968},[4871],{"type":29,"tag":127,"props":4872,"children":4873},{"style":686},[4874],{"type":56,"value":2974},{"type":29,"tag":127,"props":4876,"children":4877},{"class":675,"line":2977},[4878],{"type":29,"tag":127,"props":4879,"children":4880},{"style":686},[4881],{"type":56,"value":2543},{"type":29,"tag":127,"props":4883,"children":4884},{"class":675,"line":2985},[4885],{"type":29,"tag":127,"props":4886,"children":4887},{"style":686},[4888],{"type":56,"value":2991},{"type":29,"tag":127,"props":4890,"children":4891},{"class":675,"line":2994},[4892],{"type":29,"tag":127,"props":4893,"children":4894},{"style":686},[4895],{"type":56,"value":3000},{"type":29,"tag":48,"props":4897,"children":4898},{},[4899],{"type":56,"value":4900},"or by using the CLI:",{"type":29,"tag":657,"props":4902,"children":4904},{"className":3008,"code":4903,"language":3010,"meta":7,"style":7},"composer config repositories.\u003Cgroup_id> composer https://\u003CDOMAIN-NAME>/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\n",[4905],{"type":29,"tag":670,"props":4906,"children":4907},{"__ignoreMap":7},[4908],{"type":29,"tag":127,"props":4909,"children":4910},{"class":675,"line":676},[4911,4915,4920,4925,4931,4936,4941,4946,4951,4956,4960,4965,4970,4974,4979,4983,4987,4991,4995],{"type":29,"tag":127,"props":4912,"children":4913},{"style":3020},[4914],{"type":56,"value":1905},{"type":29,"tag":127,"props":4916,"children":4917},{"style":718},[4918],{"type":56,"value":4919}," config",{"type":29,"tag":127,"props":4921,"children":4922},{"style":718},[4923],{"type":56,"value":4924}," repositories.",{"type":29,"tag":127,"props":4926,"children":4928},{"style":4927},"--shiki-default:#F97583;--shiki-dark:#F97583;--shiki-sepia:#F92672",[4929],{"type":56,"value":4930},"\u003C",{"type":29,"tag":127,"props":4932,"children":4933},{"style":718},[4934],{"type":56,"value":4935},"group_i",{"type":29,"tag":127,"props":4937,"children":4938},{"style":686},[4939],{"type":56,"value":4940},"d",{"type":29,"tag":127,"props":4942,"children":4943},{"style":4927},[4944],{"type":56,"value":4945},">",{"type":29,"tag":127,"props":4947,"children":4948},{"style":718},[4949],{"type":56,"value":4950}," composer",{"type":29,"tag":127,"props":4952,"children":4953},{"style":718},[4954],{"type":56,"value":4955}," https://",{"type":29,"tag":127,"props":4957,"children":4958},{"style":4927},[4959],{"type":56,"value":4930},{"type":29,"tag":127,"props":4961,"children":4962},{"style":718},[4963],{"type":56,"value":4964},"DOMAIN-NAM",{"type":29,"tag":127,"props":4966,"children":4967},{"style":686},[4968],{"type":56,"value":4969},"E",{"type":29,"tag":127,"props":4971,"children":4972},{"style":4927},[4973],{"type":56,"value":4945},{"type":29,"tag":127,"props":4975,"children":4976},{"style":718},[4977],{"type":56,"value":4978},"/api/v4/group/",{"type":29,"tag":127,"props":4980,"children":4981},{"style":4927},[4982],{"type":56,"value":4930},{"type":29,"tag":127,"props":4984,"children":4985},{"style":718},[4986],{"type":56,"value":4935},{"type":29,"tag":127,"props":4988,"children":4989},{"style":686},[4990],{"type":56,"value":4940},{"type":29,"tag":127,"props":4992,"children":4993},{"style":4927},[4994],{"type":56,"value":4945},{"type":29,"tag":127,"props":4996,"children":4997},{"style":718},[4998],{"type":56,"value":4999},"/-/packages/composer/packages.json\n",{"type":29,"tag":48,"props":5001,"children":5002},{},[5003],{"type":56,"value":5004},"And setup GitLab credentials:",{"type":29,"tag":657,"props":5006,"children":5008},{"className":3008,"code":5007,"language":3010,"meta":7,"style":7},"composer config gitlab-token.\u003CDOMAIN-NAME> \u003Cpersonal_access_token>\n",[5009],{"type":29,"tag":670,"props":5010,"children":5011},{"__ignoreMap":7},[5012],{"type":29,"tag":127,"props":5013,"children":5014},{"class":675,"line":676},[5015,5019,5023,5028,5032,5036,5040,5044,5049,5054,5059],{"type":29,"tag":127,"props":5016,"children":5017},{"style":3020},[5018],{"type":56,"value":1905},{"type":29,"tag":127,"props":5020,"children":5021},{"style":718},[5022],{"type":56,"value":4919},{"type":29,"tag":127,"props":5024,"children":5025},{"style":718},[5026],{"type":56,"value":5027}," gitlab-token.",{"type":29,"tag":127,"props":5029,"children":5030},{"style":4927},[5031],{"type":56,"value":4930},{"type":29,"tag":127,"props":5033,"children":5034},{"style":718},[5035],{"type":56,"value":4964},{"type":29,"tag":127,"props":5037,"children":5038},{"style":686},[5039],{"type":56,"value":4969},{"type":29,"tag":127,"props":5041,"children":5042},{"style":4927},[5043],{"type":56,"value":4945},{"type":29,"tag":127,"props":5045,"children":5046},{"style":4927},[5047],{"type":56,"value":5048}," \u003C",{"type":29,"tag":127,"props":5050,"children":5051},{"style":718},[5052],{"type":56,"value":5053},"personal_access_toke",{"type":29,"tag":127,"props":5055,"children":5056},{"style":686},[5057],{"type":56,"value":5058},"n",{"type":29,"tag":127,"props":5060,"children":5061},{"style":4927},[5062],{"type":56,"value":5063},">\n",{"type":29,"tag":48,"props":5065,"children":5066},{},[5067,5069,5074],{"type":56,"value":5068},"You can read more about this process in the ",{"type":29,"tag":643,"props":5070,"children":5072},{"href":5071},"https://docs.gitlab.com/user/packages/composer_repository/#install-a-composer-package",[5073],{"type":56,"value":1869},{"type":56,"value":916},{"type":29,"tag":48,"props":5076,"children":5077},{},[5078],{"type":56,"value":5079},"Now we require our package us usual:",{"type":29,"tag":657,"props":5081,"children":5082},{"className":3008,"code":3009,"language":3010,"meta":7,"style":7},[5083],{"type":29,"tag":670,"props":5084,"children":5085},{"__ignoreMap":7},[5086],{"type":29,"tag":127,"props":5087,"children":5088},{"class":675,"line":676},[5089,5093,5097],{"type":29,"tag":127,"props":5090,"children":5091},{"style":3020},[5092],{"type":56,"value":1905},{"type":29,"tag":127,"props":5094,"children":5095},{"style":718},[5096],{"type":56,"value":3027},{"type":29,"tag":127,"props":5098,"children":5099},{"style":718},[5100],{"type":56,"value":3032},{"type":29,"tag":657,"props":5102,"children":5104},{"className":3743,"code":5103,"language":3745,"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",[5105],{"type":29,"tag":670,"props":5106,"children":5107},{"__ignoreMap":7},[5108,5115,5122,5129,5136,5143,5150,5157,5164,5171,5179,5187,5194,5201,5208,5215,5222,5229],{"type":29,"tag":127,"props":5109,"children":5110},{"class":675,"line":676},[5111],{"type":29,"tag":127,"props":5112,"children":5113},{},[5114],{"type":56,"value":3098},{"type":29,"tag":127,"props":5116,"children":5117},{"class":675,"line":342},[5118],{"type":29,"tag":127,"props":5119,"children":5120},{},[5121],{"type":56,"value":3106},{"type":29,"tag":127,"props":5123,"children":5124},{"class":675,"line":704},[5125],{"type":29,"tag":127,"props":5126,"children":5127},{},[5128],{"type":56,"value":3772},{"type":29,"tag":127,"props":5130,"children":5131},{"class":675,"line":724},[5132],{"type":29,"tag":127,"props":5133,"children":5134},{},[5135],{"type":56,"value":3780},{"type":29,"tag":127,"props":5137,"children":5138},{"class":675,"line":662},[5139],{"type":29,"tag":127,"props":5140,"children":5141},{},[5142],{"type":56,"value":3130},{"type":29,"tag":127,"props":5144,"children":5145},{"class":675,"line":663},[5146],{"type":29,"tag":127,"props":5147,"children":5148},{},[5149],{"type":56,"value":3795},{"type":29,"tag":127,"props":5151,"children":5152},{"class":675,"line":664},[5153],{"type":29,"tag":127,"props":5154,"children":5155},{},[5156],{"type":56,"value":3146},{"type":29,"tag":127,"props":5158,"children":5159},{"class":675,"line":665},[5160],{"type":29,"tag":127,"props":5161,"children":5162},{},[5163],{"type":56,"value":3154},{"type":29,"tag":127,"props":5165,"children":5166},{"class":675,"line":666},[5167],{"type":29,"tag":127,"props":5168,"children":5169},{},[5170],{"type":56,"value":3162},{"type":29,"tag":127,"props":5172,"children":5173},{"class":675,"line":1325},[5174],{"type":29,"tag":127,"props":5175,"children":5176},{},[5177],{"type":56,"value":5178},"  - Downloading acme/sample-plugin (1.0.0)\n",{"type":29,"tag":127,"props":5180,"children":5181},{"class":675,"line":1338},[5182],{"type":29,"tag":127,"props":5183,"children":5184},{},[5185],{"type":56,"value":5186},"  - Installing acme/sample-plugin (1.0.0): Extracting archive\n",{"type":29,"tag":127,"props":5188,"children":5189},{"class":675,"line":118},[5190],{"type":29,"tag":127,"props":5191,"children":5192},{},[5193],{"type":56,"value":3186},{"type":29,"tag":127,"props":5195,"children":5196},{"class":675,"line":1363},[5197],{"type":29,"tag":127,"props":5198,"children":5199},{"emptyLinePlaceholder":500},[5200],{"type":56,"value":1395},{"type":29,"tag":127,"props":5202,"children":5203},{"class":675,"line":1376},[5204],{"type":29,"tag":127,"props":5205,"children":5206},{},[5207],{"type":56,"value":3201},{"type":29,"tag":127,"props":5209,"children":5210},{"class":675,"line":1389},[5211],{"type":29,"tag":127,"props":5212,"children":5213},{"emptyLinePlaceholder":500},[5214],{"type":56,"value":1395},{"type":29,"tag":127,"props":5216,"children":5217},{"class":675,"line":1398},[5218],{"type":29,"tag":127,"props":5219,"children":5220},{},[5221],{"type":56,"value":3216},{"type":29,"tag":127,"props":5223,"children":5224},{"class":675,"line":1411},[5225],{"type":29,"tag":127,"props":5226,"children":5227},{"emptyLinePlaceholder":500},[5228],{"type":56,"value":1395},{"type":29,"tag":127,"props":5230,"children":5231},{"class":675,"line":1424},[5232],{"type":29,"tag":127,"props":5233,"children":5234},{},[5235],{"type":56,"value":3882},{"type":29,"tag":48,"props":5237,"children":5238},{},[5239],{"type":29,"tag":127,"props":5240,"children":5243},{"className":5241},[5242],"text-h2",[5244],{"type":56,"value":5245},"Awesome. Direct package download!",{"type":29,"tag":122,"props":5247,"children":5249},{"id":5248},"why-bother",[5250],{"type":56,"value":5251},"Why bother?",{"type":29,"tag":48,"props":5253,"children":5254},{},[5255,5257,5263,5265,5271],{"type":56,"value":5256},"This is an excellent question. The main reason is package caching. When running in a ",{"type":29,"tag":670,"props":5258,"children":5260},{"className":5259},[],[5261],{"type":56,"value":5262},"CI/CD",{"type":56,"value":5264}," environment or ",{"type":29,"tag":670,"props":5266,"children":5268},{"className":5267},[],[5269],{"type":56,"value":5270},"docker build",{"type":56,"value":5272},",\ncaching packages can give you a massive performance boost.",{"type":29,"tag":1663,"props":5274,"children":5275},{},[],{"type":29,"tag":1184,"props":5277,"children":5278},{},[],{"type":29,"tag":90,"props":5280,"children":5282},{"id":5281},"release-pipeline",[5283],{"type":56,"value":5284},"Release pipeline",{"type":29,"tag":122,"props":5286,"children":5288},{"id":5287},"with-manual-tagging",[5289],{"type":56,"value":5290},"With manual tagging",{"type":29,"tag":48,"props":5292,"children":5293},{},[5294],{"type":56,"value":5295},"This is a simple pipeline when you need to manually create and push a git tag.",{"type":29,"tag":48,"props":5297,"children":5298},{},[5299,5301,5306,5307],{"type":56,"value":5300},"Make sure to always update the ",{"type":29,"tag":670,"props":5302,"children":5304},{"className":5303},[],[5305],{"type":56,"value":3262},{"type":56,"value":3264},{"type":29,"tag":670,"props":5308,"children":5310},{"className":5309},[],[5311],{"type":56,"value":3270},{"type":29,"tag":657,"props":5313,"children":5315},{"className":3008,"code":5314,"language":3010,"meta":7,"style":7},"git tag \u003Cversion>\ngit push --tags\n",[5316],{"type":29,"tag":670,"props":5317,"children":5318},{"__ignoreMap":7},[5319,5347],{"type":29,"tag":127,"props":5320,"children":5321},{"class":675,"line":676},[5322,5326,5330,5334,5339,5343],{"type":29,"tag":127,"props":5323,"children":5324},{"style":3020},[5325],{"type":56,"value":906},{"type":29,"tag":127,"props":5327,"children":5328},{"style":718},[5329],{"type":56,"value":3692},{"type":29,"tag":127,"props":5331,"children":5332},{"style":4927},[5333],{"type":56,"value":5048},{"type":29,"tag":127,"props":5335,"children":5336},{"style":718},[5337],{"type":56,"value":5338},"versio",{"type":29,"tag":127,"props":5340,"children":5341},{"style":686},[5342],{"type":56,"value":5058},{"type":29,"tag":127,"props":5344,"children":5345},{"style":4927},[5346],{"type":56,"value":5063},{"type":29,"tag":127,"props":5348,"children":5349},{"class":675,"line":342},[5350,5354,5358],{"type":29,"tag":127,"props":5351,"children":5352},{"style":3020},[5353],{"type":56,"value":906},{"type":29,"tag":127,"props":5355,"children":5356},{"style":718},[5357],{"type":56,"value":3709},{"type":29,"tag":127,"props":5359,"children":5360},{"style":2290},[5361],{"type":56,"value":3714},{"type":29,"tag":657,"props":5363,"children":5366},{"className":667,"code":5364,"filename":5365,"language":508,"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",[5367],{"type":29,"tag":670,"props":5368,"children":5369},{"__ignoreMap":7},[5370,5382,5395,5402,5414,5431,5447,5459,5472,5489,5501],{"type":29,"tag":127,"props":5371,"children":5372},{"class":675,"line":676},[5373,5378],{"type":29,"tag":127,"props":5374,"children":5375},{"style":680},[5376],{"type":56,"value":5377},"stages",{"type":29,"tag":127,"props":5379,"children":5380},{"style":686},[5381],{"type":56,"value":689},{"type":29,"tag":127,"props":5383,"children":5384},{"class":675,"line":342},[5385,5390],{"type":29,"tag":127,"props":5386,"children":5387},{"style":686},[5388],{"type":56,"value":5389},"  - ",{"type":29,"tag":127,"props":5391,"children":5392},{"style":718},[5393],{"type":56,"value":5394},"release\n",{"type":29,"tag":127,"props":5396,"children":5397},{"class":675,"line":704},[5398],{"type":29,"tag":127,"props":5399,"children":5400},{"emptyLinePlaceholder":500},[5401],{"type":56,"value":1395},{"type":29,"tag":127,"props":5403,"children":5404},{"class":675,"line":724},[5405,5410],{"type":29,"tag":127,"props":5406,"children":5407},{"style":680},[5408],{"type":56,"value":5409},"deploy",{"type":29,"tag":127,"props":5411,"children":5412},{"style":686},[5413],{"type":56,"value":689},{"type":29,"tag":127,"props":5415,"children":5416},{"class":675,"line":662},[5417,5422,5426],{"type":29,"tag":127,"props":5418,"children":5419},{"style":680},[5420],{"type":56,"value":5421},"  image",{"type":29,"tag":127,"props":5423,"children":5424},{"style":686},[5425],{"type":56,"value":715},{"type":29,"tag":127,"props":5427,"children":5428},{"style":718},[5429],{"type":56,"value":5430},"alpine/curl\n",{"type":29,"tag":127,"props":5432,"children":5433},{"class":675,"line":663},[5434,5439,5443],{"type":29,"tag":127,"props":5435,"children":5436},{"style":680},[5437],{"type":56,"value":5438},"  stage",{"type":29,"tag":127,"props":5440,"children":5441},{"style":686},[5442],{"type":56,"value":715},{"type":29,"tag":127,"props":5444,"children":5445},{"style":718},[5446],{"type":56,"value":5394},{"type":29,"tag":127,"props":5448,"children":5449},{"class":675,"line":664},[5450,5455],{"type":29,"tag":127,"props":5451,"children":5452},{"style":680},[5453],{"type":56,"value":5454},"  script",{"type":29,"tag":127,"props":5456,"children":5457},{"style":686},[5458],{"type":56,"value":689},{"type":29,"tag":127,"props":5460,"children":5461},{"class":675,"line":665},[5462,5467],{"type":29,"tag":127,"props":5463,"children":5464},{"style":686},[5465],{"type":56,"value":5466},"    - ",{"type":29,"tag":127,"props":5468,"children":5469},{"style":718},[5470],{"type":56,"value":5471},"'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":29,"tag":127,"props":5473,"children":5474},{"class":675,"line":666},[5475,5480,5484],{"type":29,"tag":127,"props":5476,"children":5477},{"style":680},[5478],{"type":56,"value":5479},"  environment",{"type":29,"tag":127,"props":5481,"children":5482},{"style":686},[5483],{"type":56,"value":715},{"type":29,"tag":127,"props":5485,"children":5486},{"style":718},[5487],{"type":56,"value":5488},"production\n",{"type":29,"tag":127,"props":5490,"children":5491},{"class":675,"line":1325},[5492,5497],{"type":29,"tag":127,"props":5493,"children":5494},{"style":680},[5495],{"type":56,"value":5496},"  rules",{"type":29,"tag":127,"props":5498,"children":5499},{"style":686},[5500],{"type":56,"value":689},{"type":29,"tag":127,"props":5502,"children":5503},{"class":675,"line":1338},[5504,5509,5513],{"type":29,"tag":127,"props":5505,"children":5506},{"style":680},[5507],{"type":56,"value":5508},"    if",{"type":29,"tag":127,"props":5510,"children":5511},{"style":686},[5512],{"type":56,"value":715},{"type":29,"tag":127,"props":5514,"children":5515},{"style":718},[5516],{"type":56,"value":5517},"$CI_COMMIT_TAG\n",{"type":29,"tag":122,"props":5519,"children":5521},{"id":5520},"with-semantic-release",[5522],{"type":56,"value":5523},"With semantic-release",{"type":29,"tag":48,"props":5525,"children":5526},{},[5527],{"type":56,"value":5528},"It would be a lot easier if we could just push our changes and don't care about versioning and tagging.",{"type":29,"tag":48,"props":5530,"children":5531},{},[5532,5538],{"type":29,"tag":643,"props":5533,"children":5535},{"href":5534},"https://github.com/semantic-release/semantic-release",[5536],{"type":56,"value":5537},"semantic-release",{"type":56,"value":5539}," automates the whole package release workflow.",{"type":29,"tag":48,"props":5541,"children":5542},{},[5543,5545,5551],{"type":56,"value":5544},"Please follow the ",{"type":29,"tag":643,"props":5546,"children":5548},{"href":5547},"https://github.com/semantic-release/gitlab?tab=readme-ov-file#gitlab-authentication",[5549],{"type":56,"value":5550},"GitLab authentication instruction",{"type":56,"value":5552}," before you continue to read.",{"type":29,"tag":657,"props":5554,"children":5557},{"className":667,"code":5555,"filename":5556,"language":508,"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",[5558],{"type":29,"tag":670,"props":5559,"children":5560},{"__ignoreMap":7},[5561,5572,5583,5590,5602,5617,5628,5645,5668,5684,5695,5707,5718,5739,5756],{"type":29,"tag":127,"props":5562,"children":5563},{"class":675,"line":676},[5564,5568],{"type":29,"tag":127,"props":5565,"children":5566},{"style":680},[5567],{"type":56,"value":5377},{"type":29,"tag":127,"props":5569,"children":5570},{"style":686},[5571],{"type":56,"value":689},{"type":29,"tag":127,"props":5573,"children":5574},{"class":675,"line":342},[5575,5579],{"type":29,"tag":127,"props":5576,"children":5577},{"style":686},[5578],{"type":56,"value":5389},{"type":29,"tag":127,"props":5580,"children":5581},{"style":718},[5582],{"type":56,"value":5394},{"type":29,"tag":127,"props":5584,"children":5585},{"class":675,"line":704},[5586],{"type":29,"tag":127,"props":5587,"children":5588},{"emptyLinePlaceholder":500},[5589],{"type":56,"value":1395},{"type":29,"tag":127,"props":5591,"children":5592},{"class":675,"line":724},[5593,5598],{"type":29,"tag":127,"props":5594,"children":5595},{"style":680},[5596],{"type":56,"value":5597},"release",{"type":29,"tag":127,"props":5599,"children":5600},{"style":686},[5601],{"type":56,"value":689},{"type":29,"tag":127,"props":5603,"children":5604},{"class":675,"line":662},[5605,5609,5613],{"type":29,"tag":127,"props":5606,"children":5607},{"style":680},[5608],{"type":56,"value":5438},{"type":29,"tag":127,"props":5610,"children":5611},{"style":686},[5612],{"type":56,"value":715},{"type":29,"tag":127,"props":5614,"children":5615},{"style":718},[5616],{"type":56,"value":5394},{"type":29,"tag":127,"props":5618,"children":5619},{"class":675,"line":663},[5620,5624],{"type":29,"tag":127,"props":5621,"children":5622},{"style":680},[5623],{"type":56,"value":5421},{"type":29,"tag":127,"props":5625,"children":5626},{"style":686},[5627],{"type":56,"value":689},{"type":29,"tag":127,"props":5629,"children":5630},{"class":675,"line":664},[5631,5636,5640],{"type":29,"tag":127,"props":5632,"children":5633},{"style":680},[5634],{"type":56,"value":5635},"    name",{"type":29,"tag":127,"props":5637,"children":5638},{"style":686},[5639],{"type":56,"value":715},{"type":29,"tag":127,"props":5641,"children":5642},{"style":718},[5643],{"type":56,"value":5644},"ghcr.io/voxpupuli/semantic-release:25.0.0-latest\n",{"type":29,"tag":127,"props":5646,"children":5647},{"class":675,"line":665},[5648,5653,5658,5663],{"type":29,"tag":127,"props":5649,"children":5650},{"style":680},[5651],{"type":56,"value":5652},"    entrypoint",{"type":29,"tag":127,"props":5654,"children":5655},{"style":686},[5656],{"type":56,"value":5657},": [",{"type":29,"tag":127,"props":5659,"children":5660},{"style":718},[5661],{"type":56,"value":5662},"\"\"",{"type":29,"tag":127,"props":5664,"children":5665},{"style":686},[5666],{"type":56,"value":5667},"]\n",{"type":29,"tag":127,"props":5669,"children":5670},{"class":675,"line":666},[5671,5676,5680],{"type":29,"tag":127,"props":5672,"children":5673},{"style":680},[5674],{"type":56,"value":5675},"  interruptible",{"type":29,"tag":127,"props":5677,"children":5678},{"style":686},[5679],{"type":56,"value":715},{"type":29,"tag":127,"props":5681,"children":5682},{"style":2290},[5683],{"type":56,"value":2293},{"type":29,"tag":127,"props":5685,"children":5686},{"class":675,"line":1325},[5687,5691],{"type":29,"tag":127,"props":5688,"children":5689},{"style":680},[5690],{"type":56,"value":5454},{"type":29,"tag":127,"props":5692,"children":5693},{"style":686},[5694],{"type":56,"value":689},{"type":29,"tag":127,"props":5696,"children":5697},{"class":675,"line":1338},[5698,5702],{"type":29,"tag":127,"props":5699,"children":5700},{"style":686},[5701],{"type":56,"value":5466},{"type":29,"tag":127,"props":5703,"children":5704},{"style":718},[5705],{"type":56,"value":5706},"/container-entrypoint.sh\n",{"type":29,"tag":127,"props":5708,"children":5709},{"class":675,"line":118},[5710,5714],{"type":29,"tag":127,"props":5711,"children":5712},{"style":680},[5713],{"type":56,"value":5496},{"type":29,"tag":127,"props":5715,"children":5716},{"style":686},[5717],{"type":56,"value":689},{"type":29,"tag":127,"props":5719,"children":5720},{"class":675,"line":1363},[5721,5725,5730,5734],{"type":29,"tag":127,"props":5722,"children":5723},{"style":686},[5724],{"type":56,"value":5466},{"type":29,"tag":127,"props":5726,"children":5727},{"style":680},[5728],{"type":56,"value":5729},"if",{"type":29,"tag":127,"props":5731,"children":5732},{"style":686},[5733],{"type":56,"value":715},{"type":29,"tag":127,"props":5735,"children":5736},{"style":718},[5737],{"type":56,"value":5738},"$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n",{"type":29,"tag":127,"props":5740,"children":5741},{"class":675,"line":1376},[5742,5747,5751],{"type":29,"tag":127,"props":5743,"children":5744},{"style":680},[5745],{"type":56,"value":5746},"      when",{"type":29,"tag":127,"props":5748,"children":5749},{"style":686},[5750],{"type":56,"value":715},{"type":29,"tag":127,"props":5752,"children":5753},{"style":718},[5754],{"type":56,"value":5755},"never\n",{"type":29,"tag":127,"props":5757,"children":5758},{"class":675,"line":1389},[5759,5763,5767,5771],{"type":29,"tag":127,"props":5760,"children":5761},{"style":686},[5762],{"type":56,"value":5466},{"type":29,"tag":127,"props":5764,"children":5765},{"style":680},[5766],{"type":56,"value":5729},{"type":29,"tag":127,"props":5768,"children":5769},{"style":686},[5770],{"type":56,"value":715},{"type":29,"tag":127,"props":5772,"children":5773},{"style":718},[5774],{"type":56,"value":5775},"$CI_COMMIT_BRANCH\n",{"type":29,"tag":657,"props":5777,"children":5780},{"className":1953,"code":5778,"filename":5779,"language":454,"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",[5781],{"type":29,"tag":670,"props":5782,"children":5783},{"__ignoreMap":7},[5784,5791,5803,5815,5823,5835,5843,5855,5863,5885,5932,5974,5982,5990,5997,6004,6011,6023,6030,6050,6077,6084,6091,6098,6110,6117,6152,6159,6166,6174],{"type":29,"tag":127,"props":5785,"children":5786},{"class":675,"line":676},[5787],{"type":29,"tag":127,"props":5788,"children":5789},{"style":686},[5790],{"type":56,"value":1972},{"type":29,"tag":127,"props":5792,"children":5793},{"class":675,"line":342},[5794,5799],{"type":29,"tag":127,"props":5795,"children":5796},{"style":1978},[5797],{"type":56,"value":5798},"  \"plugins\"",{"type":29,"tag":127,"props":5800,"children":5801},{"style":686},[5802],{"type":56,"value":2213},{"type":29,"tag":127,"props":5804,"children":5805},{"class":675,"line":704},[5806,5811],{"type":29,"tag":127,"props":5807,"children":5808},{"style":1988},[5809],{"type":56,"value":5810},"    \"@semantic-release/commit-analyzer\"",{"type":29,"tag":127,"props":5812,"children":5813},{"style":686},[5814],{"type":56,"value":1996},{"type":29,"tag":127,"props":5816,"children":5817},{"class":675,"line":724},[5818],{"type":29,"tag":127,"props":5819,"children":5820},{"style":686},[5821],{"type":56,"value":5822},"    [\n",{"type":29,"tag":127,"props":5824,"children":5825},{"class":675,"line":662},[5826,5831],{"type":29,"tag":127,"props":5827,"children":5828},{"style":1988},[5829],{"type":56,"value":5830},"      \"semantic-release-replace-plugin\"",{"type":29,"tag":127,"props":5832,"children":5833},{"style":686},[5834],{"type":56,"value":1996},{"type":29,"tag":127,"props":5836,"children":5837},{"class":675,"line":663},[5838],{"type":29,"tag":127,"props":5839,"children":5840},{"style":686},[5841],{"type":56,"value":5842},"      {\n",{"type":29,"tag":127,"props":5844,"children":5845},{"class":675,"line":664},[5846,5851],{"type":29,"tag":127,"props":5847,"children":5848},{"style":1978},[5849],{"type":56,"value":5850},"        \"replacements\"",{"type":29,"tag":127,"props":5852,"children":5853},{"style":686},[5854],{"type":56,"value":2213},{"type":29,"tag":127,"props":5856,"children":5857},{"class":675,"line":665},[5858],{"type":29,"tag":127,"props":5859,"children":5860},{"style":686},[5861],{"type":56,"value":5862},"          {\n",{"type":29,"tag":127,"props":5864,"children":5865},{"class":675,"line":666},[5866,5871,5875,5880],{"type":29,"tag":127,"props":5867,"children":5868},{"style":1978},[5869],{"type":56,"value":5870},"            \"files\"",{"type":29,"tag":127,"props":5872,"children":5873},{"style":686},[5874],{"type":56,"value":5657},{"type":29,"tag":127,"props":5876,"children":5877},{"style":1988},[5878],{"type":56,"value":5879},"\"composer.json\"",{"type":29,"tag":127,"props":5881,"children":5882},{"style":686},[5883],{"type":56,"value":5884},"],\n",{"type":29,"tag":127,"props":5886,"children":5887},{"class":675,"line":1325},[5888,5893,5897,5902,5907,5911,5915,5920,5924,5928],{"type":29,"tag":127,"props":5889,"children":5890},{"style":1978},[5891],{"type":56,"value":5892},"            \"from\"",{"type":29,"tag":127,"props":5894,"children":5895},{"style":686},[5896],{"type":56,"value":715},{"type":29,"tag":127,"props":5898,"children":5899},{"style":1988},[5900],{"type":56,"value":5901},"\"version",{"type":29,"tag":127,"props":5903,"children":5904},{"style":2290},[5905],{"type":56,"value":5906},"\\\"",{"type":29,"tag":127,"props":5908,"children":5909},{"style":1988},[5910],{"type":56,"value":715},{"type":29,"tag":127,"props":5912,"children":5913},{"style":2290},[5914],{"type":56,"value":5906},{"type":29,"tag":127,"props":5916,"children":5917},{"style":1988},[5918],{"type":56,"value":5919},".*",{"type":29,"tag":127,"props":5921,"children":5922},{"style":2290},[5923],{"type":56,"value":5906},{"type":29,"tag":127,"props":5925,"children":5926},{"style":1988},[5927],{"type":56,"value":2598},{"type":29,"tag":127,"props":5929,"children":5930},{"style":686},[5931],{"type":56,"value":1996},{"type":29,"tag":127,"props":5933,"children":5934},{"class":675,"line":1338},[5935,5940,5944,5948,5952,5956,5960,5965,5969],{"type":29,"tag":127,"props":5936,"children":5937},{"style":1978},[5938],{"type":56,"value":5939},"            \"to\"",{"type":29,"tag":127,"props":5941,"children":5942},{"style":686},[5943],{"type":56,"value":715},{"type":29,"tag":127,"props":5945,"children":5946},{"style":1988},[5947],{"type":56,"value":5901},{"type":29,"tag":127,"props":5949,"children":5950},{"style":2290},[5951],{"type":56,"value":5906},{"type":29,"tag":127,"props":5953,"children":5954},{"style":1988},[5955],{"type":56,"value":715},{"type":29,"tag":127,"props":5957,"children":5958},{"style":2290},[5959],{"type":56,"value":5906},{"type":29,"tag":127,"props":5961,"children":5962},{"style":1988},[5963],{"type":56,"value":5964},"${nextRelease.version}",{"type":29,"tag":127,"props":5966,"children":5967},{"style":2290},[5968],{"type":56,"value":5906},{"type":29,"tag":127,"props":5970,"children":5971},{"style":1988},[5972],{"type":56,"value":5973},"\"\n",{"type":29,"tag":127,"props":5975,"children":5976},{"class":675,"line":118},[5977],{"type":29,"tag":127,"props":5978,"children":5979},{"style":686},[5980],{"type":56,"value":5981},"          }\n",{"type":29,"tag":127,"props":5983,"children":5984},{"class":675,"line":1363},[5985],{"type":29,"tag":127,"props":5986,"children":5987},{"style":686},[5988],{"type":56,"value":5989},"        ]\n",{"type":29,"tag":127,"props":5991,"children":5992},{"class":675,"line":1376},[5993],{"type":29,"tag":127,"props":5994,"children":5995},{"style":686},[5996],{"type":56,"value":2301},{"type":29,"tag":127,"props":5998,"children":5999},{"class":675,"line":1389},[6000],{"type":29,"tag":127,"props":6001,"children":6002},{"style":686},[6003],{"type":56,"value":2845},{"type":29,"tag":127,"props":6005,"children":6006},{"class":675,"line":1398},[6007],{"type":29,"tag":127,"props":6008,"children":6009},{"style":686},[6010],{"type":56,"value":5822},{"type":29,"tag":127,"props":6012,"children":6013},{"class":675,"line":1411},[6014,6019],{"type":29,"tag":127,"props":6015,"children":6016},{"style":1988},[6017],{"type":56,"value":6018},"      \"@semantic-release/git\"",{"type":29,"tag":127,"props":6020,"children":6021},{"style":686},[6022],{"type":56,"value":1996},{"type":29,"tag":127,"props":6024,"children":6025},{"class":675,"line":1424},[6026],{"type":29,"tag":127,"props":6027,"children":6028},{"style":686},[6029],{"type":56,"value":5842},{"type":29,"tag":127,"props":6031,"children":6032},{"class":675,"line":1433},[6033,6038,6042,6046],{"type":29,"tag":127,"props":6034,"children":6035},{"style":1978},[6036],{"type":56,"value":6037},"        \"assets\"",{"type":29,"tag":127,"props":6039,"children":6040},{"style":686},[6041],{"type":56,"value":5657},{"type":29,"tag":127,"props":6043,"children":6044},{"style":1988},[6045],{"type":56,"value":5879},{"type":29,"tag":127,"props":6047,"children":6048},{"style":686},[6049],{"type":56,"value":5884},{"type":29,"tag":127,"props":6051,"children":6052},{"class":675,"line":1446},[6053,6058,6062,6067,6072],{"type":29,"tag":127,"props":6054,"children":6055},{"style":1978},[6056],{"type":56,"value":6057},"        \"message\"",{"type":29,"tag":127,"props":6059,"children":6060},{"style":686},[6061],{"type":56,"value":715},{"type":29,"tag":127,"props":6063,"children":6064},{"style":1988},[6065],{"type":56,"value":6066},"\"chore(release): ${nextRelease.version} [skip ci]",{"type":29,"tag":127,"props":6068,"children":6069},{"style":2290},[6070],{"type":56,"value":6071},"\\n\\n",{"type":29,"tag":127,"props":6073,"children":6074},{"style":1988},[6075],{"type":56,"value":6076},"${nextRelease.notes}\"\n",{"type":29,"tag":127,"props":6078,"children":6079},{"class":675,"line":1459},[6080],{"type":29,"tag":127,"props":6081,"children":6082},{"style":686},[6083],{"type":56,"value":2301},{"type":29,"tag":127,"props":6085,"children":6086},{"class":675,"line":1472},[6087],{"type":29,"tag":127,"props":6088,"children":6089},{"style":686},[6090],{"type":56,"value":2845},{"type":29,"tag":127,"props":6092,"children":6093},{"class":675,"line":1480},[6094],{"type":29,"tag":127,"props":6095,"children":6096},{"style":686},[6097],{"type":56,"value":5822},{"type":29,"tag":127,"props":6099,"children":6100},{"class":675,"line":1493},[6101,6106],{"type":29,"tag":127,"props":6102,"children":6103},{"style":1988},[6104],{"type":56,"value":6105},"      \"@semantic-release/exec\"",{"type":29,"tag":127,"props":6107,"children":6108},{"style":686},[6109],{"type":56,"value":1996},{"type":29,"tag":127,"props":6111,"children":6112},{"class":675,"line":1506},[6113],{"type":29,"tag":127,"props":6114,"children":6115},{"style":686},[6116],{"type":56,"value":5842},{"type":29,"tag":127,"props":6118,"children":6119},{"class":675,"line":1519},[6120,6125,6129,6134,6138,6143,6147],{"type":29,"tag":127,"props":6121,"children":6122},{"style":1978},[6123],{"type":56,"value":6124},"        \"publishCmd\"",{"type":29,"tag":127,"props":6126,"children":6127},{"style":686},[6128],{"type":56,"value":715},{"type":29,"tag":127,"props":6130,"children":6131},{"style":1988},[6132],{"type":56,"value":6133},"\"curl --fail-with-body --header ",{"type":29,"tag":127,"props":6135,"children":6136},{"style":2290},[6137],{"type":56,"value":5906},{"type":29,"tag":127,"props":6139,"children":6140},{"style":1988},[6141],{"type":56,"value":6142},"Job-Token: ${process.env.CI_JOB_TOKEN}",{"type":29,"tag":127,"props":6144,"children":6145},{"style":2290},[6146],{"type":56,"value":5906},{"type":29,"tag":127,"props":6148,"children":6149},{"style":1988},[6150],{"type":56,"value":6151}," --data tag=${nextRelease.gitTag} ${process.env.CI_API_V4_URL}/projects/${process.env.CI_PROJECT_ID}/packages/composer\"\n",{"type":29,"tag":127,"props":6153,"children":6154},{"class":675,"line":1532},[6155],{"type":29,"tag":127,"props":6156,"children":6157},{"style":686},[6158],{"type":56,"value":2301},{"type":29,"tag":127,"props":6160,"children":6161},{"class":675,"line":1545},[6162],{"type":29,"tag":127,"props":6163,"children":6164},{"style":686},[6165],{"type":56,"value":2875},{"type":29,"tag":127,"props":6167,"children":6168},{"class":675,"line":2398},[6169],{"type":29,"tag":127,"props":6170,"children":6171},{"style":686},[6172],{"type":56,"value":6173},"  ]\n",{"type":29,"tag":127,"props":6175,"children":6176},{"class":675,"line":2406},[6177],{"type":29,"tag":127,"props":6178,"children":6179},{"style":686},[6180],{"type":56,"value":3000},{"type":29,"tag":48,"props":6182,"children":6183},{},[6184],{"type":56,"value":6185},"This will:",{"type":29,"tag":960,"props":6187,"children":6188},{},[6189,6194,6204,6216,6221],{"type":29,"tag":812,"props":6190,"children":6191},{},[6192],{"type":56,"value":6193},"Analise the commits from the last release to decide if a new version should be released",{"type":29,"tag":812,"props":6195,"children":6196},{},[6197,6199],{"type":56,"value":6198},"Update the version in ",{"type":29,"tag":670,"props":6200,"children":6202},{"className":6201},[],[6203],{"type":56,"value":3270},{"type":29,"tag":812,"props":6205,"children":6206},{},[6207,6209,6214],{"type":56,"value":6208},"Commit the ",{"type":29,"tag":670,"props":6210,"children":6212},{"className":6211},[],[6213],{"type":56,"value":3270},{"type":56,"value":6215}," back into the repo",{"type":29,"tag":812,"props":6217,"children":6218},{},[6219],{"type":56,"value":6220},"Create a tag",{"type":29,"tag":812,"props":6222,"children":6223},{},[6224],{"type":56,"value":6225},"Release a composer package from this tag",{"type":29,"tag":1826,"props":6227,"children":6228},{},[6229],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":6231},[6232,6238],{"id":1924,"depth":342,"text":1927,"children":6233},[6234,6235,6236,6237],{"id":1935,"depth":704,"text":1938},{"id":3236,"depth":704,"text":3239},{"id":3897,"depth":704,"text":3900},{"id":5248,"depth":704,"text":5251},{"id":5281,"depth":342,"text":5284,"children":6239},[6240,6241],{"id":5287,"depth":704,"text":5290},{"id":5520,"depth":704,"text":5523},{"_path":543,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":544,"description":545,"author":518,"image":519,"releaseDate":533,"blogCategories":6243,"articleTags":6244,"tags":6245,"body":6246,"_type":346,"_id":549,"_source":348,"_file":550,"_stem":551,"_extension":351},[522,523],[523,536,537],[461,24],{"type":26,"children":6247,"toc":7319},[6248,6252,6263,6275,6281,6286,6315,6320,6325,6343,6355,6360,6381,6387,6407,6726,6737,6742,7284,7293,7297,7315],{"type":29,"tag":61,"props":6249,"children":6251},{"alt":7,"aspect-ratio":1849,"height":1850,"object-fit":1851,"src":6250},"/blog/shopware-plugin-build+release.png",[],{"type":29,"tag":48,"props":6253,"children":6254},{},[6255,6256,6261],{"type":56,"value":892},{"type":29,"tag":643,"props":6257,"children":6258},{"href":530},[6259],{"type":56,"value":6260},"previous post",{"type":56,"value":6262}," I described how to distribute a Shopware 6 plugin over GitLab Package registry.",{"type":29,"tag":48,"props":6264,"children":6265},{},[6266,6268,6273],{"type":56,"value":6267},"When building our project using ",{"type":29,"tag":643,"props":6269,"children":6271},{"href":6270},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html#building-an-extension",[6272],{"type":56,"value":1916},{"type":56,"value":6274},",\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":29,"tag":90,"props":6276,"children":6278},{"id":6277},"building-manually",[6279],{"type":56,"value":6280},"Building manually",{"type":29,"tag":48,"props":6282,"children":6283},{},[6284],{"type":56,"value":6285},"Building a plugin is as simple as running:",{"type":29,"tag":657,"props":6287,"children":6289},{"className":3008,"code":6288,"language":3010,"meta":7,"style":7},"shopware-cli extension build .\n",[6290],{"type":29,"tag":670,"props":6291,"children":6292},{"__ignoreMap":7},[6293],{"type":29,"tag":127,"props":6294,"children":6295},{"class":675,"line":676},[6296,6300,6305,6310],{"type":29,"tag":127,"props":6297,"children":6298},{"style":3020},[6299],{"type":56,"value":1916},{"type":29,"tag":127,"props":6301,"children":6302},{"style":718},[6303],{"type":56,"value":6304}," extension",{"type":29,"tag":127,"props":6306,"children":6307},{"style":718},[6308],{"type":56,"value":6309}," build",{"type":29,"tag":127,"props":6311,"children":6312},{"style":718},[6313],{"type":56,"value":6314}," .\n",{"type":29,"tag":48,"props":6316,"children":6317},{},[6318],{"type":56,"value":6319},"In the plugin root directory.",{"type":29,"tag":48,"props":6321,"children":6322},{},[6323],{"type":56,"value":6324},"There are some tweaks you can make, like:",{"type":29,"tag":808,"props":6326,"children":6327},{},[6328,6333,6338],{"type":29,"tag":812,"props":6329,"children":6330},{},[6331],{"type":56,"value":6332},"constrain a shopware version",{"type":29,"tag":812,"props":6334,"children":6335},{},[6336],{"type":56,"value":6337},"specify extra bundles",{"type":29,"tag":812,"props":6339,"children":6340},{},[6341],{"type":56,"value":6342},"use esbuild",{"type":29,"tag":48,"props":6344,"children":6345},{},[6346,6348,6353],{"type":56,"value":6347},"Please refer to the ",{"type":29,"tag":643,"props":6349,"children":6351},{"href":6350},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html",[6352],{"type":56,"value":1869},{"type":56,"value":6354}," for detailed configuration.",{"type":29,"tag":48,"props":6356,"children":6357},{},[6358],{"type":56,"value":6359},"The build process will create the following directories containing the compiled files:",{"type":29,"tag":808,"props":6361,"children":6362},{},[6363,6372],{"type":29,"tag":812,"props":6364,"children":6365},{},[6366],{"type":29,"tag":670,"props":6367,"children":6369},{"className":6368},[],[6370],{"type":56,"value":6371},"src/Resources/app/storefront/dist/",{"type":29,"tag":812,"props":6373,"children":6374},{},[6375],{"type":29,"tag":670,"props":6376,"children":6378},{"className":6377},[],[6379],{"type":56,"value":6380},"src/Resources/public/static/",{"type":29,"tag":90,"props":6382,"children":6384},{"id":6383},"build-pipeline",[6385],{"type":56,"value":6386},"Build pipeline",{"type":29,"tag":48,"props":6388,"children":6389},{},[6390,6392,6397,6399,6405],{"type":56,"value":6391},"We use the official ",{"type":29,"tag":670,"props":6393,"children":6395},{"className":6394},[],[6396],{"type":56,"value":1916},{"type":56,"value":6398}," docker image. To speed up the process, we take advantage of the ",{"type":29,"tag":670,"props":6400,"children":6402},{"className":6401},[],[6403],{"type":56,"value":6404},"CI",{"type":56,"value":6406}," caching system.",{"type":29,"tag":657,"props":6408,"children":6411},{"className":667,"code":6409,"filename":5556,"highlights":6410,"language":508,"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",[663,1376,1389,1398,1411,1424],[6412],{"type":29,"tag":670,"props":6413,"children":6414},{"__ignoreMap":7},[6415,6426,6438,6445,6457,6468,6485,6504,6519,6531,6548,6565,6576,6587,6600,6622,6635,6649,6662,6673,6692,6707],{"type":29,"tag":127,"props":6416,"children":6417},{"class":675,"line":676},[6418,6422],{"type":29,"tag":127,"props":6419,"children":6420},{"style":680},[6421],{"type":56,"value":5377},{"type":29,"tag":127,"props":6423,"children":6424},{"style":686},[6425],{"type":56,"value":689},{"type":29,"tag":127,"props":6427,"children":6428},{"class":675,"line":342},[6429,6433],{"type":29,"tag":127,"props":6430,"children":6431},{"style":686},[6432],{"type":56,"value":5389},{"type":29,"tag":127,"props":6434,"children":6435},{"style":718},[6436],{"type":56,"value":6437},"build\n",{"type":29,"tag":127,"props":6439,"children":6440},{"class":675,"line":704},[6441],{"type":29,"tag":127,"props":6442,"children":6443},{"emptyLinePlaceholder":500},[6444],{"type":56,"value":1395},{"type":29,"tag":127,"props":6446,"children":6447},{"class":675,"line":724},[6448,6453],{"type":29,"tag":127,"props":6449,"children":6450},{"style":680},[6451],{"type":56,"value":6452},"build",{"type":29,"tag":127,"props":6454,"children":6455},{"style":686},[6456],{"type":56,"value":689},{"type":29,"tag":127,"props":6458,"children":6459},{"class":675,"line":662},[6460,6464],{"type":29,"tag":127,"props":6461,"children":6462},{"style":680},[6463],{"type":56,"value":5421},{"type":29,"tag":127,"props":6465,"children":6466},{"style":686},[6467],{"type":56,"value":689},{"type":29,"tag":127,"props":6469,"children":6471},{"class":6470,"line":663},[675,738],[6472,6476,6480],{"type":29,"tag":127,"props":6473,"children":6474},{"style":680},[6475],{"type":56,"value":5635},{"type":29,"tag":127,"props":6477,"children":6478},{"style":686},[6479],{"type":56,"value":715},{"type":29,"tag":127,"props":6481,"children":6482},{"style":718},[6483],{"type":56,"value":6484},"ghcr.io/shopware/shopware-cli:latest-php-8.2\n",{"type":29,"tag":127,"props":6486,"children":6487},{"class":675,"line":664},[6488,6492,6496,6500],{"type":29,"tag":127,"props":6489,"children":6490},{"style":680},[6491],{"type":56,"value":5652},{"type":29,"tag":127,"props":6493,"children":6494},{"style":686},[6495],{"type":56,"value":5657},{"type":29,"tag":127,"props":6497,"children":6498},{"style":718},[6499],{"type":56,"value":5662},{"type":29,"tag":127,"props":6501,"children":6502},{"style":686},[6503],{"type":56,"value":5667},{"type":29,"tag":127,"props":6505,"children":6506},{"class":675,"line":665},[6507,6511,6515],{"type":29,"tag":127,"props":6508,"children":6509},{"style":680},[6510],{"type":56,"value":5438},{"type":29,"tag":127,"props":6512,"children":6513},{"style":686},[6514],{"type":56,"value":715},{"type":29,"tag":127,"props":6516,"children":6517},{"style":718},[6518],{"type":56,"value":6437},{"type":29,"tag":127,"props":6520,"children":6521},{"class":675,"line":666},[6522,6527],{"type":29,"tag":127,"props":6523,"children":6524},{"style":680},[6525],{"type":56,"value":6526},"  variables",{"type":29,"tag":127,"props":6528,"children":6529},{"style":686},[6530],{"type":56,"value":689},{"type":29,"tag":127,"props":6532,"children":6533},{"class":675,"line":1325},[6534,6539,6543],{"type":29,"tag":127,"props":6535,"children":6536},{"style":680},[6537],{"type":56,"value":6538},"    COMPOSER_CACHE_DIR",{"type":29,"tag":127,"props":6540,"children":6541},{"style":686},[6542],{"type":56,"value":715},{"type":29,"tag":127,"props":6544,"children":6545},{"style":718},[6546],{"type":56,"value":6547},"${CI_PROJECT_DIR}/.composer\n",{"type":29,"tag":127,"props":6549,"children":6550},{"class":675,"line":1338},[6551,6556,6560],{"type":29,"tag":127,"props":6552,"children":6553},{"style":680},[6554],{"type":56,"value":6555},"    npm_config_cache",{"type":29,"tag":127,"props":6557,"children":6558},{"style":686},[6559],{"type":56,"value":715},{"type":29,"tag":127,"props":6561,"children":6562},{"style":718},[6563],{"type":56,"value":6564},"${CI_PROJECT_DIR}/.npm\n",{"type":29,"tag":127,"props":6566,"children":6567},{"class":675,"line":118},[6568,6572],{"type":29,"tag":127,"props":6569,"children":6570},{"style":680},[6571],{"type":56,"value":5454},{"type":29,"tag":127,"props":6573,"children":6574},{"style":686},[6575],{"type":56,"value":689},{"type":29,"tag":127,"props":6577,"children":6578},{"class":675,"line":1363},[6579,6583],{"type":29,"tag":127,"props":6580,"children":6581},{"style":686},[6582],{"type":56,"value":5466},{"type":29,"tag":127,"props":6584,"children":6585},{"style":718},[6586],{"type":56,"value":6288},{"type":29,"tag":127,"props":6588,"children":6590},{"class":6589,"line":1376},[675,738],[6591,6596],{"type":29,"tag":127,"props":6592,"children":6593},{"style":680},[6594],{"type":56,"value":6595},"  cache",{"type":29,"tag":127,"props":6597,"children":6598},{"style":686},[6599],{"type":56,"value":689},{"type":29,"tag":127,"props":6601,"children":6603},{"class":6602,"line":1389},[675,738],[6604,6608,6613,6617],{"type":29,"tag":127,"props":6605,"children":6606},{"style":686},[6607],{"type":56,"value":5466},{"type":29,"tag":127,"props":6609,"children":6610},{"style":680},[6611],{"type":56,"value":6612},"key",{"type":29,"tag":127,"props":6614,"children":6615},{"style":686},[6616],{"type":56,"value":715},{"type":29,"tag":127,"props":6618,"children":6619},{"style":718},[6620],{"type":56,"value":6621},"$CI_JOB_NAME\n",{"type":29,"tag":127,"props":6623,"children":6625},{"class":6624,"line":1398},[675,738],[6626,6631],{"type":29,"tag":127,"props":6627,"children":6628},{"style":680},[6629],{"type":56,"value":6630},"      paths",{"type":29,"tag":127,"props":6632,"children":6633},{"style":686},[6634],{"type":56,"value":689},{"type":29,"tag":127,"props":6636,"children":6638},{"class":6637,"line":1411},[675,738],[6639,6644],{"type":29,"tag":127,"props":6640,"children":6641},{"style":686},[6642],{"type":56,"value":6643},"        - ",{"type":29,"tag":127,"props":6645,"children":6646},{"style":718},[6647],{"type":56,"value":6648},"$COMPOSER_CACHE_DIR\n",{"type":29,"tag":127,"props":6650,"children":6652},{"class":6651,"line":1424},[675,738],[6653,6657],{"type":29,"tag":127,"props":6654,"children":6655},{"style":686},[6656],{"type":56,"value":6643},{"type":29,"tag":127,"props":6658,"children":6659},{"style":718},[6660],{"type":56,"value":6661},"$npm_config_cache\n",{"type":29,"tag":127,"props":6663,"children":6664},{"class":675,"line":1433},[6665,6669],{"type":29,"tag":127,"props":6666,"children":6667},{"style":680},[6668],{"type":56,"value":5496},{"type":29,"tag":127,"props":6670,"children":6671},{"style":686},[6672],{"type":56,"value":689},{"type":29,"tag":127,"props":6674,"children":6675},{"class":675,"line":1446},[6676,6680,6684,6688],{"type":29,"tag":127,"props":6677,"children":6678},{"style":686},[6679],{"type":56,"value":5466},{"type":29,"tag":127,"props":6681,"children":6682},{"style":680},[6683],{"type":56,"value":5729},{"type":29,"tag":127,"props":6685,"children":6686},{"style":686},[6687],{"type":56,"value":715},{"type":29,"tag":127,"props":6689,"children":6690},{"style":718},[6691],{"type":56,"value":5738},{"type":29,"tag":127,"props":6693,"children":6694},{"class":675,"line":1459},[6695,6699,6703],{"type":29,"tag":127,"props":6696,"children":6697},{"style":680},[6698],{"type":56,"value":5746},{"type":29,"tag":127,"props":6700,"children":6701},{"style":686},[6702],{"type":56,"value":715},{"type":29,"tag":127,"props":6704,"children":6705},{"style":718},[6706],{"type":56,"value":5755},{"type":29,"tag":127,"props":6708,"children":6709},{"class":675,"line":1472},[6710,6714,6718,6722],{"type":29,"tag":127,"props":6711,"children":6712},{"style":686},[6713],{"type":56,"value":5466},{"type":29,"tag":127,"props":6715,"children":6716},{"style":680},[6717],{"type":56,"value":5729},{"type":29,"tag":127,"props":6719,"children":6720},{"style":686},[6721],{"type":56,"value":715},{"type":29,"tag":127,"props":6723,"children":6724},{"style":718},[6725],{"type":56,"value":5775},{"type":29,"tag":48,"props":6727,"children":6728},{},[6729,6731,6736],{"type":56,"value":6730},"Let's combine it with our release pipeline from the ",{"type":29,"tag":643,"props":6732,"children":6734},{"href":6733},"/en/blog/shopware-plugin-gitlab-pipeline-release#with-semantic-release",[6735],{"type":56,"value":6260},{"type":56,"value":916},{"type":29,"tag":48,"props":6738,"children":6739},{},[6740],{"type":56,"value":6741},"It's important to pass the built artifacts over to the next job.",{"type":29,"tag":657,"props":6743,"children":6746},{"className":667,"code":6744,"filename":5556,"highlights":6745,"language":508,"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",[1446,1459,1472,1480],[6747],{"type":29,"tag":670,"props":6748,"children":6749},{"__ignoreMap":7},[6750,6761,6772,6783,6790,6801,6812,6827,6846,6861,6872,6887,6902,6913,6924,6935,6954,6965,6976,6987,7000,7013,7026,7039,7050,7069,7084,7103,7110,7121,7136,7147,7163,7182,7197,7208,7220,7231,7250,7265],{"type":29,"tag":127,"props":6751,"children":6752},{"class":675,"line":676},[6753,6757],{"type":29,"tag":127,"props":6754,"children":6755},{"style":680},[6756],{"type":56,"value":5377},{"type":29,"tag":127,"props":6758,"children":6759},{"style":686},[6760],{"type":56,"value":689},{"type":29,"tag":127,"props":6762,"children":6763},{"class":675,"line":342},[6764,6768],{"type":29,"tag":127,"props":6765,"children":6766},{"style":686},[6767],{"type":56,"value":5389},{"type":29,"tag":127,"props":6769,"children":6770},{"style":718},[6771],{"type":56,"value":5394},{"type":29,"tag":127,"props":6773,"children":6774},{"class":675,"line":704},[6775,6779],{"type":29,"tag":127,"props":6776,"children":6777},{"style":686},[6778],{"type":56,"value":5389},{"type":29,"tag":127,"props":6780,"children":6781},{"style":718},[6782],{"type":56,"value":6437},{"type":29,"tag":127,"props":6784,"children":6785},{"class":675,"line":724},[6786],{"type":29,"tag":127,"props":6787,"children":6788},{"emptyLinePlaceholder":500},[6789],{"type":56,"value":1395},{"type":29,"tag":127,"props":6791,"children":6792},{"class":675,"line":662},[6793,6797],{"type":29,"tag":127,"props":6794,"children":6795},{"style":680},[6796],{"type":56,"value":6452},{"type":29,"tag":127,"props":6798,"children":6799},{"style":686},[6800],{"type":56,"value":689},{"type":29,"tag":127,"props":6802,"children":6803},{"class":675,"line":663},[6804,6808],{"type":29,"tag":127,"props":6805,"children":6806},{"style":680},[6807],{"type":56,"value":5421},{"type":29,"tag":127,"props":6809,"children":6810},{"style":686},[6811],{"type":56,"value":689},{"type":29,"tag":127,"props":6813,"children":6814},{"class":675,"line":664},[6815,6819,6823],{"type":29,"tag":127,"props":6816,"children":6817},{"style":680},[6818],{"type":56,"value":5635},{"type":29,"tag":127,"props":6820,"children":6821},{"style":686},[6822],{"type":56,"value":715},{"type":29,"tag":127,"props":6824,"children":6825},{"style":718},[6826],{"type":56,"value":6484},{"type":29,"tag":127,"props":6828,"children":6829},{"class":675,"line":665},[6830,6834,6838,6842],{"type":29,"tag":127,"props":6831,"children":6832},{"style":680},[6833],{"type":56,"value":5652},{"type":29,"tag":127,"props":6835,"children":6836},{"style":686},[6837],{"type":56,"value":5657},{"type":29,"tag":127,"props":6839,"children":6840},{"style":718},[6841],{"type":56,"value":5662},{"type":29,"tag":127,"props":6843,"children":6844},{"style":686},[6845],{"type":56,"value":5667},{"type":29,"tag":127,"props":6847,"children":6848},{"class":675,"line":666},[6849,6853,6857],{"type":29,"tag":127,"props":6850,"children":6851},{"style":680},[6852],{"type":56,"value":5438},{"type":29,"tag":127,"props":6854,"children":6855},{"style":686},[6856],{"type":56,"value":715},{"type":29,"tag":127,"props":6858,"children":6859},{"style":718},[6860],{"type":56,"value":6437},{"type":29,"tag":127,"props":6862,"children":6863},{"class":675,"line":1325},[6864,6868],{"type":29,"tag":127,"props":6865,"children":6866},{"style":680},[6867],{"type":56,"value":6526},{"type":29,"tag":127,"props":6869,"children":6870},{"style":686},[6871],{"type":56,"value":689},{"type":29,"tag":127,"props":6873,"children":6874},{"class":675,"line":1338},[6875,6879,6883],{"type":29,"tag":127,"props":6876,"children":6877},{"style":680},[6878],{"type":56,"value":6538},{"type":29,"tag":127,"props":6880,"children":6881},{"style":686},[6882],{"type":56,"value":715},{"type":29,"tag":127,"props":6884,"children":6885},{"style":718},[6886],{"type":56,"value":6547},{"type":29,"tag":127,"props":6888,"children":6889},{"class":675,"line":118},[6890,6894,6898],{"type":29,"tag":127,"props":6891,"children":6892},{"style":680},[6893],{"type":56,"value":6555},{"type":29,"tag":127,"props":6895,"children":6896},{"style":686},[6897],{"type":56,"value":715},{"type":29,"tag":127,"props":6899,"children":6900},{"style":718},[6901],{"type":56,"value":6564},{"type":29,"tag":127,"props":6903,"children":6904},{"class":675,"line":1363},[6905,6909],{"type":29,"tag":127,"props":6906,"children":6907},{"style":680},[6908],{"type":56,"value":5454},{"type":29,"tag":127,"props":6910,"children":6911},{"style":686},[6912],{"type":56,"value":689},{"type":29,"tag":127,"props":6914,"children":6915},{"class":675,"line":1376},[6916,6920],{"type":29,"tag":127,"props":6917,"children":6918},{"style":686},[6919],{"type":56,"value":5466},{"type":29,"tag":127,"props":6921,"children":6922},{"style":718},[6923],{"type":56,"value":6288},{"type":29,"tag":127,"props":6925,"children":6926},{"class":675,"line":1389},[6927,6931],{"type":29,"tag":127,"props":6928,"children":6929},{"style":680},[6930],{"type":56,"value":6595},{"type":29,"tag":127,"props":6932,"children":6933},{"style":686},[6934],{"type":56,"value":689},{"type":29,"tag":127,"props":6936,"children":6937},{"class":675,"line":1398},[6938,6942,6946,6950],{"type":29,"tag":127,"props":6939,"children":6940},{"style":686},[6941],{"type":56,"value":5466},{"type":29,"tag":127,"props":6943,"children":6944},{"style":680},[6945],{"type":56,"value":6612},{"type":29,"tag":127,"props":6947,"children":6948},{"style":686},[6949],{"type":56,"value":715},{"type":29,"tag":127,"props":6951,"children":6952},{"style":718},[6953],{"type":56,"value":6621},{"type":29,"tag":127,"props":6955,"children":6956},{"class":675,"line":1411},[6957,6961],{"type":29,"tag":127,"props":6958,"children":6959},{"style":680},[6960],{"type":56,"value":6630},{"type":29,"tag":127,"props":6962,"children":6963},{"style":686},[6964],{"type":56,"value":689},{"type":29,"tag":127,"props":6966,"children":6967},{"class":675,"line":1424},[6968,6972],{"type":29,"tag":127,"props":6969,"children":6970},{"style":686},[6971],{"type":56,"value":6643},{"type":29,"tag":127,"props":6973,"children":6974},{"style":718},[6975],{"type":56,"value":6648},{"type":29,"tag":127,"props":6977,"children":6978},{"class":675,"line":1433},[6979,6983],{"type":29,"tag":127,"props":6980,"children":6981},{"style":686},[6982],{"type":56,"value":6643},{"type":29,"tag":127,"props":6984,"children":6985},{"style":718},[6986],{"type":56,"value":6661},{"type":29,"tag":127,"props":6988,"children":6990},{"class":6989,"line":1446},[675,738],[6991,6996],{"type":29,"tag":127,"props":6992,"children":6993},{"style":680},[6994],{"type":56,"value":6995},"  artifacts",{"type":29,"tag":127,"props":6997,"children":6998},{"style":686},[6999],{"type":56,"value":689},{"type":29,"tag":127,"props":7001,"children":7003},{"class":7002,"line":1459},[675,738],[7004,7009],{"type":29,"tag":127,"props":7005,"children":7006},{"style":680},[7007],{"type":56,"value":7008},"    paths",{"type":29,"tag":127,"props":7010,"children":7011},{"style":686},[7012],{"type":56,"value":689},{"type":29,"tag":127,"props":7014,"children":7016},{"class":7015,"line":1472},[675,738],[7017,7021],{"type":29,"tag":127,"props":7018,"children":7019},{"style":686},[7020],{"type":56,"value":744},{"type":29,"tag":127,"props":7022,"children":7023},{"style":718},[7024],{"type":56,"value":7025},"src/Resources/public\n",{"type":29,"tag":127,"props":7027,"children":7029},{"class":7028,"line":1480},[675,738],[7030,7034],{"type":29,"tag":127,"props":7031,"children":7032},{"style":686},[7033],{"type":56,"value":744},{"type":29,"tag":127,"props":7035,"children":7036},{"style":718},[7037],{"type":56,"value":7038},"src/Storefront/Resources/public\n",{"type":29,"tag":127,"props":7040,"children":7041},{"class":675,"line":1493},[7042,7046],{"type":29,"tag":127,"props":7043,"children":7044},{"style":680},[7045],{"type":56,"value":5496},{"type":29,"tag":127,"props":7047,"children":7048},{"style":686},[7049],{"type":56,"value":689},{"type":29,"tag":127,"props":7051,"children":7052},{"class":675,"line":1506},[7053,7057,7061,7065],{"type":29,"tag":127,"props":7054,"children":7055},{"style":686},[7056],{"type":56,"value":5466},{"type":29,"tag":127,"props":7058,"children":7059},{"style":680},[7060],{"type":56,"value":5729},{"type":29,"tag":127,"props":7062,"children":7063},{"style":686},[7064],{"type":56,"value":715},{"type":29,"tag":127,"props":7066,"children":7067},{"style":718},[7068],{"type":56,"value":5738},{"type":29,"tag":127,"props":7070,"children":7071},{"class":675,"line":1519},[7072,7076,7080],{"type":29,"tag":127,"props":7073,"children":7074},{"style":680},[7075],{"type":56,"value":5746},{"type":29,"tag":127,"props":7077,"children":7078},{"style":686},[7079],{"type":56,"value":715},{"type":29,"tag":127,"props":7081,"children":7082},{"style":718},[7083],{"type":56,"value":5755},{"type":29,"tag":127,"props":7085,"children":7086},{"class":675,"line":1532},[7087,7091,7095,7099],{"type":29,"tag":127,"props":7088,"children":7089},{"style":686},[7090],{"type":56,"value":5466},{"type":29,"tag":127,"props":7092,"children":7093},{"style":680},[7094],{"type":56,"value":5729},{"type":29,"tag":127,"props":7096,"children":7097},{"style":686},[7098],{"type":56,"value":715},{"type":29,"tag":127,"props":7100,"children":7101},{"style":718},[7102],{"type":56,"value":5775},{"type":29,"tag":127,"props":7104,"children":7105},{"class":675,"line":1545},[7106],{"type":29,"tag":127,"props":7107,"children":7108},{"emptyLinePlaceholder":500},[7109],{"type":56,"value":1395},{"type":29,"tag":127,"props":7111,"children":7112},{"class":675,"line":2398},[7113,7117],{"type":29,"tag":127,"props":7114,"children":7115},{"style":680},[7116],{"type":56,"value":5597},{"type":29,"tag":127,"props":7118,"children":7119},{"style":686},[7120],{"type":56,"value":689},{"type":29,"tag":127,"props":7122,"children":7123},{"class":675,"line":2406},[7124,7128,7132],{"type":29,"tag":127,"props":7125,"children":7126},{"style":680},[7127],{"type":56,"value":5438},{"type":29,"tag":127,"props":7129,"children":7130},{"style":686},[7131],{"type":56,"value":715},{"type":29,"tag":127,"props":7133,"children":7134},{"style":718},[7135],{"type":56,"value":5394},{"type":29,"tag":127,"props":7137,"children":7138},{"class":675,"line":2426},[7139,7143],{"type":29,"tag":127,"props":7140,"children":7141},{"style":680},[7142],{"type":56,"value":5421},{"type":29,"tag":127,"props":7144,"children":7145},{"style":686},[7146],{"type":56,"value":689},{"type":29,"tag":127,"props":7148,"children":7149},{"class":675,"line":2447},[7150,7154,7158],{"type":29,"tag":127,"props":7151,"children":7152},{"style":680},[7153],{"type":56,"value":5635},{"type":29,"tag":127,"props":7155,"children":7156},{"style":686},[7157],{"type":56,"value":715},{"type":29,"tag":127,"props":7159,"children":7160},{"style":718},[7161],{"type":56,"value":7162},"ghcr.io/voxpupuli/semantic-release:latest\n",{"type":29,"tag":127,"props":7164,"children":7165},{"class":675,"line":2459},[7166,7170,7174,7178],{"type":29,"tag":127,"props":7167,"children":7168},{"style":680},[7169],{"type":56,"value":5652},{"type":29,"tag":127,"props":7171,"children":7172},{"style":686},[7173],{"type":56,"value":5657},{"type":29,"tag":127,"props":7175,"children":7176},{"style":718},[7177],{"type":56,"value":5662},{"type":29,"tag":127,"props":7179,"children":7180},{"style":686},[7181],{"type":56,"value":5667},{"type":29,"tag":127,"props":7183,"children":7184},{"class":675,"line":2475},[7185,7189,7193],{"type":29,"tag":127,"props":7186,"children":7187},{"style":680},[7188],{"type":56,"value":5675},{"type":29,"tag":127,"props":7190,"children":7191},{"style":686},[7192],{"type":56,"value":715},{"type":29,"tag":127,"props":7194,"children":7195},{"style":2290},[7196],{"type":56,"value":2293},{"type":29,"tag":127,"props":7198,"children":7199},{"class":675,"line":2483},[7200,7204],{"type":29,"tag":127,"props":7201,"children":7202},{"style":680},[7203],{"type":56,"value":5454},{"type":29,"tag":127,"props":7205,"children":7206},{"style":686},[7207],{"type":56,"value":689},{"type":29,"tag":127,"props":7209,"children":7210},{"class":675,"line":1957},[7211,7215],{"type":29,"tag":127,"props":7212,"children":7213},{"style":686},[7214],{"type":56,"value":5466},{"type":29,"tag":127,"props":7216,"children":7217},{"style":718},[7218],{"type":56,"value":7219},"/docker-entrypoint.sh\n",{"type":29,"tag":127,"props":7221,"children":7222},{"class":675,"line":1958},[7223,7227],{"type":29,"tag":127,"props":7224,"children":7225},{"style":680},[7226],{"type":56,"value":5496},{"type":29,"tag":127,"props":7228,"children":7229},{"style":686},[7230],{"type":56,"value":689},{"type":29,"tag":127,"props":7232,"children":7233},{"class":675,"line":1959},[7234,7238,7242,7246],{"type":29,"tag":127,"props":7235,"children":7236},{"style":686},[7237],{"type":56,"value":5466},{"type":29,"tag":127,"props":7239,"children":7240},{"style":680},[7241],{"type":56,"value":5729},{"type":29,"tag":127,"props":7243,"children":7244},{"style":686},[7245],{"type":56,"value":715},{"type":29,"tag":127,"props":7247,"children":7248},{"style":718},[7249],{"type":56,"value":5738},{"type":29,"tag":127,"props":7251,"children":7252},{"class":675,"line":1960},[7253,7257,7261],{"type":29,"tag":127,"props":7254,"children":7255},{"style":680},[7256],{"type":56,"value":5746},{"type":29,"tag":127,"props":7258,"children":7259},{"style":686},[7260],{"type":56,"value":715},{"type":29,"tag":127,"props":7262,"children":7263},{"style":718},[7264],{"type":56,"value":5755},{"type":29,"tag":127,"props":7266,"children":7267},{"class":675,"line":2546},[7268,7272,7276,7280],{"type":29,"tag":127,"props":7269,"children":7270},{"style":686},[7271],{"type":56,"value":5466},{"type":29,"tag":127,"props":7273,"children":7274},{"style":680},[7275],{"type":56,"value":5729},{"type":29,"tag":127,"props":7277,"children":7278},{"style":686},[7279],{"type":56,"value":715},{"type":29,"tag":127,"props":7281,"children":7282},{"style":718},[7283],{"type":56,"value":5775},{"type":29,"tag":48,"props":7285,"children":7286},{},[7287],{"type":29,"tag":127,"props":7288,"children":7290},{"className":7289},[5242],[7291],{"type":56,"value":7292},"That's it!",{"type":29,"tag":48,"props":7294,"children":7295},{},[7296],{"type":56,"value":6185},{"type":29,"tag":960,"props":7298,"children":7299},{},[7300,7305,7310],{"type":29,"tag":812,"props":7301,"children":7302},{},[7303],{"type":56,"value":7304},"Build all the assets",{"type":29,"tag":812,"props":7306,"children":7307},{},[7308],{"type":56,"value":7309},"Pass them to the second job",{"type":29,"tag":812,"props":7311,"children":7312},{},[7313],{"type":56,"value":7314},"Run the release process as described previously",{"type":29,"tag":1826,"props":7316,"children":7317},{},[7318],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":7320},[7321,7322],{"id":6277,"depth":342,"text":6280},{"id":6383,"depth":342,"text":6386},{"_path":553,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":554,"description":555,"author":518,"image":519,"releaseDate":533,"blogCategories":7324,"articleTags":7325,"tags":7326,"body":7327,"_type":346,"_id":559,"_source":348,"_file":560,"_stem":561,"_extension":351},[522,523],[523,536,537],[461,24],{"type":26,"children":7328,"toc":9593},[7329,7333,7338,7389,7395,7407,7418,7460,7473,7481,7492,7498,7503,7773,7778,7783,7788,7793,7804,7809,7834,7840,7852,8620,8624,8652,8657,8663,8668,9589],{"type":29,"tag":61,"props":7330,"children":7332},{"alt":7,"aspect-ratio":1849,"height":1850,"object-fit":1851,"src":7331},"/blog/shopware-plugin-test.png",[],{"type":29,"tag":48,"props":7334,"children":7335},{},[7336],{"type":56,"value":7337},"When it comes to testing a Shopware 6 plugin, there are two types of test that can be performed:",{"type":29,"tag":960,"props":7339,"children":7340},{},[7341,7377],{"type":29,"tag":812,"props":7342,"children":7343},{},[7344,7346,7352,7354],{"type":56,"value":7345},"Testing the code itself (",{"type":29,"tag":643,"props":7347,"children":7349},{"href":7348},"https://developer.shopware.com/docs/guides/plugins/plugins/testing/",[7350],{"type":56,"value":7351},"more in the official documentation",{"type":56,"value":7353},")\n",{"type":29,"tag":960,"props":7355,"children":7356},{},[7357,7362,7367,7372],{"type":29,"tag":812,"props":7358,"children":7359},{},[7360],{"type":56,"value":7361},"PHP unit test",{"type":29,"tag":812,"props":7363,"children":7364},{},[7365],{"type":56,"value":7366},"Jest unit tests in Shopware's storefront",{"type":29,"tag":812,"props":7368,"children":7369},{},[7370],{"type":56,"value":7371},"Jest unit tests in Shopware's administration",{"type":29,"tag":812,"props":7373,"children":7374},{},[7375],{"type":56,"value":7376},"End-to-End (E2E) Testing",{"type":29,"tag":812,"props":7378,"children":7379},{},[7380,7382,7387],{"type":56,"value":7381},"Ensuring high code quality (",{"type":29,"tag":643,"props":7383,"children":7385},{"href":7384},"https://developer.shopware.com/docs/products/cli/validation.html",[7386],{"type":56,"value":7351},{"type":56,"value":7388},")",{"type":29,"tag":90,"props":7390,"children":7392},{"id":7391},"code-quality",[7393],{"type":56,"value":7394},"Code quality",{"type":29,"tag":48,"props":7396,"children":7397},{},[7398,7400,7405],{"type":56,"value":7399},"Let's start with code quality because it's easier to run it outside a ",{"type":29,"tag":670,"props":7401,"children":7403},{"className":7402},[],[7404],{"type":56,"value":5262},{"type":56,"value":7406}," environment.",{"type":29,"tag":48,"props":7408,"children":7409},{},[7410,7412,7417],{"type":56,"value":7411},"We will again use the ",{"type":29,"tag":670,"props":7413,"children":7415},{"className":7414},[],[7416],{"type":56,"value":1916},{"type":56,"value":916},{"type":29,"tag":657,"props":7419,"children":7421},{"code":7420,"language":3010,"meta":7,"className":3008,"style":7},"shopware-cli extension validate --full --reporter summary .\n",[7422],{"type":29,"tag":670,"props":7423,"children":7424},{"__ignoreMap":7},[7425],{"type":29,"tag":127,"props":7426,"children":7427},{"class":675,"line":676},[7428,7432,7436,7441,7446,7451,7456],{"type":29,"tag":127,"props":7429,"children":7430},{"style":3020},[7431],{"type":56,"value":1916},{"type":29,"tag":127,"props":7433,"children":7434},{"style":718},[7435],{"type":56,"value":6304},{"type":29,"tag":127,"props":7437,"children":7438},{"style":718},[7439],{"type":56,"value":7440}," validate",{"type":29,"tag":127,"props":7442,"children":7443},{"style":2290},[7444],{"type":56,"value":7445}," --full",{"type":29,"tag":127,"props":7447,"children":7448},{"style":2290},[7449],{"type":56,"value":7450}," --reporter",{"type":29,"tag":127,"props":7452,"children":7453},{"style":718},[7454],{"type":56,"value":7455}," summary",{"type":29,"tag":127,"props":7457,"children":7458},{"style":718},[7459],{"type":56,"value":6314},{"type":29,"tag":48,"props":7461,"children":7462},{},[7463,7465,7471],{"type":56,"value":7464},"This will run all the tests described ",{"type":29,"tag":643,"props":7466,"children":7468},{"href":7467},"https://developer.shopware.com/docs/products/cli/validation.html#running-all-validation-tools",[7469],{"type":56,"value":7470},"here",{"type":56,"value":7472},"\nand hopefully produce an output like this:",{"type":29,"tag":657,"props":7474,"children":7476},{"code":7475},"✖ 0 problems (0 errors, 0 warnings)\n",[7477],{"type":29,"tag":670,"props":7478,"children":7479},{"__ignoreMap":7},[7480],{"type":56,"value":7475},{"type":29,"tag":48,"props":7482,"children":7483},{},[7484,7486,7491],{"type":56,"value":7485},"If there are any errors, refer to the Shopware documentation how to fix them and rerun only the failed tests like described ",{"type":29,"tag":643,"props":7487,"children":7489},{"href":7488},"https://developer.shopware.com/docs/products/cli/validation.html#running-specific-tools",[7490],{"type":56,"value":7470},{"type":56,"value":916},{"type":29,"tag":122,"props":7493,"children":7495},{"id":7494},"code-quality-pipeline",[7496],{"type":56,"value":7497},"Code quality pipeline",{"type":29,"tag":48,"props":7499,"children":7500},{},[7501],{"type":56,"value":7502},"Now we will run it in GitLab.",{"type":29,"tag":657,"props":7504,"children":7507},{"code":7505,"filename":5556,"highlights":7506,"language":508,"meta":7,"className":667,"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",[663,1376,1389,1398,1411,1424],[7508],{"type":29,"tag":670,"props":7509,"children":7510},{"__ignoreMap":7},[7511,7522,7534,7541,7552,7564,7581,7601,7617,7629,7641,7653,7665,7682,7695,7716,7736,7753],{"type":29,"tag":127,"props":7512,"children":7513},{"class":675,"line":676},[7514,7518],{"type":29,"tag":127,"props":7515,"children":7516},{"style":680},[7517],{"type":56,"value":5377},{"type":29,"tag":127,"props":7519,"children":7520},{"style":686},[7521],{"type":56,"value":689},{"type":29,"tag":127,"props":7523,"children":7524},{"class":675,"line":342},[7525,7529],{"type":29,"tag":127,"props":7526,"children":7527},{"style":686},[7528],{"type":56,"value":5389},{"type":29,"tag":127,"props":7530,"children":7531},{"style":718},[7532],{"type":56,"value":7533},"test\n",{"type":29,"tag":127,"props":7535,"children":7536},{"class":675,"line":704},[7537],{"type":29,"tag":127,"props":7538,"children":7539},{"emptyLinePlaceholder":500},[7540],{"type":56,"value":1395},{"type":29,"tag":127,"props":7542,"children":7543},{"class":675,"line":724},[7544,7548],{"type":29,"tag":127,"props":7545,"children":7546},{"style":680},[7547],{"type":56,"value":7391},{"type":29,"tag":127,"props":7549,"children":7550},{"style":686},[7551],{"type":56,"value":689},{"type":29,"tag":127,"props":7553,"children":7554},{"class":675,"line":662},[7555,7560],{"type":29,"tag":127,"props":7556,"children":7557},{"style":680},[7558],{"type":56,"value":7559},"   image",{"type":29,"tag":127,"props":7561,"children":7562},{"style":686},[7563],{"type":56,"value":689},{"type":29,"tag":127,"props":7565,"children":7567},{"class":7566,"line":663},[675,738],[7568,7573,7577],{"type":29,"tag":127,"props":7569,"children":7570},{"style":680},[7571],{"type":56,"value":7572},"      name",{"type":29,"tag":127,"props":7574,"children":7575},{"style":686},[7576],{"type":56,"value":715},{"type":29,"tag":127,"props":7578,"children":7579},{"style":718},[7580],{"type":56,"value":6484},{"type":29,"tag":127,"props":7582,"children":7583},{"class":675,"line":664},[7584,7589,7593,7597],{"type":29,"tag":127,"props":7585,"children":7586},{"style":680},[7587],{"type":56,"value":7588},"      entrypoint",{"type":29,"tag":127,"props":7590,"children":7591},{"style":686},[7592],{"type":56,"value":5657},{"type":29,"tag":127,"props":7594,"children":7595},{"style":718},[7596],{"type":56,"value":5662},{"type":29,"tag":127,"props":7598,"children":7599},{"style":686},[7600],{"type":56,"value":5667},{"type":29,"tag":127,"props":7602,"children":7603},{"class":675,"line":665},[7604,7609,7613],{"type":29,"tag":127,"props":7605,"children":7606},{"style":680},[7607],{"type":56,"value":7608},"   stage",{"type":29,"tag":127,"props":7610,"children":7611},{"style":686},[7612],{"type":56,"value":715},{"type":29,"tag":127,"props":7614,"children":7615},{"style":718},[7616],{"type":56,"value":7533},{"type":29,"tag":127,"props":7618,"children":7619},{"class":675,"line":666},[7620,7625],{"type":29,"tag":127,"props":7621,"children":7622},{"style":680},[7623],{"type":56,"value":7624},"   script",{"type":29,"tag":127,"props":7626,"children":7627},{"style":686},[7628],{"type":56,"value":689},{"type":29,"tag":127,"props":7630,"children":7631},{"class":675,"line":1325},[7632,7636],{"type":29,"tag":127,"props":7633,"children":7634},{"style":686},[7635],{"type":56,"value":744},{"type":29,"tag":127,"props":7637,"children":7638},{"style":718},[7639],{"type":56,"value":7640},"shopware-cli extension validate --full . | tee report.json\n",{"type":29,"tag":127,"props":7642,"children":7643},{"class":675,"line":1338},[7644,7649],{"type":29,"tag":127,"props":7645,"children":7646},{"style":680},[7647],{"type":56,"value":7648},"   artifacts",{"type":29,"tag":127,"props":7650,"children":7651},{"style":686},[7652],{"type":56,"value":689},{"type":29,"tag":127,"props":7654,"children":7655},{"class":675,"line":118},[7656,7661],{"type":29,"tag":127,"props":7657,"children":7658},{"style":680},[7659],{"type":56,"value":7660},"      reports",{"type":29,"tag":127,"props":7662,"children":7663},{"style":686},[7664],{"type":56,"value":689},{"type":29,"tag":127,"props":7666,"children":7667},{"class":675,"line":1363},[7668,7673,7677],{"type":29,"tag":127,"props":7669,"children":7670},{"style":680},[7671],{"type":56,"value":7672},"         codequality",{"type":29,"tag":127,"props":7674,"children":7675},{"style":686},[7676],{"type":56,"value":715},{"type":29,"tag":127,"props":7678,"children":7679},{"style":718},[7680],{"type":56,"value":7681},"report.json\n",{"type":29,"tag":127,"props":7683,"children":7685},{"class":7684,"line":1376},[675,738],[7686,7691],{"type":29,"tag":127,"props":7687,"children":7688},{"style":680},[7689],{"type":56,"value":7690},"   rules",{"type":29,"tag":127,"props":7692,"children":7693},{"style":686},[7694],{"type":56,"value":689},{"type":29,"tag":127,"props":7696,"children":7698},{"class":7697,"line":1389},[675,738],[7699,7703,7707,7711],{"type":29,"tag":127,"props":7700,"children":7701},{"style":686},[7702],{"type":56,"value":744},{"type":29,"tag":127,"props":7704,"children":7705},{"style":680},[7706],{"type":56,"value":5729},{"type":29,"tag":127,"props":7708,"children":7709},{"style":686},[7710],{"type":56,"value":715},{"type":29,"tag":127,"props":7712,"children":7713},{"style":718},[7714],{"type":56,"value":7715},"$CI_PIPELINE_SOURCE == \"merge_request_event\"\n",{"type":29,"tag":127,"props":7717,"children":7719},{"class":7718,"line":1398},[675,738],[7720,7724,7728,7732],{"type":29,"tag":127,"props":7721,"children":7722},{"style":686},[7723],{"type":56,"value":744},{"type":29,"tag":127,"props":7725,"children":7726},{"style":680},[7727],{"type":56,"value":5729},{"type":29,"tag":127,"props":7729,"children":7730},{"style":686},[7731],{"type":56,"value":715},{"type":29,"tag":127,"props":7733,"children":7734},{"style":718},[7735],{"type":56,"value":5738},{"type":29,"tag":127,"props":7737,"children":7739},{"class":7738,"line":1411},[675,738],[7740,7745,7749],{"type":29,"tag":127,"props":7741,"children":7742},{"style":680},[7743],{"type":56,"value":7744},"        when",{"type":29,"tag":127,"props":7746,"children":7747},{"style":686},[7748],{"type":56,"value":715},{"type":29,"tag":127,"props":7750,"children":7751},{"style":718},[7752],{"type":56,"value":5755},{"type":29,"tag":127,"props":7754,"children":7756},{"class":7755,"line":1424},[675,738],[7757,7761,7765,7769],{"type":29,"tag":127,"props":7758,"children":7759},{"style":686},[7760],{"type":56,"value":744},{"type":29,"tag":127,"props":7762,"children":7763},{"style":680},[7764],{"type":56,"value":5729},{"type":29,"tag":127,"props":7766,"children":7767},{"style":686},[7768],{"type":56,"value":715},{"type":29,"tag":127,"props":7770,"children":7771},{"style":718},[7772],{"type":56,"value":5775},{"type":29,"tag":48,"props":7774,"children":7775},{},[7776],{"type":56,"value":7777},"This pipeline will run on the default branch and on merge request pipelines.",{"type":29,"tag":48,"props":7779,"children":7780},{},[7781],{"type":56,"value":7782},"Running on the default branch before build and release prevents from accidentally creating a low-quality release.",{"type":29,"tag":48,"props":7784,"children":7785},{},[7786],{"type":56,"value":7787},"A nice touch to the MR pipeline is the Code Quality report integration!",{"type":29,"tag":90,"props":7789,"children":7791},{"id":7790},"php-unit-test",[7792],{"type":56,"value":7361},{"type":29,"tag":48,"props":7794,"children":7795},{},[7796,7798],{"type":56,"value":7797},"First of all, we need to configure PHPUnit by following the ",{"type":29,"tag":643,"props":7799,"children":7801},{"href":7800},"https://developer.shopware.com/docs/guides/plugins/plugins/testing/php-unit.html",[7802],{"type":56,"value":7803},"official shopware documentation",{"type":29,"tag":48,"props":7805,"children":7806},{},[7807],{"type":56,"value":7808},"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":29,"tag":657,"props":7810,"children":7812},{"code":7811,"language":3010,"meta":7,"className":3008,"style":7},"./vendor/bin/phpunit --configuration=\"custom/static-plugins/SwagBasicExample\"\n",[7813],{"type":29,"tag":670,"props":7814,"children":7815},{"__ignoreMap":7},[7816],{"type":29,"tag":127,"props":7817,"children":7818},{"class":675,"line":676},[7819,7824,7829],{"type":29,"tag":127,"props":7820,"children":7821},{"style":3020},[7822],{"type":56,"value":7823},"./vendor/bin/phpunit",{"type":29,"tag":127,"props":7825,"children":7826},{"style":2290},[7827],{"type":56,"value":7828}," --configuration=",{"type":29,"tag":127,"props":7830,"children":7831},{"style":718},[7832],{"type":56,"value":7833},"\"custom/static-plugins/SwagBasicExample\"\n",{"type":29,"tag":122,"props":7835,"children":7837},{"id":7836},"phpunit-pipeline",[7838],{"type":56,"value":7839},"PHPUnit pipeline",{"type":29,"tag":48,"props":7841,"children":7842},{},[7843,7845,7850],{"type":56,"value":7844},"Running PHPUnit for a plugin requires a full Shopware instance. Fortunately, ",{"type":29,"tag":670,"props":7846,"children":7848},{"className":7847},[],[7849],{"type":56,"value":1916},{"type":56,"value":7851}," can help us to deal with it.",{"type":29,"tag":657,"props":7853,"children":7856},{"code":7854,"filename":5556,"highlights":7855,"language":508,"meta":7,"className":667,"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",[666,1325,1338,118,1363,1376,1398,1446,1459,1472,1480,1532,1545,2398,2406,2426,2447,2459,2475,2483,1957,1959],[7857],{"type":29,"tag":670,"props":7858,"children":7859},{"__ignoreMap":7},[7860,7871,7883,7890,7902,7917,7928,7943,7962,7975,7996,8014,8027,8045,8063,8074,8092,8109,8126,8133,8151,8169,8187,8203,8210,8227,8239,8252,8265,8278,8291,8304,8317,8330,8343,8356,8368,8379,8392,8399,8410,8429,8440,8451,8468,8479,8491,8503,8520,8537,8548,8567,8586,8601],{"type":29,"tag":127,"props":7861,"children":7862},{"class":675,"line":676},[7863,7867],{"type":29,"tag":127,"props":7864,"children":7865},{"style":680},[7866],{"type":56,"value":5377},{"type":29,"tag":127,"props":7868,"children":7869},{"style":686},[7870],{"type":56,"value":689},{"type":29,"tag":127,"props":7872,"children":7873},{"class":675,"line":342},[7874,7879],{"type":29,"tag":127,"props":7875,"children":7876},{"style":686},[7877],{"type":56,"value":7878},"   - ",{"type":29,"tag":127,"props":7880,"children":7881},{"style":718},[7882],{"type":56,"value":7533},{"type":29,"tag":127,"props":7884,"children":7885},{"class":675,"line":704},[7886],{"type":29,"tag":127,"props":7887,"children":7888},{"emptyLinePlaceholder":500},[7889],{"type":56,"value":1395},{"type":29,"tag":127,"props":7891,"children":7892},{"class":675,"line":724},[7893,7898],{"type":29,"tag":127,"props":7894,"children":7895},{"style":680},[7896],{"type":56,"value":7897},"phpunit",{"type":29,"tag":127,"props":7899,"children":7900},{"style":686},[7901],{"type":56,"value":689},{"type":29,"tag":127,"props":7903,"children":7904},{"class":675,"line":662},[7905,7909,7913],{"type":29,"tag":127,"props":7906,"children":7907},{"style":680},[7908],{"type":56,"value":5438},{"type":29,"tag":127,"props":7910,"children":7911},{"style":686},[7912],{"type":56,"value":715},{"type":29,"tag":127,"props":7914,"children":7915},{"style":718},[7916],{"type":56,"value":7533},{"type":29,"tag":127,"props":7918,"children":7919},{"class":675,"line":663},[7920,7924],{"type":29,"tag":127,"props":7921,"children":7922},{"style":680},[7923],{"type":56,"value":5421},{"type":29,"tag":127,"props":7925,"children":7926},{"style":686},[7927],{"type":56,"value":689},{"type":29,"tag":127,"props":7929,"children":7930},{"class":675,"line":664},[7931,7935,7939],{"type":29,"tag":127,"props":7932,"children":7933},{"style":680},[7934],{"type":56,"value":5635},{"type":29,"tag":127,"props":7936,"children":7937},{"style":686},[7938],{"type":56,"value":715},{"type":29,"tag":127,"props":7940,"children":7941},{"style":718},[7942],{"type":56,"value":6484},{"type":29,"tag":127,"props":7944,"children":7945},{"class":675,"line":665},[7946,7950,7954,7958],{"type":29,"tag":127,"props":7947,"children":7948},{"style":680},[7949],{"type":56,"value":5652},{"type":29,"tag":127,"props":7951,"children":7952},{"style":686},[7953],{"type":56,"value":5657},{"type":29,"tag":127,"props":7955,"children":7956},{"style":718},[7957],{"type":56,"value":5662},{"type":29,"tag":127,"props":7959,"children":7960},{"style":686},[7961],{"type":56,"value":5667},{"type":29,"tag":127,"props":7963,"children":7965},{"class":7964,"line":666},[675,738],[7966,7971],{"type":29,"tag":127,"props":7967,"children":7968},{"style":680},[7969],{"type":56,"value":7970},"  services",{"type":29,"tag":127,"props":7972,"children":7973},{"style":686},[7974],{"type":56,"value":689},{"type":29,"tag":127,"props":7976,"children":7978},{"class":7977,"line":1325},[675,738],[7979,7983,7987,7991],{"type":29,"tag":127,"props":7980,"children":7981},{"style":686},[7982],{"type":56,"value":5466},{"type":29,"tag":127,"props":7984,"children":7985},{"style":680},[7986],{"type":56,"value":1778},{"type":29,"tag":127,"props":7988,"children":7989},{"style":686},[7990],{"type":56,"value":715},{"type":29,"tag":127,"props":7992,"children":7993},{"style":718},[7994],{"type":56,"value":7995},"mysql:8.3.0\n",{"type":29,"tag":127,"props":7997,"children":7999},{"class":7998,"line":1338},[675,738],[8000,8005,8009],{"type":29,"tag":127,"props":8001,"children":8002},{"style":680},[8003],{"type":56,"value":8004},"      alias",{"type":29,"tag":127,"props":8006,"children":8007},{"style":686},[8008],{"type":56,"value":715},{"type":29,"tag":127,"props":8010,"children":8011},{"style":718},[8012],{"type":56,"value":8013},"test_database\n",{"type":29,"tag":127,"props":8015,"children":8017},{"class":8016,"line":118},[675,738],[8018,8023],{"type":29,"tag":127,"props":8019,"children":8020},{"style":680},[8021],{"type":56,"value":8022},"      variables",{"type":29,"tag":127,"props":8024,"children":8025},{"style":686},[8026],{"type":56,"value":689},{"type":29,"tag":127,"props":8028,"children":8030},{"class":8029,"line":1363},[675,738],[8031,8036,8040],{"type":29,"tag":127,"props":8032,"children":8033},{"style":680},[8034],{"type":56,"value":8035},"        MYSQL_SKIP_TEST_DB",{"type":29,"tag":127,"props":8037,"children":8038},{"style":686},[8039],{"type":56,"value":715},{"type":29,"tag":127,"props":8041,"children":8042},{"style":718},[8043],{"type":56,"value":8044},"'yes'\n",{"type":29,"tag":127,"props":8046,"children":8048},{"class":8047,"line":1376},[675,738],[8049,8054,8058],{"type":29,"tag":127,"props":8050,"children":8051},{"style":680},[8052],{"type":56,"value":8053},"        MYSQL_ALLOW_EMPTY_PASSWORD",{"type":29,"tag":127,"props":8055,"children":8056},{"style":686},[8057],{"type":56,"value":715},{"type":29,"tag":127,"props":8059,"children":8060},{"style":2290},[8061],{"type":56,"value":8062},"yes\n",{"type":29,"tag":127,"props":8064,"children":8065},{"class":675,"line":1389},[8066,8070],{"type":29,"tag":127,"props":8067,"children":8068},{"style":680},[8069],{"type":56,"value":6526},{"type":29,"tag":127,"props":8071,"children":8072},{"style":686},[8073],{"type":56,"value":689},{"type":29,"tag":127,"props":8075,"children":8077},{"class":8076,"line":1398},[675,738],[8078,8083,8087],{"type":29,"tag":127,"props":8079,"children":8080},{"style":680},[8081],{"type":56,"value":8082},"    GIT_STRATEGY",{"type":29,"tag":127,"props":8084,"children":8085},{"style":686},[8086],{"type":56,"value":715},{"type":29,"tag":127,"props":8088,"children":8089},{"style":718},[8090],{"type":56,"value":8091},"none\n",{"type":29,"tag":127,"props":8093,"children":8094},{"class":675,"line":1411},[8095,8100,8104],{"type":29,"tag":127,"props":8096,"children":8097},{"style":680},[8098],{"type":56,"value":8099},"    SHOPWARE_ROOT",{"type":29,"tag":127,"props":8101,"children":8102},{"style":686},[8103],{"type":56,"value":715},{"type":29,"tag":127,"props":8105,"children":8106},{"style":718},[8107],{"type":56,"value":8108},"${CI_PROJECT_DIR}/shopware\n",{"type":29,"tag":127,"props":8110,"children":8111},{"class":675,"line":1424},[8112,8117,8121],{"type":29,"tag":127,"props":8113,"children":8114},{"style":680},[8115],{"type":56,"value":8116},"    SHOPWARE_VERSION",{"type":29,"tag":127,"props":8118,"children":8119},{"style":686},[8120],{"type":56,"value":715},{"type":29,"tag":127,"props":8122,"children":8123},{"style":2290},[8124],{"type":56,"value":8125},"6.6.10.13\n",{"type":29,"tag":127,"props":8127,"children":8128},{"class":675,"line":1433},[8129],{"type":29,"tag":127,"props":8130,"children":8131},{"style":686},[8132],{"type":56,"value":1232},{"type":29,"tag":127,"props":8134,"children":8136},{"class":8135,"line":1446},[675,738],[8137,8142,8146],{"type":29,"tag":127,"props":8138,"children":8139},{"style":680},[8140],{"type":56,"value":8141},"    APP_SECRET",{"type":29,"tag":127,"props":8143,"children":8144},{"style":686},[8145],{"type":56,"value":715},{"type":29,"tag":127,"props":8147,"children":8148},{"style":718},[8149],{"type":56,"value":8150},"def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48\n",{"type":29,"tag":127,"props":8152,"children":8154},{"class":8153,"line":1459},[675,738],[8155,8160,8164],{"type":29,"tag":127,"props":8156,"children":8157},{"style":680},[8158],{"type":56,"value":8159},"    MESSENGER_TRANSPORT_DSN",{"type":29,"tag":127,"props":8161,"children":8162},{"style":686},[8163],{"type":56,"value":715},{"type":29,"tag":127,"props":8165,"children":8166},{"style":718},[8167],{"type":56,"value":8168},"sync://\n",{"type":29,"tag":127,"props":8170,"children":8172},{"class":8171,"line":1472},[675,738],[8173,8178,8182],{"type":29,"tag":127,"props":8174,"children":8175},{"style":680},[8176],{"type":56,"value":8177},"    DATABASE_URL",{"type":29,"tag":127,"props":8179,"children":8180},{"style":686},[8181],{"type":56,"value":715},{"type":29,"tag":127,"props":8183,"children":8184},{"style":718},[8185],{"type":56,"value":8186},"mysql://root@test_database/shopware\n",{"type":29,"tag":127,"props":8188,"children":8190},{"class":8189,"line":1480},[675,738],[8191,8195,8199],{"type":29,"tag":127,"props":8192,"children":8193},{"style":680},[8194],{"type":56,"value":6538},{"type":29,"tag":127,"props":8196,"children":8197},{"style":686},[8198],{"type":56,"value":715},{"type":29,"tag":127,"props":8200,"children":8201},{"style":718},[8202],{"type":56,"value":6547},{"type":29,"tag":127,"props":8204,"children":8205},{"class":675,"line":1493},[8206],{"type":29,"tag":127,"props":8207,"children":8208},{"emptyLinePlaceholder":500},[8209],{"type":56,"value":1395},{"type":29,"tag":127,"props":8211,"children":8212},{"class":675,"line":1506},[8213,8218,8222],{"type":29,"tag":127,"props":8214,"children":8215},{"style":680},[8216],{"type":56,"value":8217},"    XDEBUG_MODE",{"type":29,"tag":127,"props":8219,"children":8220},{"style":686},[8221],{"type":56,"value":715},{"type":29,"tag":127,"props":8223,"children":8224},{"style":718},[8225],{"type":56,"value":8226},"coverage\n",{"type":29,"tag":127,"props":8228,"children":8229},{"class":675,"line":1519},[8230,8235],{"type":29,"tag":127,"props":8231,"children":8232},{"style":680},[8233],{"type":56,"value":8234},"  before_script",{"type":29,"tag":127,"props":8236,"children":8237},{"style":686},[8238],{"type":56,"value":689},{"type":29,"tag":127,"props":8240,"children":8242},{"class":8241,"line":1532},[675,738],[8243,8247],{"type":29,"tag":127,"props":8244,"children":8245},{"style":686},[8246],{"type":56,"value":5466},{"type":29,"tag":127,"props":8248,"children":8249},{"style":718},[8250],{"type":56,"value":8251},"apk add --no-cache php-8.2-xdebug\n",{"type":29,"tag":127,"props":8253,"children":8255},{"class":8254,"line":1545},[675,738],[8256,8260],{"type":29,"tag":127,"props":8257,"children":8258},{"style":686},[8259],{"type":56,"value":5466},{"type":29,"tag":127,"props":8261,"children":8262},{"style":718},[8263],{"type":56,"value":8264},"shopware-cli project create shopware ${SHOPWARE_VERSION}\n",{"type":29,"tag":127,"props":8266,"children":8268},{"class":8267,"line":2398},[675,738],[8269,8273],{"type":29,"tag":127,"props":8270,"children":8271},{"style":686},[8272],{"type":56,"value":5466},{"type":29,"tag":127,"props":8274,"children":8275},{"style":718},[8276],{"type":56,"value":8277},"cd $SHOPWARE_ROOT\n",{"type":29,"tag":127,"props":8279,"children":8281},{"class":8280,"line":2406},[675,738],[8282,8286],{"type":29,"tag":127,"props":8283,"children":8284},{"style":686},[8285],{"type":56,"value":5466},{"type":29,"tag":127,"props":8287,"children":8288},{"style":718},[8289],{"type":56,"value":8290},"composer req --dev shopware/dev-tools phpunit/phpunit\n",{"type":29,"tag":127,"props":8292,"children":8294},{"class":8293,"line":2426},[675,738],[8295,8299],{"type":29,"tag":127,"props":8296,"children":8297},{"style":686},[8298],{"type":56,"value":5466},{"type":29,"tag":127,"props":8300,"children":8301},{"style":718},[8302],{"type":56,"value":8303},"git clone \"https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\" \"custom/plugins/${CI_PROJECT_NAME}\"\n",{"type":29,"tag":127,"props":8305,"children":8307},{"class":8306,"line":2447},[675,738],[8308,8312],{"type":29,"tag":127,"props":8309,"children":8310},{"style":686},[8311],{"type":56,"value":5466},{"type":29,"tag":127,"props":8313,"children":8314},{"style":718},[8315],{"type":56,"value":8316},"cd custom/plugins/${CI_PROJECT_NAME}\n",{"type":29,"tag":127,"props":8318,"children":8320},{"class":8319,"line":2459},[675,738],[8321,8325],{"type":29,"tag":127,"props":8322,"children":8323},{"style":686},[8324],{"type":56,"value":5466},{"type":29,"tag":127,"props":8326,"children":8327},{"style":718},[8328],{"type":56,"value":8329},"git checkout ${CI_COMMIT_SHA}\n",{"type":29,"tag":127,"props":8331,"children":8333},{"class":8332,"line":2475},[675,738],[8334,8338],{"type":29,"tag":127,"props":8335,"children":8336},{"style":686},[8337],{"type":56,"value":5466},{"type":29,"tag":127,"props":8339,"children":8340},{"style":718},[8341],{"type":56,"value":8342},"cd ${SHOPWARE_ROOT}\n",{"type":29,"tag":127,"props":8344,"children":8346},{"class":8345,"line":2483},[675,738],[8347,8351],{"type":29,"tag":127,"props":8348,"children":8349},{"style":686},[8350],{"type":56,"value":5466},{"type":29,"tag":127,"props":8352,"children":8353},{"style":718},[8354],{"type":56,"value":8355},"composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)\n",{"type":29,"tag":127,"props":8357,"children":8359},{"class":8358,"line":1957},[675,738],[8360,8364],{"type":29,"tag":127,"props":8361,"children":8362},{"style":686},[8363],{"type":56,"value":5466},{"type":29,"tag":127,"props":8365,"children":8366},{"style":718},[8367],{"type":56,"value":8316},{"type":29,"tag":127,"props":8369,"children":8370},{"class":675,"line":1958},[8371,8375],{"type":29,"tag":127,"props":8372,"children":8373},{"style":680},[8374],{"type":56,"value":5454},{"type":29,"tag":127,"props":8376,"children":8377},{"style":686},[8378],{"type":56,"value":689},{"type":29,"tag":127,"props":8380,"children":8382},{"class":8381,"line":1959},[675,738],[8383,8387],{"type":29,"tag":127,"props":8384,"children":8385},{"style":686},[8386],{"type":56,"value":5466},{"type":29,"tag":127,"props":8388,"children":8389},{"style":718},[8390],{"type":56,"value":8391},"${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml\n",{"type":29,"tag":127,"props":8393,"children":8394},{"class":675,"line":1960},[8395],{"type":29,"tag":127,"props":8396,"children":8397},{"emptyLinePlaceholder":500},[8398],{"type":56,"value":1395},{"type":29,"tag":127,"props":8400,"children":8401},{"class":675,"line":2546},[8402,8406],{"type":29,"tag":127,"props":8403,"children":8404},{"style":680},[8405],{"type":56,"value":6595},{"type":29,"tag":127,"props":8407,"children":8408},{"style":686},[8409],{"type":56,"value":689},{"type":29,"tag":127,"props":8411,"children":8412},{"class":675,"line":2555},[8413,8417,8421,8425],{"type":29,"tag":127,"props":8414,"children":8415},{"style":686},[8416],{"type":56,"value":5466},{"type":29,"tag":127,"props":8418,"children":8419},{"style":680},[8420],{"type":56,"value":6612},{"type":29,"tag":127,"props":8422,"children":8423},{"style":686},[8424],{"type":56,"value":715},{"type":29,"tag":127,"props":8426,"children":8427},{"style":718},[8428],{"type":56,"value":6621},{"type":29,"tag":127,"props":8430,"children":8431},{"class":675,"line":2568},[8432,8436],{"type":29,"tag":127,"props":8433,"children":8434},{"style":680},[8435],{"type":56,"value":6630},{"type":29,"tag":127,"props":8437,"children":8438},{"style":686},[8439],{"type":56,"value":689},{"type":29,"tag":127,"props":8441,"children":8442},{"class":675,"line":2581},[8443,8447],{"type":29,"tag":127,"props":8444,"children":8445},{"style":686},[8446],{"type":56,"value":6643},{"type":29,"tag":127,"props":8448,"children":8449},{"style":718},[8450],{"type":56,"value":6648},{"type":29,"tag":127,"props":8452,"children":8453},{"class":675,"line":2610},[8454,8459,8463],{"type":29,"tag":127,"props":8455,"children":8456},{"style":680},[8457],{"type":56,"value":8458},"  coverage",{"type":29,"tag":127,"props":8460,"children":8461},{"style":686},[8462],{"type":56,"value":715},{"type":29,"tag":127,"props":8464,"children":8465},{"style":718},[8466],{"type":56,"value":8467},"/^\\s*Lines:\\s*\\d+.\\d+\\%/\n",{"type":29,"tag":127,"props":8469,"children":8470},{"class":675,"line":2618},[8471,8475],{"type":29,"tag":127,"props":8472,"children":8473},{"style":680},[8474],{"type":56,"value":6995},{"type":29,"tag":127,"props":8476,"children":8477},{"style":686},[8478],{"type":56,"value":689},{"type":29,"tag":127,"props":8480,"children":8481},{"class":675,"line":2626},[8482,8487],{"type":29,"tag":127,"props":8483,"children":8484},{"style":680},[8485],{"type":56,"value":8486},"    reports",{"type":29,"tag":127,"props":8488,"children":8489},{"style":686},[8490],{"type":56,"value":689},{"type":29,"tag":127,"props":8492,"children":8493},{"class":675,"line":2647},[8494,8499],{"type":29,"tag":127,"props":8495,"children":8496},{"style":680},[8497],{"type":56,"value":8498},"      coverage_report",{"type":29,"tag":127,"props":8500,"children":8501},{"style":686},[8502],{"type":56,"value":689},{"type":29,"tag":127,"props":8504,"children":8505},{"class":675,"line":2660},[8506,8511,8515],{"type":29,"tag":127,"props":8507,"children":8508},{"style":680},[8509],{"type":56,"value":8510},"        coverage_format",{"type":29,"tag":127,"props":8512,"children":8513},{"style":686},[8514],{"type":56,"value":715},{"type":29,"tag":127,"props":8516,"children":8517},{"style":718},[8518],{"type":56,"value":8519},"cobertura\n",{"type":29,"tag":127,"props":8521,"children":8522},{"class":675,"line":2673},[8523,8528,8532],{"type":29,"tag":127,"props":8524,"children":8525},{"style":680},[8526],{"type":56,"value":8527},"        path",{"type":29,"tag":127,"props":8529,"children":8530},{"style":686},[8531],{"type":56,"value":715},{"type":29,"tag":127,"props":8533,"children":8534},{"style":718},[8535],{"type":56,"value":8536},"coverage.cobertura.xml\n",{"type":29,"tag":127,"props":8538,"children":8539},{"class":675,"line":2694},[8540,8544],{"type":29,"tag":127,"props":8541,"children":8542},{"style":680},[8543],{"type":56,"value":5496},{"type":29,"tag":127,"props":8545,"children":8546},{"style":686},[8547],{"type":56,"value":689},{"type":29,"tag":127,"props":8549,"children":8550},{"class":675,"line":2711},[8551,8555,8559,8563],{"type":29,"tag":127,"props":8552,"children":8553},{"style":686},[8554],{"type":56,"value":5466},{"type":29,"tag":127,"props":8556,"children":8557},{"style":680},[8558],{"type":56,"value":5729},{"type":29,"tag":127,"props":8560,"children":8561},{"style":686},[8562],{"type":56,"value":715},{"type":29,"tag":127,"props":8564,"children":8565},{"style":718},[8566],{"type":56,"value":7715},{"type":29,"tag":127,"props":8568,"children":8569},{"class":675,"line":2719},[8570,8574,8578,8582],{"type":29,"tag":127,"props":8571,"children":8572},{"style":686},[8573],{"type":56,"value":5466},{"type":29,"tag":127,"props":8575,"children":8576},{"style":680},[8577],{"type":56,"value":5729},{"type":29,"tag":127,"props":8579,"children":8580},{"style":686},[8581],{"type":56,"value":715},{"type":29,"tag":127,"props":8583,"children":8584},{"style":718},[8585],{"type":56,"value":5738},{"type":29,"tag":127,"props":8587,"children":8588},{"class":675,"line":2740},[8589,8593,8597],{"type":29,"tag":127,"props":8590,"children":8591},{"style":680},[8592],{"type":56,"value":5746},{"type":29,"tag":127,"props":8594,"children":8595},{"style":686},[8596],{"type":56,"value":715},{"type":29,"tag":127,"props":8598,"children":8599},{"style":718},[8600],{"type":56,"value":5755},{"type":29,"tag":127,"props":8602,"children":8603},{"class":675,"line":2757},[8604,8608,8612,8616],{"type":29,"tag":127,"props":8605,"children":8606},{"style":686},[8607],{"type":56,"value":5466},{"type":29,"tag":127,"props":8609,"children":8610},{"style":680},[8611],{"type":56,"value":5729},{"type":29,"tag":127,"props":8613,"children":8614},{"style":686},[8615],{"type":56,"value":715},{"type":29,"tag":127,"props":8617,"children":8618},{"style":718},[8619],{"type":56,"value":5775},{"type":29,"tag":48,"props":8621,"children":8622},{},[8623],{"type":56,"value":1560},{"type":29,"tag":960,"props":8625,"children":8626},{},[8627,8632,8637,8642,8647],{"type":29,"tag":812,"props":8628,"children":8629},{},[8630],{"type":56,"value":8631},"We disable automatic repository cloning (16)",{"type":29,"tag":812,"props":8633,"children":8634},{},[8635],{"type":56,"value":8636},"We include a database service (9-14)",{"type":29,"tag":812,"props":8638,"children":8639},{},[8640],{"type":56,"value":8641},"We set some required Shopware env variables (20-23)",{"type":29,"tag":812,"props":8643,"children":8644},{},[8645],{"type":56,"value":8646},"Create an empty shopware project with phpunit and xdebug (27-36)",{"type":29,"tag":812,"props":8648,"children":8649},{},[8650],{"type":56,"value":8651},"Run PHPUnit with code coverage generation as text and in cobertura format (38)",{"type":29,"tag":48,"props":8653,"children":8654},{},[8655],{"type":56,"value":8656},"Like the Code quality pipeline, this takes full advantage of GitLab coverage reporting",{"type":29,"tag":90,"props":8658,"children":8660},{"id":8659},"putting-it-all-together",[8661],{"type":56,"value":8662},"Putting it all together",{"type":29,"tag":48,"props":8664,"children":8665},{},[8666],{"type":56,"value":8667},"For this part, we don't include the build and release part.",{"type":29,"tag":657,"props":8669,"children":8671},{"code":8670,"filename":5556,"language":508,"meta":7,"className":667,"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",[8672],{"type":29,"tag":670,"props":8673,"children":8674},{"__ignoreMap":7},[8675,8686,8697,8704,8715,8730,8741,8756,8775,8786,8805,8820,8831,8846,8861,8872,8887,8902,8917,8924,8939,8954,8969,8984,8991,9006,9017,9028,9039,9050,9061,9072,9083,9094,9105,9116,9127,9138,9149,9156,9167,9186,9197,9208,9223,9234,9245,9256,9271,9286,9297,9316,9335,9350,9369,9376,9387,9398,9413,9432,9447,9458,9469,9480,9491,9506,9517,9536,9555,9570],{"type":29,"tag":127,"props":8676,"children":8677},{"class":675,"line":676},[8678,8682],{"type":29,"tag":127,"props":8679,"children":8680},{"style":680},[8681],{"type":56,"value":5377},{"type":29,"tag":127,"props":8683,"children":8684},{"style":686},[8685],{"type":56,"value":689},{"type":29,"tag":127,"props":8687,"children":8688},{"class":675,"line":342},[8689,8693],{"type":29,"tag":127,"props":8690,"children":8691},{"style":686},[8692],{"type":56,"value":7878},{"type":29,"tag":127,"props":8694,"children":8695},{"style":718},[8696],{"type":56,"value":7533},{"type":29,"tag":127,"props":8698,"children":8699},{"class":675,"line":704},[8700],{"type":29,"tag":127,"props":8701,"children":8702},{"emptyLinePlaceholder":500},[8703],{"type":56,"value":1395},{"type":29,"tag":127,"props":8705,"children":8706},{"class":675,"line":724},[8707,8711],{"type":29,"tag":127,"props":8708,"children":8709},{"style":680},[8710],{"type":56,"value":7897},{"type":29,"tag":127,"props":8712,"children":8713},{"style":686},[8714],{"type":56,"value":689},{"type":29,"tag":127,"props":8716,"children":8717},{"class":675,"line":662},[8718,8722,8726],{"type":29,"tag":127,"props":8719,"children":8720},{"style":680},[8721],{"type":56,"value":5438},{"type":29,"tag":127,"props":8723,"children":8724},{"style":686},[8725],{"type":56,"value":715},{"type":29,"tag":127,"props":8727,"children":8728},{"style":718},[8729],{"type":56,"value":7533},{"type":29,"tag":127,"props":8731,"children":8732},{"class":675,"line":663},[8733,8737],{"type":29,"tag":127,"props":8734,"children":8735},{"style":680},[8736],{"type":56,"value":5421},{"type":29,"tag":127,"props":8738,"children":8739},{"style":686},[8740],{"type":56,"value":689},{"type":29,"tag":127,"props":8742,"children":8743},{"class":675,"line":664},[8744,8748,8752],{"type":29,"tag":127,"props":8745,"children":8746},{"style":680},[8747],{"type":56,"value":5635},{"type":29,"tag":127,"props":8749,"children":8750},{"style":686},[8751],{"type":56,"value":715},{"type":29,"tag":127,"props":8753,"children":8754},{"style":718},[8755],{"type":56,"value":6484},{"type":29,"tag":127,"props":8757,"children":8758},{"class":675,"line":665},[8759,8763,8767,8771],{"type":29,"tag":127,"props":8760,"children":8761},{"style":680},[8762],{"type":56,"value":5652},{"type":29,"tag":127,"props":8764,"children":8765},{"style":686},[8766],{"type":56,"value":5657},{"type":29,"tag":127,"props":8768,"children":8769},{"style":718},[8770],{"type":56,"value":5662},{"type":29,"tag":127,"props":8772,"children":8773},{"style":686},[8774],{"type":56,"value":5667},{"type":29,"tag":127,"props":8776,"children":8777},{"class":675,"line":666},[8778,8782],{"type":29,"tag":127,"props":8779,"children":8780},{"style":680},[8781],{"type":56,"value":7970},{"type":29,"tag":127,"props":8783,"children":8784},{"style":686},[8785],{"type":56,"value":689},{"type":29,"tag":127,"props":8787,"children":8788},{"class":675,"line":1325},[8789,8793,8797,8801],{"type":29,"tag":127,"props":8790,"children":8791},{"style":686},[8792],{"type":56,"value":5466},{"type":29,"tag":127,"props":8794,"children":8795},{"style":680},[8796],{"type":56,"value":1778},{"type":29,"tag":127,"props":8798,"children":8799},{"style":686},[8800],{"type":56,"value":715},{"type":29,"tag":127,"props":8802,"children":8803},{"style":718},[8804],{"type":56,"value":7995},{"type":29,"tag":127,"props":8806,"children":8807},{"class":675,"line":1338},[8808,8812,8816],{"type":29,"tag":127,"props":8809,"children":8810},{"style":680},[8811],{"type":56,"value":8004},{"type":29,"tag":127,"props":8813,"children":8814},{"style":686},[8815],{"type":56,"value":715},{"type":29,"tag":127,"props":8817,"children":8818},{"style":718},[8819],{"type":56,"value":8013},{"type":29,"tag":127,"props":8821,"children":8822},{"class":675,"line":118},[8823,8827],{"type":29,"tag":127,"props":8824,"children":8825},{"style":680},[8826],{"type":56,"value":8022},{"type":29,"tag":127,"props":8828,"children":8829},{"style":686},[8830],{"type":56,"value":689},{"type":29,"tag":127,"props":8832,"children":8833},{"class":675,"line":1363},[8834,8838,8842],{"type":29,"tag":127,"props":8835,"children":8836},{"style":680},[8837],{"type":56,"value":8035},{"type":29,"tag":127,"props":8839,"children":8840},{"style":686},[8841],{"type":56,"value":715},{"type":29,"tag":127,"props":8843,"children":8844},{"style":718},[8845],{"type":56,"value":8044},{"type":29,"tag":127,"props":8847,"children":8848},{"class":675,"line":1376},[8849,8853,8857],{"type":29,"tag":127,"props":8850,"children":8851},{"style":680},[8852],{"type":56,"value":8053},{"type":29,"tag":127,"props":8854,"children":8855},{"style":686},[8856],{"type":56,"value":715},{"type":29,"tag":127,"props":8858,"children":8859},{"style":2290},[8860],{"type":56,"value":8062},{"type":29,"tag":127,"props":8862,"children":8863},{"class":675,"line":1389},[8864,8868],{"type":29,"tag":127,"props":8865,"children":8866},{"style":680},[8867],{"type":56,"value":6526},{"type":29,"tag":127,"props":8869,"children":8870},{"style":686},[8871],{"type":56,"value":689},{"type":29,"tag":127,"props":8873,"children":8874},{"class":675,"line":1398},[8875,8879,8883],{"type":29,"tag":127,"props":8876,"children":8877},{"style":680},[8878],{"type":56,"value":8082},{"type":29,"tag":127,"props":8880,"children":8881},{"style":686},[8882],{"type":56,"value":715},{"type":29,"tag":127,"props":8884,"children":8885},{"style":718},[8886],{"type":56,"value":8091},{"type":29,"tag":127,"props":8888,"children":8889},{"class":675,"line":1411},[8890,8894,8898],{"type":29,"tag":127,"props":8891,"children":8892},{"style":680},[8893],{"type":56,"value":8099},{"type":29,"tag":127,"props":8895,"children":8896},{"style":686},[8897],{"type":56,"value":715},{"type":29,"tag":127,"props":8899,"children":8900},{"style":718},[8901],{"type":56,"value":8108},{"type":29,"tag":127,"props":8903,"children":8904},{"class":675,"line":1424},[8905,8909,8913],{"type":29,"tag":127,"props":8906,"children":8907},{"style":680},[8908],{"type":56,"value":8116},{"type":29,"tag":127,"props":8910,"children":8911},{"style":686},[8912],{"type":56,"value":715},{"type":29,"tag":127,"props":8914,"children":8915},{"style":2290},[8916],{"type":56,"value":8125},{"type":29,"tag":127,"props":8918,"children":8919},{"class":675,"line":1433},[8920],{"type":29,"tag":127,"props":8921,"children":8922},{"style":686},[8923],{"type":56,"value":1232},{"type":29,"tag":127,"props":8925,"children":8926},{"class":675,"line":1446},[8927,8931,8935],{"type":29,"tag":127,"props":8928,"children":8929},{"style":680},[8930],{"type":56,"value":8141},{"type":29,"tag":127,"props":8932,"children":8933},{"style":686},[8934],{"type":56,"value":715},{"type":29,"tag":127,"props":8936,"children":8937},{"style":718},[8938],{"type":56,"value":8150},{"type":29,"tag":127,"props":8940,"children":8941},{"class":675,"line":1459},[8942,8946,8950],{"type":29,"tag":127,"props":8943,"children":8944},{"style":680},[8945],{"type":56,"value":8159},{"type":29,"tag":127,"props":8947,"children":8948},{"style":686},[8949],{"type":56,"value":715},{"type":29,"tag":127,"props":8951,"children":8952},{"style":718},[8953],{"type":56,"value":8168},{"type":29,"tag":127,"props":8955,"children":8956},{"class":675,"line":1472},[8957,8961,8965],{"type":29,"tag":127,"props":8958,"children":8959},{"style":680},[8960],{"type":56,"value":8177},{"type":29,"tag":127,"props":8962,"children":8963},{"style":686},[8964],{"type":56,"value":715},{"type":29,"tag":127,"props":8966,"children":8967},{"style":718},[8968],{"type":56,"value":8186},{"type":29,"tag":127,"props":8970,"children":8971},{"class":675,"line":1480},[8972,8976,8980],{"type":29,"tag":127,"props":8973,"children":8974},{"style":680},[8975],{"type":56,"value":6538},{"type":29,"tag":127,"props":8977,"children":8978},{"style":686},[8979],{"type":56,"value":715},{"type":29,"tag":127,"props":8981,"children":8982},{"style":718},[8983],{"type":56,"value":6547},{"type":29,"tag":127,"props":8985,"children":8986},{"class":675,"line":1493},[8987],{"type":29,"tag":127,"props":8988,"children":8989},{"emptyLinePlaceholder":500},[8990],{"type":56,"value":1395},{"type":29,"tag":127,"props":8992,"children":8993},{"class":675,"line":1506},[8994,8998,9002],{"type":29,"tag":127,"props":8995,"children":8996},{"style":680},[8997],{"type":56,"value":8217},{"type":29,"tag":127,"props":8999,"children":9000},{"style":686},[9001],{"type":56,"value":715},{"type":29,"tag":127,"props":9003,"children":9004},{"style":718},[9005],{"type":56,"value":8226},{"type":29,"tag":127,"props":9007,"children":9008},{"class":675,"line":1519},[9009,9013],{"type":29,"tag":127,"props":9010,"children":9011},{"style":680},[9012],{"type":56,"value":8234},{"type":29,"tag":127,"props":9014,"children":9015},{"style":686},[9016],{"type":56,"value":689},{"type":29,"tag":127,"props":9018,"children":9019},{"class":675,"line":1532},[9020,9024],{"type":29,"tag":127,"props":9021,"children":9022},{"style":686},[9023],{"type":56,"value":5466},{"type":29,"tag":127,"props":9025,"children":9026},{"style":718},[9027],{"type":56,"value":8251},{"type":29,"tag":127,"props":9029,"children":9030},{"class":675,"line":1545},[9031,9035],{"type":29,"tag":127,"props":9032,"children":9033},{"style":686},[9034],{"type":56,"value":5466},{"type":29,"tag":127,"props":9036,"children":9037},{"style":718},[9038],{"type":56,"value":8264},{"type":29,"tag":127,"props":9040,"children":9041},{"class":675,"line":2398},[9042,9046],{"type":29,"tag":127,"props":9043,"children":9044},{"style":686},[9045],{"type":56,"value":5466},{"type":29,"tag":127,"props":9047,"children":9048},{"style":718},[9049],{"type":56,"value":8277},{"type":29,"tag":127,"props":9051,"children":9052},{"class":675,"line":2406},[9053,9057],{"type":29,"tag":127,"props":9054,"children":9055},{"style":686},[9056],{"type":56,"value":5466},{"type":29,"tag":127,"props":9058,"children":9059},{"style":718},[9060],{"type":56,"value":8290},{"type":29,"tag":127,"props":9062,"children":9063},{"class":675,"line":2426},[9064,9068],{"type":29,"tag":127,"props":9065,"children":9066},{"style":686},[9067],{"type":56,"value":5466},{"type":29,"tag":127,"props":9069,"children":9070},{"style":718},[9071],{"type":56,"value":8303},{"type":29,"tag":127,"props":9073,"children":9074},{"class":675,"line":2447},[9075,9079],{"type":29,"tag":127,"props":9076,"children":9077},{"style":686},[9078],{"type":56,"value":5466},{"type":29,"tag":127,"props":9080,"children":9081},{"style":718},[9082],{"type":56,"value":8316},{"type":29,"tag":127,"props":9084,"children":9085},{"class":675,"line":2459},[9086,9090],{"type":29,"tag":127,"props":9087,"children":9088},{"style":686},[9089],{"type":56,"value":5466},{"type":29,"tag":127,"props":9091,"children":9092},{"style":718},[9093],{"type":56,"value":8329},{"type":29,"tag":127,"props":9095,"children":9096},{"class":675,"line":2475},[9097,9101],{"type":29,"tag":127,"props":9098,"children":9099},{"style":686},[9100],{"type":56,"value":5466},{"type":29,"tag":127,"props":9102,"children":9103},{"style":718},[9104],{"type":56,"value":8342},{"type":29,"tag":127,"props":9106,"children":9107},{"class":675,"line":2483},[9108,9112],{"type":29,"tag":127,"props":9109,"children":9110},{"style":686},[9111],{"type":56,"value":5466},{"type":29,"tag":127,"props":9113,"children":9114},{"style":718},[9115],{"type":56,"value":8355},{"type":29,"tag":127,"props":9117,"children":9118},{"class":675,"line":1957},[9119,9123],{"type":29,"tag":127,"props":9120,"children":9121},{"style":686},[9122],{"type":56,"value":5466},{"type":29,"tag":127,"props":9124,"children":9125},{"style":718},[9126],{"type":56,"value":8316},{"type":29,"tag":127,"props":9128,"children":9129},{"class":675,"line":1958},[9130,9134],{"type":29,"tag":127,"props":9131,"children":9132},{"style":680},[9133],{"type":56,"value":5454},{"type":29,"tag":127,"props":9135,"children":9136},{"style":686},[9137],{"type":56,"value":689},{"type":29,"tag":127,"props":9139,"children":9140},{"class":675,"line":1959},[9141,9145],{"type":29,"tag":127,"props":9142,"children":9143},{"style":686},[9144],{"type":56,"value":5466},{"type":29,"tag":127,"props":9146,"children":9147},{"style":718},[9148],{"type":56,"value":8391},{"type":29,"tag":127,"props":9150,"children":9151},{"class":675,"line":1960},[9152],{"type":29,"tag":127,"props":9153,"children":9154},{"emptyLinePlaceholder":500},[9155],{"type":56,"value":1395},{"type":29,"tag":127,"props":9157,"children":9158},{"class":675,"line":2546},[9159,9163],{"type":29,"tag":127,"props":9160,"children":9161},{"style":680},[9162],{"type":56,"value":6595},{"type":29,"tag":127,"props":9164,"children":9165},{"style":686},[9166],{"type":56,"value":689},{"type":29,"tag":127,"props":9168,"children":9169},{"class":675,"line":2555},[9170,9174,9178,9182],{"type":29,"tag":127,"props":9171,"children":9172},{"style":686},[9173],{"type":56,"value":5466},{"type":29,"tag":127,"props":9175,"children":9176},{"style":680},[9177],{"type":56,"value":6612},{"type":29,"tag":127,"props":9179,"children":9180},{"style":686},[9181],{"type":56,"value":715},{"type":29,"tag":127,"props":9183,"children":9184},{"style":718},[9185],{"type":56,"value":6621},{"type":29,"tag":127,"props":9187,"children":9188},{"class":675,"line":2568},[9189,9193],{"type":29,"tag":127,"props":9190,"children":9191},{"style":680},[9192],{"type":56,"value":6630},{"type":29,"tag":127,"props":9194,"children":9195},{"style":686},[9196],{"type":56,"value":689},{"type":29,"tag":127,"props":9198,"children":9199},{"class":675,"line":2581},[9200,9204],{"type":29,"tag":127,"props":9201,"children":9202},{"style":686},[9203],{"type":56,"value":6643},{"type":29,"tag":127,"props":9205,"children":9206},{"style":718},[9207],{"type":56,"value":6648},{"type":29,"tag":127,"props":9209,"children":9210},{"class":675,"line":2610},[9211,9215,9219],{"type":29,"tag":127,"props":9212,"children":9213},{"style":680},[9214],{"type":56,"value":8458},{"type":29,"tag":127,"props":9216,"children":9217},{"style":686},[9218],{"type":56,"value":715},{"type":29,"tag":127,"props":9220,"children":9221},{"style":718},[9222],{"type":56,"value":8467},{"type":29,"tag":127,"props":9224,"children":9225},{"class":675,"line":2618},[9226,9230],{"type":29,"tag":127,"props":9227,"children":9228},{"style":680},[9229],{"type":56,"value":6995},{"type":29,"tag":127,"props":9231,"children":9232},{"style":686},[9233],{"type":56,"value":689},{"type":29,"tag":127,"props":9235,"children":9236},{"class":675,"line":2626},[9237,9241],{"type":29,"tag":127,"props":9238,"children":9239},{"style":680},[9240],{"type":56,"value":8486},{"type":29,"tag":127,"props":9242,"children":9243},{"style":686},[9244],{"type":56,"value":689},{"type":29,"tag":127,"props":9246,"children":9247},{"class":675,"line":2647},[9248,9252],{"type":29,"tag":127,"props":9249,"children":9250},{"style":680},[9251],{"type":56,"value":8498},{"type":29,"tag":127,"props":9253,"children":9254},{"style":686},[9255],{"type":56,"value":689},{"type":29,"tag":127,"props":9257,"children":9258},{"class":675,"line":2660},[9259,9263,9267],{"type":29,"tag":127,"props":9260,"children":9261},{"style":680},[9262],{"type":56,"value":8510},{"type":29,"tag":127,"props":9264,"children":9265},{"style":686},[9266],{"type":56,"value":715},{"type":29,"tag":127,"props":9268,"children":9269},{"style":718},[9270],{"type":56,"value":8519},{"type":29,"tag":127,"props":9272,"children":9273},{"class":675,"line":2673},[9274,9278,9282],{"type":29,"tag":127,"props":9275,"children":9276},{"style":680},[9277],{"type":56,"value":8527},{"type":29,"tag":127,"props":9279,"children":9280},{"style":686},[9281],{"type":56,"value":715},{"type":29,"tag":127,"props":9283,"children":9284},{"style":718},[9285],{"type":56,"value":8536},{"type":29,"tag":127,"props":9287,"children":9288},{"class":675,"line":2694},[9289,9293],{"type":29,"tag":127,"props":9290,"children":9291},{"style":680},[9292],{"type":56,"value":5496},{"type":29,"tag":127,"props":9294,"children":9295},{"style":686},[9296],{"type":56,"value":689},{"type":29,"tag":127,"props":9298,"children":9299},{"class":675,"line":2711},[9300,9304,9308,9312],{"type":29,"tag":127,"props":9301,"children":9302},{"style":686},[9303],{"type":56,"value":5466},{"type":29,"tag":127,"props":9305,"children":9306},{"style":680},[9307],{"type":56,"value":5729},{"type":29,"tag":127,"props":9309,"children":9310},{"style":686},[9311],{"type":56,"value":715},{"type":29,"tag":127,"props":9313,"children":9314},{"style":718},[9315],{"type":56,"value":7715},{"type":29,"tag":127,"props":9317,"children":9318},{"class":675,"line":2719},[9319,9323,9327,9331],{"type":29,"tag":127,"props":9320,"children":9321},{"style":686},[9322],{"type":56,"value":5466},{"type":29,"tag":127,"props":9324,"children":9325},{"style":680},[9326],{"type":56,"value":5729},{"type":29,"tag":127,"props":9328,"children":9329},{"style":686},[9330],{"type":56,"value":715},{"type":29,"tag":127,"props":9332,"children":9333},{"style":718},[9334],{"type":56,"value":5738},{"type":29,"tag":127,"props":9336,"children":9337},{"class":675,"line":2740},[9338,9342,9346],{"type":29,"tag":127,"props":9339,"children":9340},{"style":680},[9341],{"type":56,"value":5746},{"type":29,"tag":127,"props":9343,"children":9344},{"style":686},[9345],{"type":56,"value":715},{"type":29,"tag":127,"props":9347,"children":9348},{"style":718},[9349],{"type":56,"value":5755},{"type":29,"tag":127,"props":9351,"children":9352},{"class":675,"line":2757},[9353,9357,9361,9365],{"type":29,"tag":127,"props":9354,"children":9355},{"style":686},[9356],{"type":56,"value":5466},{"type":29,"tag":127,"props":9358,"children":9359},{"style":680},[9360],{"type":56,"value":5729},{"type":29,"tag":127,"props":9362,"children":9363},{"style":686},[9364],{"type":56,"value":715},{"type":29,"tag":127,"props":9366,"children":9367},{"style":718},[9368],{"type":56,"value":5775},{"type":29,"tag":127,"props":9370,"children":9371},{"class":675,"line":2765},[9372],{"type":29,"tag":127,"props":9373,"children":9374},{"emptyLinePlaceholder":500},[9375],{"type":56,"value":1395},{"type":29,"tag":127,"props":9377,"children":9378},{"class":675,"line":2778},[9379,9383],{"type":29,"tag":127,"props":9380,"children":9381},{"style":680},[9382],{"type":56,"value":7391},{"type":29,"tag":127,"props":9384,"children":9385},{"style":686},[9386],{"type":56,"value":689},{"type":29,"tag":127,"props":9388,"children":9389},{"class":675,"line":2791},[9390,9394],{"type":29,"tag":127,"props":9391,"children":9392},{"style":680},[9393],{"type":56,"value":7559},{"type":29,"tag":127,"props":9395,"children":9396},{"style":686},[9397],{"type":56,"value":689},{"type":29,"tag":127,"props":9399,"children":9400},{"class":675,"line":2809},[9401,9405,9409],{"type":29,"tag":127,"props":9402,"children":9403},{"style":680},[9404],{"type":56,"value":7572},{"type":29,"tag":127,"props":9406,"children":9407},{"style":686},[9408],{"type":56,"value":715},{"type":29,"tag":127,"props":9410,"children":9411},{"style":718},[9412],{"type":56,"value":6484},{"type":29,"tag":127,"props":9414,"children":9415},{"class":675,"line":2817},[9416,9420,9424,9428],{"type":29,"tag":127,"props":9417,"children":9418},{"style":680},[9419],{"type":56,"value":7588},{"type":29,"tag":127,"props":9421,"children":9422},{"style":686},[9423],{"type":56,"value":5657},{"type":29,"tag":127,"props":9425,"children":9426},{"style":718},[9427],{"type":56,"value":5662},{"type":29,"tag":127,"props":9429,"children":9430},{"style":686},[9431],{"type":56,"value":5667},{"type":29,"tag":127,"props":9433,"children":9434},{"class":675,"line":2830},[9435,9439,9443],{"type":29,"tag":127,"props":9436,"children":9437},{"style":680},[9438],{"type":56,"value":7608},{"type":29,"tag":127,"props":9440,"children":9441},{"style":686},[9442],{"type":56,"value":715},{"type":29,"tag":127,"props":9444,"children":9445},{"style":718},[9446],{"type":56,"value":7533},{"type":29,"tag":127,"props":9448,"children":9449},{"class":675,"line":2839},[9450,9454],{"type":29,"tag":127,"props":9451,"children":9452},{"style":680},[9453],{"type":56,"value":7624},{"type":29,"tag":127,"props":9455,"children":9456},{"style":686},[9457],{"type":56,"value":689},{"type":29,"tag":127,"props":9459,"children":9460},{"class":675,"line":2848},[9461,9465],{"type":29,"tag":127,"props":9462,"children":9463},{"style":686},[9464],{"type":56,"value":744},{"type":29,"tag":127,"props":9466,"children":9467},{"style":718},[9468],{"type":56,"value":7640},{"type":29,"tag":127,"props":9470,"children":9471},{"class":675,"line":2861},[9472,9476],{"type":29,"tag":127,"props":9473,"children":9474},{"style":680},[9475],{"type":56,"value":7648},{"type":29,"tag":127,"props":9477,"children":9478},{"style":686},[9479],{"type":56,"value":689},{"type":29,"tag":127,"props":9481,"children":9482},{"class":675,"line":2869},[9483,9487],{"type":29,"tag":127,"props":9484,"children":9485},{"style":680},[9486],{"type":56,"value":7660},{"type":29,"tag":127,"props":9488,"children":9489},{"style":686},[9490],{"type":56,"value":689},{"type":29,"tag":127,"props":9492,"children":9493},{"class":675,"line":2878},[9494,9498,9502],{"type":29,"tag":127,"props":9495,"children":9496},{"style":680},[9497],{"type":56,"value":7672},{"type":29,"tag":127,"props":9499,"children":9500},{"style":686},[9501],{"type":56,"value":715},{"type":29,"tag":127,"props":9503,"children":9504},{"style":718},[9505],{"type":56,"value":7681},{"type":29,"tag":127,"props":9507,"children":9508},{"class":675,"line":2886},[9509,9513],{"type":29,"tag":127,"props":9510,"children":9511},{"style":680},[9512],{"type":56,"value":7690},{"type":29,"tag":127,"props":9514,"children":9515},{"style":686},[9516],{"type":56,"value":689},{"type":29,"tag":127,"props":9518,"children":9519},{"class":675,"line":2899},[9520,9524,9528,9532],{"type":29,"tag":127,"props":9521,"children":9522},{"style":686},[9523],{"type":56,"value":744},{"type":29,"tag":127,"props":9525,"children":9526},{"style":680},[9527],{"type":56,"value":5729},{"type":29,"tag":127,"props":9529,"children":9530},{"style":686},[9531],{"type":56,"value":715},{"type":29,"tag":127,"props":9533,"children":9534},{"style":718},[9535],{"type":56,"value":7715},{"type":29,"tag":127,"props":9537,"children":9538},{"class":675,"line":2912},[9539,9543,9547,9551],{"type":29,"tag":127,"props":9540,"children":9541},{"style":686},[9542],{"type":56,"value":744},{"type":29,"tag":127,"props":9544,"children":9545},{"style":680},[9546],{"type":56,"value":5729},{"type":29,"tag":127,"props":9548,"children":9549},{"style":686},[9550],{"type":56,"value":715},{"type":29,"tag":127,"props":9552,"children":9553},{"style":718},[9554],{"type":56,"value":5738},{"type":29,"tag":127,"props":9556,"children":9557},{"class":675,"line":2933},[9558,9562,9566],{"type":29,"tag":127,"props":9559,"children":9560},{"style":680},[9561],{"type":56,"value":7744},{"type":29,"tag":127,"props":9563,"children":9564},{"style":686},[9565],{"type":56,"value":715},{"type":29,"tag":127,"props":9567,"children":9568},{"style":718},[9569],{"type":56,"value":5755},{"type":29,"tag":127,"props":9571,"children":9572},{"class":675,"line":2946},[9573,9577,9581,9585],{"type":29,"tag":127,"props":9574,"children":9575},{"style":686},[9576],{"type":56,"value":744},{"type":29,"tag":127,"props":9578,"children":9579},{"style":680},[9580],{"type":56,"value":5729},{"type":29,"tag":127,"props":9582,"children":9583},{"style":686},[9584],{"type":56,"value":715},{"type":29,"tag":127,"props":9586,"children":9587},{"style":718},[9588],{"type":56,"value":5775},{"type":29,"tag":1826,"props":9590,"children":9591},{},[9592],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":9594},[9595,9598,9601],{"id":7391,"depth":342,"text":7394,"children":9596},[9597],{"id":7494,"depth":704,"text":7497},{"id":7790,"depth":342,"text":7361,"children":9599},[9600],{"id":7836,"depth":704,"text":7839},{"id":8659,"depth":342,"text":8662},{"_path":563,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":564,"description":565,"author":518,"image":519,"releaseDate":566,"blogCategories":9603,"articleTags":9604,"tags":9605,"body":9606,"_type":346,"_id":570,"_source":348,"_file":571,"_stem":572,"_extension":351},[522,523],[523,536],[24],{"type":26,"children":9607,"toc":11065},[9608,9613,9618,9623,9628,9633,9651,9656,9698,9704,9717,9730,9735,9741,9754,9767,9776,9782,9787,9900,10418,10453,10464,10467,10472,10633,10646,10652,10657,10727,10732,10738,10743,10754,10767,10801,10828,10840,10861,10874,10877,10882,10895,10913,10918,10923,11043,11061],{"type":29,"tag":48,"props":9609,"children":9610},{},[9611],{"type":56,"value":9612},"Managing a multiservice server can be tricky. Not every software is compatible with another, for example different requirements for database or PHP-versions.",{"type":29,"tag":48,"props":9614,"children":9615},{},[9616],{"type":56,"value":9617},"Additionally, all the software should be in the latest version, to mitigate possible security risks.",{"type":29,"tag":48,"props":9619,"children":9620},{},[9621],{"type":56,"value":9622},"There are many ways to handle this: Ansible, Chef etc.",{"type":29,"tag":48,"props":9624,"children":9625},{},[9626],{"type":56,"value":9627},"Out goal was to have an easy to use, automated and free solution.",{"type":29,"tag":48,"props":9629,"children":9630},{},[9631],{"type":56,"value":9632},"Here are the goals:",{"type":29,"tag":808,"props":9634,"children":9635},{},[9636,9641,9646],{"type":29,"tag":812,"props":9637,"children":9638},{},[9639],{"type":56,"value":9640},"use the GitOps approach to store and version control the deployment",{"type":29,"tag":812,"props":9642,"children":9643},{},[9644],{"type":56,"value":9645},"use containers to run the software",{"type":29,"tag":812,"props":9647,"children":9648},{},[9649],{"type":56,"value":9650},"get automated security updates and opt in for minor/major version updates",{"type":29,"tag":48,"props":9652,"children":9653},{},[9654],{"type":56,"value":9655},"This is the stack we ended with:",{"type":29,"tag":808,"props":9657,"children":9658},{},[9659,9676,9687],{"type":29,"tag":812,"props":9660,"children":9661},{},[9662,9667,9669,9674],{"type":29,"tag":643,"props":9663,"children":9665},{"href":9664},"https://www.docker.com/",[9666],{"type":56,"value":378},{"type":56,"value":9668}," and ",{"type":29,"tag":643,"props":9670,"children":9671},{"href":911},[9672],{"type":56,"value":9673},"Docker Compose",{"type":56,"value":9675}," do manage the software",{"type":29,"tag":812,"props":9677,"children":9678},{},[9679,9685],{"type":29,"tag":643,"props":9680,"children":9682},{"href":9681},"https://about.gitlab.com/",[9683],{"type":56,"value":9684},"GitLab",{"type":56,"value":9686}," to store all the compose files",{"type":29,"tag":812,"props":9688,"children":9689},{},[9690,9696],{"type":29,"tag":643,"props":9691,"children":9693},{"href":9692},"https://docs.renovatebot.com",[9694],{"type":56,"value":9695},"Renovate Bot",{"type":56,"value":9697}," to keep the software up to date",{"type":29,"tag":90,"props":9699,"children":9701},{"id":9700},"about-the-stack",[9702],{"type":56,"value":9703},"About the stack",{"type":29,"tag":48,"props":9705,"children":9706},{},[9707,9709,9715],{"type":56,"value":9708},"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":29,"tag":670,"props":9710,"children":9712},{"className":9711},[],[9713],{"type":56,"value":9714},"scp",{"type":56,"value":9716}," it from a pipeline.",{"type":29,"tag":48,"props":9718,"children":9719},{},[9720,9722,9728],{"type":56,"value":9721},"GitLab is out primary tool for version control. Additionally, a ",{"type":29,"tag":643,"props":9723,"children":9725},{"href":9724},"https://docs.gitlab.com/runner/",[9726],{"type":56,"value":9727},"GitLab Runner",{"type":56,"value":9729}," takes care of running pipelines.",{"type":29,"tag":48,"props":9731,"children":9732},{},[9733],{"type":56,"value":9734},"Renovate automates dependency updates. PHP, Go, Python, Docker - to name a couple. We already use it for various projects.",{"type":29,"tag":90,"props":9736,"children":9738},{"id":9737},"container-with-docker-and-docker-compose",[9739],{"type":56,"value":9740},"Container with Docker and Docker Compose",{"type":29,"tag":48,"props":9742,"children":9743},{},[9744,9746,9752],{"type":56,"value":9745},"The main reason why we chose Docker is the ability to access a remote Docker host and execute Docker commands.\nRefer to ",{"type":29,"tag":643,"props":9747,"children":9749},{"href":9748},"https://docs.docker.com/reference/cli/docker/#host",[9750],{"type":56,"value":9751},"the official documentation",{"type":56,"value":9753}," for more information.",{"type":29,"tag":48,"props":9755,"children":9756},{},[9757,9759,9765],{"type":56,"value":9758},"We are using ",{"type":29,"tag":670,"props":9760,"children":9762},{"className":9761},[],[9763],{"type":56,"value":9764},"ssh",{"type":56,"value":9766}," to access our target server.",{"type":29,"tag":48,"props":9768,"children":9769},{},[9770],{"type":29,"tag":670,"props":9771,"children":9773},{"className":9772},[],[9774],{"type":56,"value":9775},"DOCKER_HOST=ssh://[username@]\u003CIP or host>[:port] docker compose up --wait",{"type":29,"tag":90,"props":9777,"children":9779},{"id":9778},"gitops-with-gitlab",[9780],{"type":56,"value":9781},"GitOps with GitLab",{"type":29,"tag":48,"props":9783,"children":9784},{},[9785],{"type":56,"value":9786},"The idea behind GitOps is to use a git repository to store the configuration. Here is an example:",{"type":29,"tag":657,"props":9788,"children":9790},{"className":3008,"code":9789,"language":3010,"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",[9791],{"type":29,"tag":670,"props":9792,"children":9793},{"__ignoreMap":7},[9794,9803,9817,9835,9847,9870,9883],{"type":29,"tag":127,"props":9795,"children":9796},{"class":675,"line":676},[9797],{"type":29,"tag":127,"props":9798,"children":9800},{"style":9799},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#66D9EF",[9801],{"type":56,"value":9802},".\n",{"type":29,"tag":127,"props":9804,"children":9805},{"class":675,"line":342},[9806,9811],{"type":29,"tag":127,"props":9807,"children":9808},{"style":3020},[9809],{"type":56,"value":9810},"├──.gitlab-ci.yml",{"type":29,"tag":127,"props":9812,"children":9814},{"style":9813},"--shiki-default:#6A737D;--shiki-dark:#6A737D;--shiki-sepia:#88846F",[9815],{"type":56,"value":9816},"             # pipeline definition\n",{"type":29,"tag":127,"props":9818,"children":9819},{"class":675,"line":704},[9820,9825,9830],{"type":29,"tag":127,"props":9821,"children":9822},{"style":3020},[9823],{"type":56,"value":9824},"├──",{"type":29,"tag":127,"props":9826,"children":9827},{"style":718},[9828],{"type":56,"value":9829}," renovate.json",{"type":29,"tag":127,"props":9831,"children":9832},{"style":9813},[9833],{"type":56,"value":9834},"             # Renovate configuration\n",{"type":29,"tag":127,"props":9836,"children":9837},{"class":675,"line":724},[9838,9842],{"type":29,"tag":127,"props":9839,"children":9840},{"style":3020},[9841],{"type":56,"value":9824},{"type":29,"tag":127,"props":9843,"children":9844},{"style":718},[9845],{"type":56,"value":9846}," nextcloud\n",{"type":29,"tag":127,"props":9848,"children":9849},{"class":675,"line":662},[9850,9855,9860,9865],{"type":29,"tag":127,"props":9851,"children":9852},{"style":3020},[9853],{"type":56,"value":9854},"│",{"type":29,"tag":127,"props":9856,"children":9857},{"style":718},[9858],{"type":56,"value":9859},"   ├──",{"type":29,"tag":127,"props":9861,"children":9862},{"style":718},[9863],{"type":56,"value":9864}," docker-compose.yml",{"type":29,"tag":127,"props":9866,"children":9867},{"style":9813},[9868],{"type":56,"value":9869},"   # Nextcloud file hosting and collaboration\n",{"type":29,"tag":127,"props":9871,"children":9872},{"class":675,"line":663},[9873,9878],{"type":29,"tag":127,"props":9874,"children":9875},{"style":3020},[9876],{"type":56,"value":9877},"└──",{"type":29,"tag":127,"props":9879,"children":9880},{"style":718},[9881],{"type":56,"value":9882}," traefik\n",{"type":29,"tag":127,"props":9884,"children":9885},{"class":675,"line":664},[9886,9891,9895],{"type":29,"tag":127,"props":9887,"children":9888},{"style":3020},[9889],{"type":56,"value":9890},"    └──",{"type":29,"tag":127,"props":9892,"children":9893},{"style":718},[9894],{"type":56,"value":9864},{"type":29,"tag":127,"props":9896,"children":9897},{"style":9813},[9898],{"type":56,"value":9899},"   # Traefik reverse proxy configuration\n",{"type":29,"tag":657,"props":9901,"children":9904},{"className":667,"code":9902,"filename":9903,"language":508,"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",[9905],{"type":29,"tag":670,"props":9906,"children":9907},{"__ignoreMap":7},[9908,9919,9931,9943,9950,9961,9972,9988,10004,10015,10027,10039,10051,10063,10075,10087,10098,10110,10122,10134,10146,10195,10212,10229,10246,10253,10264,10280,10295,10307,10319,10336,10347,10359,10370,10382,10394,10406],{"type":29,"tag":127,"props":9909,"children":9910},{"class":675,"line":676},[9911,9915],{"type":29,"tag":127,"props":9912,"children":9913},{"style":680},[9914],{"type":56,"value":1208},{"type":29,"tag":127,"props":9916,"children":9917},{"style":686},[9918],{"type":56,"value":689},{"type":29,"tag":127,"props":9920,"children":9921},{"class":675,"line":342},[9922,9927],{"type":29,"tag":127,"props":9923,"children":9924},{"style":680},[9925],{"type":56,"value":9926},"  nextcloud",{"type":29,"tag":127,"props":9928,"children":9929},{"style":686},[9930],{"type":56,"value":689},{"type":29,"tag":127,"props":9932,"children":9933},{"class":675,"line":704},[9934,9939],{"type":29,"tag":127,"props":9935,"children":9936},{"style":680},[9937],{"type":56,"value":9938},"  db",{"type":29,"tag":127,"props":9940,"children":9941},{"style":686},[9942],{"type":56,"value":689},{"type":29,"tag":127,"props":9944,"children":9945},{"class":675,"line":724},[9946],{"type":29,"tag":127,"props":9947,"children":9948},{"emptyLinePlaceholder":500},[9949],{"type":56,"value":1395},{"type":29,"tag":127,"props":9951,"children":9952},{"class":675,"line":662},[9953,9957],{"type":29,"tag":127,"props":9954,"children":9955},{"style":680},[9956],{"type":56,"value":683},{"type":29,"tag":127,"props":9958,"children":9959},{"style":686},[9960],{"type":56,"value":689},{"type":29,"tag":127,"props":9962,"children":9963},{"class":675,"line":663},[9964,9968],{"type":29,"tag":127,"props":9965,"children":9966},{"style":680},[9967],{"type":56,"value":9938},{"type":29,"tag":127,"props":9969,"children":9970},{"style":686},[9971],{"type":56,"value":689},{"type":29,"tag":127,"props":9973,"children":9974},{"class":675,"line":664},[9975,9979,9983],{"type":29,"tag":127,"props":9976,"children":9977},{"style":680},[9978],{"type":56,"value":710},{"type":29,"tag":127,"props":9980,"children":9981},{"style":686},[9982],{"type":56,"value":715},{"type":29,"tag":127,"props":9984,"children":9985},{"style":718},[9986],{"type":56,"value":9987},"mariadb:11.8\n",{"type":29,"tag":127,"props":9989,"children":9990},{"class":675,"line":665},[9991,9995,9999],{"type":29,"tag":127,"props":9992,"children":9993},{"style":680},[9994],{"type":56,"value":1280},{"type":29,"tag":127,"props":9996,"children":9997},{"style":686},[9998],{"type":56,"value":715},{"type":29,"tag":127,"props":10000,"children":10001},{"style":718},[10002],{"type":56,"value":10003},"unless-stopped\n",{"type":29,"tag":127,"props":10005,"children":10006},{"class":675,"line":666},[10007,10011],{"type":29,"tag":127,"props":10008,"children":10009},{"style":680},[10010],{"type":56,"value":1525},{"type":29,"tag":127,"props":10012,"children":10013},{"style":686},[10014],{"type":56,"value":689},{"type":29,"tag":127,"props":10016,"children":10017},{"class":675,"line":1325},[10018,10022],{"type":29,"tag":127,"props":10019,"children":10020},{"style":686},[10021],{"type":56,"value":744},{"type":29,"tag":127,"props":10023,"children":10024},{"style":718},[10025],{"type":56,"value":10026},"db:/var/lib/mysql\n",{"type":29,"tag":127,"props":10028,"children":10029},{"class":675,"line":1338},[10030,10035],{"type":29,"tag":127,"props":10031,"children":10032},{"style":680},[10033],{"type":56,"value":10034},"    environment",{"type":29,"tag":127,"props":10036,"children":10037},{"style":686},[10038],{"type":56,"value":689},{"type":29,"tag":127,"props":10040,"children":10041},{"class":675,"line":118},[10042,10046],{"type":29,"tag":127,"props":10043,"children":10044},{"style":686},[10045],{"type":56,"value":744},{"type":29,"tag":127,"props":10047,"children":10048},{"style":718},[10049],{"type":56,"value":10050},"MARIADB_ROOT_PASSWORD=${NEXTCLOUD_MARIADB_ROOT_PASSWORD:?error}\n",{"type":29,"tag":127,"props":10052,"children":10053},{"class":675,"line":1363},[10054,10058],{"type":29,"tag":127,"props":10055,"children":10056},{"style":686},[10057],{"type":56,"value":744},{"type":29,"tag":127,"props":10059,"children":10060},{"style":718},[10061],{"type":56,"value":10062},"MARIADB_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":29,"tag":127,"props":10064,"children":10065},{"class":675,"line":1376},[10066,10070],{"type":29,"tag":127,"props":10067,"children":10068},{"style":686},[10069],{"type":56,"value":744},{"type":29,"tag":127,"props":10071,"children":10072},{"style":718},[10073],{"type":56,"value":10074},"MARIADB_DATABASE=nextcloud\n",{"type":29,"tag":127,"props":10076,"children":10077},{"class":675,"line":1389},[10078,10082],{"type":29,"tag":127,"props":10079,"children":10080},{"style":686},[10081],{"type":56,"value":744},{"type":29,"tag":127,"props":10083,"children":10084},{"style":718},[10085],{"type":56,"value":10086},"MARIADB_USER=nextcloud\n",{"type":29,"tag":127,"props":10088,"children":10089},{"class":675,"line":1398},[10090,10094],{"type":29,"tag":127,"props":10091,"children":10092},{"style":680},[10093],{"type":56,"value":1331},{"type":29,"tag":127,"props":10095,"children":10096},{"style":686},[10097],{"type":56,"value":689},{"type":29,"tag":127,"props":10099,"children":10100},{"class":675,"line":1411},[10101,10105],{"type":29,"tag":127,"props":10102,"children":10103},{"style":686},[10104],{"type":56,"value":744},{"type":29,"tag":127,"props":10106,"children":10107},{"style":718},[10108],{"type":56,"value":10109},"--transaction-isolation=READ-COMMITTED\n",{"type":29,"tag":127,"props":10111,"children":10112},{"class":675,"line":1424},[10113,10117],{"type":29,"tag":127,"props":10114,"children":10115},{"style":686},[10116],{"type":56,"value":744},{"type":29,"tag":127,"props":10118,"children":10119},{"style":718},[10120],{"type":56,"value":10121},"--log-bin=binlog\n",{"type":29,"tag":127,"props":10123,"children":10124},{"class":675,"line":1433},[10125,10129],{"type":29,"tag":127,"props":10126,"children":10127},{"style":686},[10128],{"type":56,"value":744},{"type":29,"tag":127,"props":10130,"children":10131},{"style":718},[10132],{"type":56,"value":10133},"--binlog-format=ROW\n",{"type":29,"tag":127,"props":10135,"children":10136},{"class":675,"line":1446},[10137,10142],{"type":29,"tag":127,"props":10138,"children":10139},{"style":680},[10140],{"type":56,"value":10141},"    healthcheck",{"type":29,"tag":127,"props":10143,"children":10144},{"style":686},[10145],{"type":56,"value":689},{"type":29,"tag":127,"props":10147,"children":10148},{"class":675,"line":1459},[10149,10154,10158,10163,10168,10173,10177,10182,10186,10191],{"type":29,"tag":127,"props":10150,"children":10151},{"style":680},[10152],{"type":56,"value":10153},"      test",{"type":29,"tag":127,"props":10155,"children":10156},{"style":686},[10157],{"type":56,"value":5657},{"type":29,"tag":127,"props":10159,"children":10160},{"style":718},[10161],{"type":56,"value":10162},"\"CMD\"",{"type":29,"tag":127,"props":10164,"children":10165},{"style":686},[10166],{"type":56,"value":10167},", ",{"type":29,"tag":127,"props":10169,"children":10170},{"style":718},[10171],{"type":56,"value":10172},"\"healthcheck.sh\"",{"type":29,"tag":127,"props":10174,"children":10175},{"style":686},[10176],{"type":56,"value":10167},{"type":29,"tag":127,"props":10178,"children":10179},{"style":718},[10180],{"type":56,"value":10181},"\"--connect\"",{"type":29,"tag":127,"props":10183,"children":10184},{"style":686},[10185],{"type":56,"value":10167},{"type":29,"tag":127,"props":10187,"children":10188},{"style":718},[10189],{"type":56,"value":10190},"\"--innodb_initialized\"",{"type":29,"tag":127,"props":10192,"children":10193},{"style":686},[10194],{"type":56,"value":5667},{"type":29,"tag":127,"props":10196,"children":10197},{"class":675,"line":1472},[10198,10203,10207],{"type":29,"tag":127,"props":10199,"children":10200},{"style":680},[10201],{"type":56,"value":10202},"      interval",{"type":29,"tag":127,"props":10204,"children":10205},{"style":686},[10206],{"type":56,"value":715},{"type":29,"tag":127,"props":10208,"children":10209},{"style":718},[10210],{"type":56,"value":10211},"15s\n",{"type":29,"tag":127,"props":10213,"children":10214},{"class":675,"line":1480},[10215,10220,10224],{"type":29,"tag":127,"props":10216,"children":10217},{"style":680},[10218],{"type":56,"value":10219},"      timeout",{"type":29,"tag":127,"props":10221,"children":10222},{"style":686},[10223],{"type":56,"value":715},{"type":29,"tag":127,"props":10225,"children":10226},{"style":718},[10227],{"type":56,"value":10228},"5s\n",{"type":29,"tag":127,"props":10230,"children":10231},{"class":675,"line":1493},[10232,10237,10241],{"type":29,"tag":127,"props":10233,"children":10234},{"style":680},[10235],{"type":56,"value":10236},"      retries",{"type":29,"tag":127,"props":10238,"children":10239},{"style":686},[10240],{"type":56,"value":715},{"type":29,"tag":127,"props":10242,"children":10243},{"style":2290},[10244],{"type":56,"value":10245},"6\n",{"type":29,"tag":127,"props":10247,"children":10248},{"class":675,"line":1506},[10249],{"type":29,"tag":127,"props":10250,"children":10251},{"emptyLinePlaceholder":500},[10252],{"type":56,"value":1395},{"type":29,"tag":127,"props":10254,"children":10255},{"class":675,"line":1519},[10256,10260],{"type":29,"tag":127,"props":10257,"children":10258},{"style":680},[10259],{"type":56,"value":9926},{"type":29,"tag":127,"props":10261,"children":10262},{"style":686},[10263],{"type":56,"value":689},{"type":29,"tag":127,"props":10265,"children":10266},{"class":675,"line":1532},[10267,10271,10275],{"type":29,"tag":127,"props":10268,"children":10269},{"style":680},[10270],{"type":56,"value":710},{"type":29,"tag":127,"props":10272,"children":10273},{"style":686},[10274],{"type":56,"value":715},{"type":29,"tag":127,"props":10276,"children":10277},{"style":718},[10278],{"type":56,"value":10279},"nextcloud:32.0.0\n",{"type":29,"tag":127,"props":10281,"children":10282},{"class":675,"line":1545},[10283,10287,10291],{"type":29,"tag":127,"props":10284,"children":10285},{"style":680},[10286],{"type":56,"value":1280},{"type":29,"tag":127,"props":10288,"children":10289},{"style":686},[10290],{"type":56,"value":715},{"type":29,"tag":127,"props":10292,"children":10293},{"style":718},[10294],{"type":56,"value":10003},{"type":29,"tag":127,"props":10296,"children":10297},{"class":675,"line":2398},[10298,10303],{"type":29,"tag":127,"props":10299,"children":10300},{"style":680},[10301],{"type":56,"value":10302},"    depends_on",{"type":29,"tag":127,"props":10304,"children":10305},{"style":686},[10306],{"type":56,"value":689},{"type":29,"tag":127,"props":10308,"children":10309},{"class":675,"line":2406},[10310,10315],{"type":29,"tag":127,"props":10311,"children":10312},{"style":680},[10313],{"type":56,"value":10314},"      db",{"type":29,"tag":127,"props":10316,"children":10317},{"style":686},[10318],{"type":56,"value":689},{"type":29,"tag":127,"props":10320,"children":10321},{"class":675,"line":2426},[10322,10327,10331],{"type":29,"tag":127,"props":10323,"children":10324},{"style":680},[10325],{"type":56,"value":10326},"        condition",{"type":29,"tag":127,"props":10328,"children":10329},{"style":686},[10330],{"type":56,"value":715},{"type":29,"tag":127,"props":10332,"children":10333},{"style":718},[10334],{"type":56,"value":10335},"service_healthy\n",{"type":29,"tag":127,"props":10337,"children":10338},{"class":675,"line":2447},[10339,10343],{"type":29,"tag":127,"props":10340,"children":10341},{"style":680},[10342],{"type":56,"value":1525},{"type":29,"tag":127,"props":10344,"children":10345},{"style":686},[10346],{"type":56,"value":689},{"type":29,"tag":127,"props":10348,"children":10349},{"class":675,"line":2459},[10350,10354],{"type":29,"tag":127,"props":10351,"children":10352},{"style":686},[10353],{"type":56,"value":744},{"type":29,"tag":127,"props":10355,"children":10356},{"style":718},[10357],{"type":56,"value":10358},"nextcloud:/var/www/html\n",{"type":29,"tag":127,"props":10360,"children":10361},{"class":675,"line":2475},[10362,10366],{"type":29,"tag":127,"props":10363,"children":10364},{"style":680},[10365],{"type":56,"value":10034},{"type":29,"tag":127,"props":10367,"children":10368},{"style":686},[10369],{"type":56,"value":689},{"type":29,"tag":127,"props":10371,"children":10372},{"class":675,"line":2483},[10373,10377],{"type":29,"tag":127,"props":10374,"children":10375},{"style":686},[10376],{"type":56,"value":744},{"type":29,"tag":127,"props":10378,"children":10379},{"style":718},[10380],{"type":56,"value":10381},"MYSQL_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":29,"tag":127,"props":10383,"children":10384},{"class":675,"line":1957},[10385,10389],{"type":29,"tag":127,"props":10386,"children":10387},{"style":686},[10388],{"type":56,"value":744},{"type":29,"tag":127,"props":10390,"children":10391},{"style":718},[10392],{"type":56,"value":10393},"MYSQL_DATABASE=nextcloud\n",{"type":29,"tag":127,"props":10395,"children":10396},{"class":675,"line":1958},[10397,10401],{"type":29,"tag":127,"props":10398,"children":10399},{"style":686},[10400],{"type":56,"value":744},{"type":29,"tag":127,"props":10402,"children":10403},{"style":718},[10404],{"type":56,"value":10405},"MYSQL_USER=nextcloud\n",{"type":29,"tag":127,"props":10407,"children":10408},{"class":675,"line":1959},[10409,10413],{"type":29,"tag":127,"props":10410,"children":10411},{"style":686},[10412],{"type":56,"value":744},{"type":29,"tag":127,"props":10414,"children":10415},{"style":718},[10416],{"type":56,"value":10417},"MYSQL_HOST=db\n",{"type":29,"tag":657,"props":10419,"children":10423},{"className":10420,"code":10421,"language":10422,"meta":7,"style":7},"language-dotenv shiki shiki-themes github-dark github-dark monokai","NEXTCLOUD_MARIADB_ROOT_PASSWORD=\nNEXTCLOUD_MARIADB_PASSWORD=\n","dotenv",[10424],{"type":29,"tag":670,"props":10425,"children":10426},{"__ignoreMap":7},[10427,10441],{"type":29,"tag":127,"props":10428,"children":10429},{"class":675,"line":676},[10430,10436],{"type":29,"tag":127,"props":10431,"children":10433},{"style":10432},"--shiki-default:#FFAB70;--shiki-dark:#FFAB70;--shiki-sepia:#F8F8F2",[10434],{"type":56,"value":10435},"NEXTCLOUD_MARIADB_ROOT_PASSWORD",{"type":29,"tag":127,"props":10437,"children":10438},{"style":4927},[10439],{"type":56,"value":10440},"=\n",{"type":29,"tag":127,"props":10442,"children":10443},{"class":675,"line":342},[10444,10449],{"type":29,"tag":127,"props":10445,"children":10446},{"style":10432},[10447],{"type":56,"value":10448},"NEXTCLOUD_MARIADB_PASSWORD",{"type":29,"tag":127,"props":10450,"children":10451},{"style":4927},[10452],{"type":56,"value":10440},{"type":29,"tag":48,"props":10454,"children":10455},{},[10456,10458],{"type":56,"value":10457},"are stored as ",{"type":29,"tag":643,"props":10459,"children":10461},{"href":10460},"https://docs.gitlab.com/ci/variables/",[10462],{"type":56,"value":10463},"CI/CD Variables",{"type":29,"tag":1184,"props":10465,"children":10466},{},[],{"type":29,"tag":48,"props":10468,"children":10469},{},[10470],{"type":56,"value":10471},"To deploy the stack, we have a pipeline:",{"type":29,"tag":657,"props":10473,"children":10475},{"className":667,"code":10474,"filename":5365,"language":508,"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",[10476],{"type":29,"tag":670,"props":10477,"children":10478},{"__ignoreMap":7},[10479,10490,10502,10509,10520,10535,10551,10562,10579,10590,10602,10613],{"type":29,"tag":127,"props":10480,"children":10481},{"class":675,"line":676},[10482,10486],{"type":29,"tag":127,"props":10483,"children":10484},{"style":680},[10485],{"type":56,"value":5377},{"type":29,"tag":127,"props":10487,"children":10488},{"style":686},[10489],{"type":56,"value":689},{"type":29,"tag":127,"props":10491,"children":10492},{"class":675,"line":342},[10493,10497],{"type":29,"tag":127,"props":10494,"children":10495},{"style":686},[10496],{"type":56,"value":5389},{"type":29,"tag":127,"props":10498,"children":10499},{"style":718},[10500],{"type":56,"value":10501},"deploy\n",{"type":29,"tag":127,"props":10503,"children":10504},{"class":675,"line":704},[10505],{"type":29,"tag":127,"props":10506,"children":10507},{"emptyLinePlaceholder":500},[10508],{"type":56,"value":1395},{"type":29,"tag":127,"props":10510,"children":10511},{"class":675,"line":724},[10512,10516],{"type":29,"tag":127,"props":10513,"children":10514},{"style":680},[10515],{"type":56,"value":5409},{"type":29,"tag":127,"props":10517,"children":10518},{"style":686},[10519],{"type":56,"value":689},{"type":29,"tag":127,"props":10521,"children":10522},{"class":675,"line":662},[10523,10527,10531],{"type":29,"tag":127,"props":10524,"children":10525},{"style":680},[10526],{"type":56,"value":5438},{"type":29,"tag":127,"props":10528,"children":10529},{"style":686},[10530],{"type":56,"value":715},{"type":29,"tag":127,"props":10532,"children":10533},{"style":718},[10534],{"type":56,"value":10501},{"type":29,"tag":127,"props":10536,"children":10537},{"class":675,"line":663},[10538,10542,10546],{"type":29,"tag":127,"props":10539,"children":10540},{"style":680},[10541],{"type":56,"value":5421},{"type":29,"tag":127,"props":10543,"children":10544},{"style":686},[10545],{"type":56,"value":715},{"type":29,"tag":127,"props":10547,"children":10548},{"style":718},[10549],{"type":56,"value":10550},"docker:28\n",{"type":29,"tag":127,"props":10552,"children":10553},{"class":675,"line":664},[10554,10558],{"type":29,"tag":127,"props":10555,"children":10556},{"style":680},[10557],{"type":56,"value":6526},{"type":29,"tag":127,"props":10559,"children":10560},{"style":686},[10561],{"type":56,"value":689},{"type":29,"tag":127,"props":10563,"children":10564},{"class":675,"line":665},[10565,10570,10574],{"type":29,"tag":127,"props":10566,"children":10567},{"style":680},[10568],{"type":56,"value":10569},"    DOCKER_HOST",{"type":29,"tag":127,"props":10571,"children":10572},{"style":686},[10573],{"type":56,"value":715},{"type":29,"tag":127,"props":10575,"children":10576},{"style":718},[10577],{"type":56,"value":10578},"ssh://[username@]\u003CIP or host>[:port]\n",{"type":29,"tag":127,"props":10580,"children":10581},{"class":675,"line":666},[10582,10586],{"type":29,"tag":127,"props":10583,"children":10584},{"style":680},[10585],{"type":56,"value":5454},{"type":29,"tag":127,"props":10587,"children":10588},{"style":686},[10589],{"type":56,"value":689},{"type":29,"tag":127,"props":10591,"children":10592},{"class":675,"line":1325},[10593,10597],{"type":29,"tag":127,"props":10594,"children":10595},{"style":686},[10596],{"type":56,"value":5466},{"type":29,"tag":127,"props":10598,"children":10599},{"style":718},[10600],{"type":56,"value":10601},"for file in $(find . -type f -name docker-compose.yml); do docker compose -f $file up --remove-orphans --wait; done\n",{"type":29,"tag":127,"props":10603,"children":10604},{"class":675,"line":1338},[10605,10609],{"type":29,"tag":127,"props":10606,"children":10607},{"style":680},[10608],{"type":56,"value":5496},{"type":29,"tag":127,"props":10610,"children":10611},{"style":686},[10612],{"type":56,"value":689},{"type":29,"tag":127,"props":10614,"children":10615},{"class":675,"line":118},[10616,10620,10624,10628],{"type":29,"tag":127,"props":10617,"children":10618},{"style":686},[10619],{"type":56,"value":5466},{"type":29,"tag":127,"props":10621,"children":10622},{"style":680},[10623],{"type":56,"value":5729},{"type":29,"tag":127,"props":10625,"children":10626},{"style":686},[10627],{"type":56,"value":715},{"type":29,"tag":127,"props":10629,"children":10630},{"style":718},[10631],{"type":56,"value":10632},"$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n",{"type":29,"tag":48,"props":10634,"children":10635},{},[10636,10638,10644],{"type":56,"value":10637},"The pipeline runs with every commit on the default branch, iterates through all ",{"type":29,"tag":670,"props":10639,"children":10641},{"className":10640},[],[10642],{"type":56,"value":10643},"docker-compose.yml",{"type":56,"value":10645}," files, and deploys them.",{"type":29,"tag":90,"props":10647,"children":10649},{"id":10648},"keep-your-deployments-up-to-date-with-renovate-bot",[10650],{"type":56,"value":10651},"Keep your deployments up-to-date with Renovate Bot",{"type":29,"tag":48,"props":10653,"children":10654},{},[10655],{"type":56,"value":10656},"Here is where Renovate kicks in.",{"type":29,"tag":657,"props":10658,"children":10661},{"className":1953,"code":10659,"filename":10660,"language":454,"meta":7,"style":7},"{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:best-practices\"\n  ]\n}\n","renovate.json",[10662],{"type":29,"tag":670,"props":10663,"children":10664},{"__ignoreMap":7},[10665,10672,10693,10705,10713,10720],{"type":29,"tag":127,"props":10666,"children":10667},{"class":675,"line":676},[10668],{"type":29,"tag":127,"props":10669,"children":10670},{"style":686},[10671],{"type":56,"value":1972},{"type":29,"tag":127,"props":10673,"children":10674},{"class":675,"line":342},[10675,10680,10684,10689],{"type":29,"tag":127,"props":10676,"children":10677},{"style":1978},[10678],{"type":56,"value":10679},"  \"$schema\"",{"type":29,"tag":127,"props":10681,"children":10682},{"style":686},[10683],{"type":56,"value":715},{"type":29,"tag":127,"props":10685,"children":10686},{"style":1988},[10687],{"type":56,"value":10688},"\"https://docs.renovatebot.com/renovate-schema.json\"",{"type":29,"tag":127,"props":10690,"children":10691},{"style":686},[10692],{"type":56,"value":1996},{"type":29,"tag":127,"props":10694,"children":10695},{"class":675,"line":704},[10696,10701],{"type":29,"tag":127,"props":10697,"children":10698},{"style":1978},[10699],{"type":56,"value":10700},"  \"extends\"",{"type":29,"tag":127,"props":10702,"children":10703},{"style":686},[10704],{"type":56,"value":2213},{"type":29,"tag":127,"props":10706,"children":10707},{"class":675,"line":724},[10708],{"type":29,"tag":127,"props":10709,"children":10710},{"style":1988},[10711],{"type":56,"value":10712},"    \"config:best-practices\"\n",{"type":29,"tag":127,"props":10714,"children":10715},{"class":675,"line":662},[10716],{"type":29,"tag":127,"props":10717,"children":10718},{"style":686},[10719],{"type":56,"value":6173},{"type":29,"tag":127,"props":10721,"children":10722},{"class":675,"line":663},[10723],{"type":29,"tag":127,"props":10724,"children":10725},{"style":686},[10726],{"type":56,"value":3000},{"type":29,"tag":48,"props":10728,"children":10729},{},[10730],{"type":56,"value":10731},"Renovate will create Merge Requests for every update. Nice!",{"type":29,"tag":90,"props":10733,"children":10735},{"id":10734},"automated-security-updates-and-opt-in-for-minormajor-version-updates",[10736],{"type":56,"value":10737},"Automated security updates and opt-in for minor/major version updates",{"type":29,"tag":48,"props":10739,"children":10740},{},[10741],{"type":56,"value":10742},"The current configuration creates Merge Requests for every update, but we want security updates to happen without user interaction.",{"type":29,"tag":48,"props":10744,"children":10745},{},[10746,10748],{"type":56,"value":10747},"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":29,"tag":643,"props":10749,"children":10751},{"href":10750},"https://hub.docker.com/_/mariadb",[10752],{"type":56,"value":10753},"MariaDB",{"type":29,"tag":48,"props":10755,"children":10756},{},[10757,10759,10765],{"type":56,"value":10758},"There are ",{"type":29,"tag":670,"props":10760,"children":10762},{"className":10761},[],[10763],{"type":56,"value":10764},"11.8.3-noble, 11.8-noble, 11-noble, lts-noble, 11.8.3, 11.8, 11, lts",{"type":56,"value":10766},", all of which refer to the same image.",{"type":29,"tag":48,"props":10768,"children":10769},{},[10770,10776,10778,10784,10786,10792,10793,10799],{"type":29,"tag":670,"props":10771,"children":10773},{"className":10772},[],[10774],{"type":56,"value":10775},"11.8.3-noble",{"type":56,"value":10777}," means that we get MariaDB in version ",{"type":29,"tag":670,"props":10779,"children":10781},{"className":10780},[],[10782],{"type":56,"value":10783},"11.8.3",{"type":56,"value":10785}," based on Ubuntu Noble.\n",{"type":29,"tag":670,"props":10787,"children":10789},{"className":10788},[],[10790],{"type":56,"value":10791},"11.8-noble",{"type":56,"value":10777},{"type":29,"tag":670,"props":10794,"children":10796},{"className":10795},[],[10797],{"type":56,"value":10798},"11.8.\u003Clatest_path>",{"type":56,"value":10800}," based on Ubuntu Noble.",{"type":29,"tag":48,"props":10802,"children":10803},{},[10804,10806,10812,10814,10819,10821,10826],{"type":56,"value":10805},"When a neu version of MariaDB is released, e.g ",{"type":29,"tag":670,"props":10807,"children":10809},{"className":10808},[],[10810],{"type":56,"value":10811},"11.8.4-noble",{"type":56,"value":10813},", a new ",{"type":29,"tag":670,"props":10815,"children":10817},{"className":10816},[],[10818],{"type":56,"value":10811},{"type":56,"value":10820}," tag will be pushed, but the ",{"type":29,"tag":670,"props":10822,"children":10824},{"className":10823},[],[10825],{"type":56,"value":10791},{"type":56,"value":10827}," will be updated.",{"type":29,"tag":48,"props":10829,"children":10830},{},[10831,10833,10838],{"type":56,"value":10832},"This same is true for the Ubuntu update. The ",{"type":29,"tag":670,"props":10834,"children":10836},{"className":10835},[],[10837],{"type":56,"value":10775},{"type":56,"value":10839}," tag can be updated, if the image is rebuild with the latest Ubuntu image.",{"type":29,"tag":48,"props":10841,"children":10842},{},[10843,10845,10851,10853,10859],{"type":56,"value":10844},"Running ",{"type":29,"tag":670,"props":10846,"children":10848},{"className":10847},[],[10849],{"type":56,"value":10850},"docker compose up",{"type":56,"value":10852}," on ",{"type":29,"tag":670,"props":10854,"children":10856},{"className":10855},[],[10857],{"type":56,"value":10858},"mariadb:11.8-noble",{"type":56,"value":10860}," will do nothing, because Docker is not aware of that change.",{"type":29,"tag":48,"props":10862,"children":10863},{},[10864,10866,10872],{"type":56,"value":10865},"In the example above we reference ",{"type":29,"tag":670,"props":10867,"children":10869},{"className":10868},[],[10870],{"type":56,"value":10871},"mariadb:11.8",{"type":56,"value":10873},", because we want to use the latest patch version based on the most current OS.",{"type":29,"tag":1184,"props":10875,"children":10876},{},[],{"type":29,"tag":48,"props":10878,"children":10879},{},[10880],{"type":56,"value":10881},"How to tell Docker that there is a new version?",{"type":29,"tag":48,"props":10883,"children":10884},{},[10885,10887,10893],{"type":56,"value":10886},"The main idea is to attach a ",{"type":29,"tag":643,"props":10888,"children":10890},{"href":10889},"https://docs.docker.com/dhi/core-concepts/digests/",[10891],{"type":56,"value":10892},"digest",{"type":56,"value":10894}," to the Docker image.",{"type":29,"tag":48,"props":10896,"children":10897},{},[10898,10900,10905,10907],{"type":56,"value":10899},"When running Renovate for the first time, it will find the reference to ",{"type":29,"tag":670,"props":10901,"children":10903},{"className":10902},[],[10904],{"type":56,"value":10871},{"type":56,"value":10906}," and create a merge request to pin the Digest to something like ",{"type":29,"tag":670,"props":10908,"children":10910},{"className":10909},[],[10911],{"type":56,"value":10912},"mariadb:11.8@sha256:ae6119716edac6998ae85508431b3d2e666530ddf4e94c61a10710caec9b0f71",{"type":29,"tag":48,"props":10914,"children":10915},{},[10916],{"type":56,"value":10917},"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":29,"tag":48,"props":10919,"children":10920},{},[10921],{"type":56,"value":10922},"To merge these updates automatically, we need to do some adjustments.",{"type":29,"tag":657,"props":10924,"children":10927},{"className":1953,"code":10925,"filename":10660,"highlights":10926,"language":454,"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",[662,663,664,665],[10928],{"type":29,"tag":670,"props":10929,"children":10930},{"__ignoreMap":7},[10931,10938,10957,10968,10980,10989,10997,11019,11036],{"type":29,"tag":127,"props":10932,"children":10933},{"class":675,"line":676},[10934],{"type":29,"tag":127,"props":10935,"children":10936},{"style":686},[10937],{"type":56,"value":1972},{"type":29,"tag":127,"props":10939,"children":10940},{"class":675,"line":342},[10941,10945,10949,10953],{"type":29,"tag":127,"props":10942,"children":10943},{"style":1978},[10944],{"type":56,"value":10679},{"type":29,"tag":127,"props":10946,"children":10947},{"style":686},[10948],{"type":56,"value":715},{"type":29,"tag":127,"props":10950,"children":10951},{"style":1988},[10952],{"type":56,"value":10688},{"type":29,"tag":127,"props":10954,"children":10955},{"style":686},[10956],{"type":56,"value":1996},{"type":29,"tag":127,"props":10958,"children":10959},{"class":675,"line":704},[10960,10964],{"type":29,"tag":127,"props":10961,"children":10962},{"style":1978},[10963],{"type":56,"value":10700},{"type":29,"tag":127,"props":10965,"children":10966},{"style":686},[10967],{"type":56,"value":2213},{"type":29,"tag":127,"props":10969,"children":10970},{"class":675,"line":724},[10971,10976],{"type":29,"tag":127,"props":10972,"children":10973},{"style":1988},[10974],{"type":56,"value":10975},"    \"config:best-practices\"",{"type":29,"tag":127,"props":10977,"children":10978},{"style":686},[10979],{"type":56,"value":1996},{"type":29,"tag":127,"props":10981,"children":10983},{"class":10982,"line":662},[675,738],[10984],{"type":29,"tag":127,"props":10985,"children":10986},{"style":1988},[10987],{"type":56,"value":10988},"    \"default:automergeDigest\"\n",{"type":29,"tag":127,"props":10990,"children":10992},{"class":10991,"line":663},[675,738],[10993],{"type":29,"tag":127,"props":10994,"children":10995},{"style":686},[10996],{"type":56,"value":2552},{"type":29,"tag":127,"props":10998,"children":11000},{"class":10999,"line":664},[675,738],[11001,11006,11010,11015],{"type":29,"tag":127,"props":11002,"children":11003},{"style":1978},[11004],{"type":56,"value":11005},"  \"automergeType\"",{"type":29,"tag":127,"props":11007,"children":11008},{"style":686},[11009],{"type":56,"value":715},{"type":29,"tag":127,"props":11011,"children":11012},{"style":1988},[11013],{"type":56,"value":11014},"\"branch\"",{"type":29,"tag":127,"props":11016,"children":11017},{"style":686},[11018],{"type":56,"value":1996},{"type":29,"tag":127,"props":11020,"children":11022},{"class":11021,"line":665},[675,738],[11023,11028,11032],{"type":29,"tag":127,"props":11024,"children":11025},{"style":1978},[11026],{"type":56,"value":11027},"  \"ignoreTests\"",{"type":29,"tag":127,"props":11029,"children":11030},{"style":686},[11031],{"type":56,"value":715},{"type":29,"tag":127,"props":11033,"children":11034},{"style":2290},[11035],{"type":56,"value":2293},{"type":29,"tag":127,"props":11037,"children":11038},{"class":675,"line":666},[11039],{"type":29,"tag":127,"props":11040,"children":11041},{"style":686},[11042],{"type":56,"value":3000},{"type":29,"tag":48,"props":11044,"children":11045},{},[11046,11048,11054,11055],{"type":56,"value":11047},"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":29,"tag":643,"props":11049,"children":11051},{"href":11050},"https://docs.renovatebot.com/key-concepts/automerge/#branch-vs-pr-automerging",[11052],{"type":56,"value":11053},"automergeType",{"type":56,"value":9668},{"type":29,"tag":643,"props":11056,"children":11058},{"href":11057},"https://docs.renovatebot.com/key-concepts/automerge/#absence-of-tests",[11059],{"type":56,"value":11060},"ignoreTests",{"type":29,"tag":1826,"props":11062,"children":11063},{},[11064],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":11066},[11067,11068,11069,11070,11071],{"id":9700,"depth":342,"text":9703},{"id":9737,"depth":342,"text":9740},{"id":9778,"depth":342,"text":9781},{"id":10648,"depth":342,"text":10651},{"id":10734,"depth":342,"text":10737},{"_path":574,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":575,"description":576,"author":518,"image":519,"releaseDate":577,"blogCategories":11073,"articleTags":11074,"tags":11075,"body":11076,"_type":346,"_id":581,"_source":348,"_file":582,"_stem":583,"_extension":351},[522,523],[523,536],[461,24],{"type":26,"children":11077,"toc":11599},[11078,11082,11093,11099,11112,11121,11152,11158,11185,11190,11218,11524,11529,11595],{"type":29,"tag":61,"props":11079,"children":11081},{"alt":7,"aspect-ratio":1849,"height":1850,"object-fit":1851,"src":11080},"/blog/shopware-renovate.png",[],{"type":29,"tag":48,"props":11083,"children":11084},{},[11085,11091],{"type":29,"tag":643,"props":11086,"children":11088},{"href":11087},"https://docs.renovatebot.com/",[11089],{"type":56,"value":11090},"Renovate",{"type":56,"value":11092}," 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":29,"tag":90,"props":11094,"children":11096},{"id":11095},"shopware-versioning-scheme",[11097],{"type":56,"value":11098},"Shopware versioning scheme",{"type":29,"tag":48,"props":11100,"children":11101},{},[11102,11104,11110],{"type":56,"value":11103},"Shopware is using a custom versioning scheme. You can read the ",{"type":29,"tag":643,"props":11105,"children":11107},{"href":11106},"https://www.shopware.com/en/news/shopware-6-versioning-strategy/",[11108],{"type":56,"value":11109},"official article",{"type":56,"value":11111},", but in short:",{"type":29,"tag":11113,"props":11114,"children":11115},"blockquote",{},[11116],{"type":29,"tag":48,"props":11117,"children":11118},{},[11119],{"type":56,"value":11120},"Shopware implemented SemVer as  \"SemVer with benefits\".",{"type":29,"tag":11113,"props":11122,"children":11123},{},[11124,11129,11147],{"type":29,"tag":48,"props":11125,"children":11126},{},[11127],{"type":56,"value":11128},"A SemVer compliant version has three numbers: Major, Minor, and Patch. They are incremented following this ruleset:",{"type":29,"tag":808,"props":11130,"children":11131},{},[11132,11137,11142],{"type":29,"tag":812,"props":11133,"children":11134},{},[11135],{"type":56,"value":11136},"MAJOR: Incompatible API changes are made",{"type":29,"tag":812,"props":11138,"children":11139},{},[11140],{"type":56,"value":11141},"MINOR: Functionality is added in a backward-compatible manner",{"type":29,"tag":812,"props":11143,"children":11144},{},[11145],{"type":56,"value":11146},"PATCH: Backward-compatible bug fixes are made",{"type":29,"tag":48,"props":11148,"children":11149},{},[11150],{"type":56,"value":11151},"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":29,"tag":90,"props":11153,"children":11155},{"id":11154},"renovate-configuration",[11156],{"type":56,"value":11157},"Renovate configuration",{"type":29,"tag":48,"props":11159,"children":11160},{},[11161,11163,11169,11171,11177,11179],{"type":56,"value":11162},"The ",{"type":29,"tag":670,"props":11164,"children":11166},{"className":11165},[],[11167],{"type":56,"value":11168},"\"big marketing number\"",{"type":56,"value":11170}," or ",{"type":29,"tag":670,"props":11172,"children":11174},{"className":11173},[],[11175],{"type":56,"value":11176},"\"generation\"",{"type":56,"value":11178}," is reflected in Renovate as ",{"type":29,"tag":670,"props":11180,"children":11182},{"className":11181},[],[11183],{"type":56,"value":11184},"compatibility",{"type":29,"tag":48,"props":11186,"children":11187},{},[11188],{"type":56,"value":11189},"The following configuration will:",{"type":29,"tag":960,"props":11191,"children":11192},{},[11193,11198,11208,11213],{"type":29,"tag":812,"props":11194,"children":11195},{},[11196],{"type":56,"value":11197},"Group all shopware specific updates",{"type":29,"tag":812,"props":11199,"children":11200},{},[11201,11203],{"type":56,"value":11202},"Group the updates as ",{"type":29,"tag":670,"props":11204,"children":11206},{"className":11205},[],[11207],{"type":56,"value":461},{"type":29,"tag":812,"props":11209,"children":11210},{},[11211],{"type":56,"value":11212},"Tell Renovate how to extract the version",{"type":29,"tag":812,"props":11214,"children":11215},{},[11216],{"type":56,"value":11217},"Tell Renovate where to find changelog information",{"type":29,"tag":657,"props":11219,"children":11221},{"className":1953,"code":11220,"filename":10660,"language":454,"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",[11222],{"type":29,"tag":670,"props":11223,"children":11224},{"__ignoreMap":7},[11225,11232,11251,11263,11270,11291,11303,11311,11319,11331,11342,11354,11366,11374,11381,11402,11486,11503,11510,11517],{"type":29,"tag":127,"props":11226,"children":11227},{"class":675,"line":676},[11228],{"type":29,"tag":127,"props":11229,"children":11230},{"style":686},[11231],{"type":56,"value":1972},{"type":29,"tag":127,"props":11233,"children":11234},{"class":675,"line":342},[11235,11239,11243,11247],{"type":29,"tag":127,"props":11236,"children":11237},{"style":1978},[11238],{"type":56,"value":10679},{"type":29,"tag":127,"props":11240,"children":11241},{"style":686},[11242],{"type":56,"value":715},{"type":29,"tag":127,"props":11244,"children":11245},{"style":1988},[11246],{"type":56,"value":10688},{"type":29,"tag":127,"props":11248,"children":11249},{"style":686},[11250],{"type":56,"value":1996},{"type":29,"tag":127,"props":11252,"children":11253},{"class":675,"line":704},[11254,11259],{"type":29,"tag":127,"props":11255,"children":11256},{"style":1978},[11257],{"type":56,"value":11258},"  \"packageRules\"",{"type":29,"tag":127,"props":11260,"children":11261},{"style":686},[11262],{"type":56,"value":2213},{"type":29,"tag":127,"props":11264,"children":11265},{"class":675,"line":724},[11266],{"type":29,"tag":127,"props":11267,"children":11268},{"style":686},[11269],{"type":56,"value":2221},{"type":29,"tag":127,"props":11271,"children":11272},{"class":675,"line":662},[11273,11278,11282,11287],{"type":29,"tag":127,"props":11274,"children":11275},{"style":1978},[11276],{"type":56,"value":11277},"      \"description\"",{"type":29,"tag":127,"props":11279,"children":11280},{"style":686},[11281],{"type":56,"value":715},{"type":29,"tag":127,"props":11283,"children":11284},{"style":1988},[11285],{"type":56,"value":11286},"\"Follow Shopware version schema\"",{"type":29,"tag":127,"props":11288,"children":11289},{"style":686},[11290],{"type":56,"value":1996},{"type":29,"tag":127,"props":11292,"children":11293},{"class":675,"line":663},[11294,11299],{"type":29,"tag":127,"props":11295,"children":11296},{"style":1978},[11297],{"type":56,"value":11298},"      \"matchDatasources\"",{"type":29,"tag":127,"props":11300,"children":11301},{"style":686},[11302],{"type":56,"value":2213},{"type":29,"tag":127,"props":11304,"children":11305},{"class":675,"line":664},[11306],{"type":29,"tag":127,"props":11307,"children":11308},{"style":1988},[11309],{"type":56,"value":11310},"        \"packagist\"\n",{"type":29,"tag":127,"props":11312,"children":11313},{"class":675,"line":665},[11314],{"type":29,"tag":127,"props":11315,"children":11316},{"style":686},[11317],{"type":56,"value":11318},"      ],\n",{"type":29,"tag":127,"props":11320,"children":11321},{"class":675,"line":666},[11322,11327],{"type":29,"tag":127,"props":11323,"children":11324},{"style":1978},[11325],{"type":56,"value":11326},"      \"matchPackageNames\"",{"type":29,"tag":127,"props":11328,"children":11329},{"style":686},[11330],{"type":56,"value":2213},{"type":29,"tag":127,"props":11332,"children":11333},{"class":675,"line":1325},[11334,11338],{"type":29,"tag":127,"props":11335,"children":11336},{"style":1988},[11337],{"type":56,"value":3411},{"type":29,"tag":127,"props":11339,"children":11340},{"style":686},[11341],{"type":56,"value":1996},{"type":29,"tag":127,"props":11343,"children":11344},{"class":675,"line":1338},[11345,11350],{"type":29,"tag":127,"props":11346,"children":11347},{"style":1988},[11348],{"type":56,"value":11349},"        \"shopware/administration\"",{"type":29,"tag":127,"props":11351,"children":11352},{"style":686},[11353],{"type":56,"value":1996},{"type":29,"tag":127,"props":11355,"children":11356},{"class":675,"line":118},[11357,11362],{"type":29,"tag":127,"props":11358,"children":11359},{"style":1988},[11360],{"type":56,"value":11361},"        \"shopware/elasticsearch\"",{"type":29,"tag":127,"props":11363,"children":11364},{"style":686},[11365],{"type":56,"value":1996},{"type":29,"tag":127,"props":11367,"children":11368},{"class":675,"line":1363},[11369],{"type":29,"tag":127,"props":11370,"children":11371},{"style":1988},[11372],{"type":56,"value":11373},"        \"shopware/storefront\"\n",{"type":29,"tag":127,"props":11375,"children":11376},{"class":675,"line":1376},[11377],{"type":29,"tag":127,"props":11378,"children":11379},{"style":686},[11380],{"type":56,"value":11318},{"type":29,"tag":127,"props":11382,"children":11383},{"class":675,"line":1389},[11384,11389,11393,11398],{"type":29,"tag":127,"props":11385,"children":11386},{"style":1978},[11387],{"type":56,"value":11388},"      \"groupName\"",{"type":29,"tag":127,"props":11390,"children":11391},{"style":686},[11392],{"type":56,"value":715},{"type":29,"tag":127,"props":11394,"children":11395},{"style":1988},[11396],{"type":56,"value":11397},"\"shopware\"",{"type":29,"tag":127,"props":11399,"children":11400},{"style":686},[11401],{"type":56,"value":1996},{"type":29,"tag":127,"props":11403,"children":11404},{"class":675,"line":1398},[11405,11410,11414,11419,11423,11428,11432,11437,11441,11446,11450,11455,11459,11464,11468,11473,11477,11482],{"type":29,"tag":127,"props":11406,"children":11407},{"style":1978},[11408],{"type":56,"value":11409},"      \"versioning\"",{"type":29,"tag":127,"props":11411,"children":11412},{"style":686},[11413],{"type":56,"value":715},{"type":29,"tag":127,"props":11415,"children":11416},{"style":1988},[11417],{"type":56,"value":11418},"\"regex:(?\u003Ccompatibility>",{"type":29,"tag":127,"props":11420,"children":11421},{"style":2290},[11422],{"type":56,"value":2593},{"type":29,"tag":127,"props":11424,"children":11425},{"style":1988},[11426],{"type":56,"value":11427},"d+)",{"type":29,"tag":127,"props":11429,"children":11430},{"style":2290},[11431],{"type":56,"value":2593},{"type":29,"tag":127,"props":11433,"children":11434},{"style":1988},[11435],{"type":56,"value":11436},".(?\u003Cmajor>",{"type":29,"tag":127,"props":11438,"children":11439},{"style":2290},[11440],{"type":56,"value":2593},{"type":29,"tag":127,"props":11442,"children":11443},{"style":1988},[11444],{"type":56,"value":11445},"d+)(",{"type":29,"tag":127,"props":11447,"children":11448},{"style":2290},[11449],{"type":56,"value":2593},{"type":29,"tag":127,"props":11451,"children":11452},{"style":1988},[11453],{"type":56,"value":11454},".(?\u003Cminor>",{"type":29,"tag":127,"props":11456,"children":11457},{"style":2290},[11458],{"type":56,"value":2593},{"type":29,"tag":127,"props":11460,"children":11461},{"style":1988},[11462],{"type":56,"value":11463},"d+))?(",{"type":29,"tag":127,"props":11465,"children":11466},{"style":2290},[11467],{"type":56,"value":2593},{"type":29,"tag":127,"props":11469,"children":11470},{"style":1988},[11471],{"type":56,"value":11472},".(?\u003Cpatch>",{"type":29,"tag":127,"props":11474,"children":11475},{"style":2290},[11476],{"type":56,"value":2593},{"type":29,"tag":127,"props":11478,"children":11479},{"style":1988},[11480],{"type":56,"value":11481},"d+))?$\"",{"type":29,"tag":127,"props":11483,"children":11484},{"style":686},[11485],{"type":56,"value":1996},{"type":29,"tag":127,"props":11487,"children":11488},{"class":675,"line":1411},[11489,11494,11498],{"type":29,"tag":127,"props":11490,"children":11491},{"style":1978},[11492],{"type":56,"value":11493},"      \"sourceUrl\"",{"type":29,"tag":127,"props":11495,"children":11496},{"style":686},[11497],{"type":56,"value":715},{"type":29,"tag":127,"props":11499,"children":11500},{"style":1988},[11501],{"type":56,"value":11502},"\"https://github.com/shopware/shopware\"\n",{"type":29,"tag":127,"props":11504,"children":11505},{"class":675,"line":1424},[11506],{"type":29,"tag":127,"props":11507,"children":11508},{"style":686},[11509],{"type":56,"value":2543},{"type":29,"tag":127,"props":11511,"children":11512},{"class":675,"line":1433},[11513],{"type":29,"tag":127,"props":11514,"children":11515},{"style":686},[11516],{"type":56,"value":6173},{"type":29,"tag":127,"props":11518,"children":11519},{"class":675,"line":1446},[11520],{"type":29,"tag":127,"props":11521,"children":11522},{"style":686},[11523],{"type":56,"value":3000},{"type":29,"tag":48,"props":11525,"children":11526},{},[11527],{"type":56,"value":11528},"This should result in creation of following merge/pull requests",{"type":29,"tag":808,"props":11530,"children":11531},{},[11532,11566],{"type":29,"tag":812,"props":11533,"children":11534},{},[11535,11537,11543,11544,11550,11551,11557,11558,11564],{"type":56,"value":11536},"fix(deps): update shopware (",{"type":29,"tag":670,"props":11538,"children":11540},{"className":11539},[],[11541],{"type":56,"value":11542},"shopware/administration",{"type":56,"value":10167},{"type":29,"tag":670,"props":11545,"children":11547},{"className":11546},[],[11548],{"type":56,"value":11549},"shopware/core",{"type":56,"value":10167},{"type":29,"tag":670,"props":11552,"children":11554},{"className":11553},[],[11555],{"type":56,"value":11556},"shopware/elasticsearch",{"type":56,"value":10167},{"type":29,"tag":670,"props":11559,"children":11561},{"className":11560},[],[11562],{"type":56,"value":11563},"shopware/storefront",{"type":56,"value":11565},")`",{"type":29,"tag":812,"props":11567,"children":11568},{},[11569,11571,11576,11577,11582,11583,11588,11589,11594],{"type":56,"value":11570},"fix(deps): update shopware to v7 (major) (",{"type":29,"tag":670,"props":11572,"children":11574},{"className":11573},[],[11575],{"type":56,"value":11542},{"type":56,"value":10167},{"type":29,"tag":670,"props":11578,"children":11580},{"className":11579},[],[11581],{"type":56,"value":11549},{"type":56,"value":10167},{"type":29,"tag":670,"props":11584,"children":11586},{"className":11585},[],[11587],{"type":56,"value":11556},{"type":56,"value":10167},{"type":29,"tag":670,"props":11590,"children":11592},{"className":11591},[],[11593],{"type":56,"value":11563},{"type":56,"value":11565},{"type":29,"tag":1826,"props":11596,"children":11597},{},[11598],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":11600},[11601,11602],{"id":11095,"depth":342,"text":11098},{"id":11154,"depth":342,"text":11157},{"_path":585,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":586,"description":587,"author":518,"image":519,"releaseDate":588,"blogCategories":11604,"articleTags":11605,"tags":11606,"body":11607,"_type":346,"_id":593,"_source":348,"_file":594,"_stem":595,"_extension":351},[522,590],[523],[24],{"type":26,"children":11608,"toc":14506},[11609,11613,11619,11629,11880,11885,11891,11896,11901,11906,12005,12011,12016,12255,12261,12266,12284,12291,12307,12634,12639,12702,12708,12723,12747,13119,13123,13159,13162,13170,13173,13176,13182,13193,13203,13216,13219,13226,13620,13624,13649,13652,13655,13665,13671,14027,14031,14044,14047,14052,14482,14486,14502],{"type":29,"tag":61,"props":11610,"children":11612},{"alt":7,"aspect-ratio":1849,"height":1850,"object-fit":1851,"src":11611},"/blog/gitlab-traefik.png",[],{"type":29,"tag":90,"props":11614,"children":11616},{"id":11615},"the-simplest-way-to-install-gitlab",[11617],{"type":56,"value":11618},"The simplest way to install GitLab",{"type":29,"tag":48,"props":11620,"children":11621},{},[11622,11624],{"type":56,"value":11623},"GitLab provides official instructions to install it using Docker and Docker Compose. You can find it in ",{"type":29,"tag":643,"props":11625,"children":11627},{"href":11626},"https://docs.gitlab.com/install/docker/installation/#install-gitlab-by-using-docker-compose",[11628],{"type":56,"value":9751},{"type":29,"tag":657,"props":11630,"children":11633},{"className":667,"code":11631,"filename":11632,"language":508,"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",[11634],{"type":29,"tag":670,"props":11635,"children":11636},{"__ignoreMap":7},[11637,11648,11660,11676,11692,11707,11724,11735,11752,11760,11768,11780,11792,11804,11816,11827,11839,11851,11863],{"type":29,"tag":127,"props":11638,"children":11639},{"class":675,"line":676},[11640,11644],{"type":29,"tag":127,"props":11641,"children":11642},{"style":680},[11643],{"type":56,"value":683},{"type":29,"tag":127,"props":11645,"children":11646},{"style":686},[11647],{"type":56,"value":689},{"type":29,"tag":127,"props":11649,"children":11650},{"class":675,"line":342},[11651,11656],{"type":29,"tag":127,"props":11652,"children":11653},{"style":680},[11654],{"type":56,"value":11655},"  gitlab",{"type":29,"tag":127,"props":11657,"children":11658},{"style":686},[11659],{"type":56,"value":689},{"type":29,"tag":127,"props":11661,"children":11662},{"class":675,"line":704},[11663,11667,11671],{"type":29,"tag":127,"props":11664,"children":11665},{"style":680},[11666],{"type":56,"value":710},{"type":29,"tag":127,"props":11668,"children":11669},{"style":686},[11670],{"type":56,"value":715},{"type":29,"tag":127,"props":11672,"children":11673},{"style":718},[11674],{"type":56,"value":11675},"gitlab/gitlab-ee:\u003Cversion>-ce.0\n",{"type":29,"tag":127,"props":11677,"children":11678},{"class":675,"line":724},[11679,11683,11687],{"type":29,"tag":127,"props":11680,"children":11681},{"style":680},[11682],{"type":56,"value":1263},{"type":29,"tag":127,"props":11684,"children":11685},{"style":686},[11686],{"type":56,"value":715},{"type":29,"tag":127,"props":11688,"children":11689},{"style":718},[11690],{"type":56,"value":11691},"gitlab\n",{"type":29,"tag":127,"props":11693,"children":11694},{"class":675,"line":662},[11695,11699,11703],{"type":29,"tag":127,"props":11696,"children":11697},{"style":680},[11698],{"type":56,"value":1280},{"type":29,"tag":127,"props":11700,"children":11701},{"style":686},[11702],{"type":56,"value":715},{"type":29,"tag":127,"props":11704,"children":11705},{"style":718},[11706],{"type":56,"value":1289},{"type":29,"tag":127,"props":11708,"children":11709},{"class":675,"line":663},[11710,11715,11719],{"type":29,"tag":127,"props":11711,"children":11712},{"style":680},[11713],{"type":56,"value":11714},"    hostname",{"type":29,"tag":127,"props":11716,"children":11717},{"style":686},[11718],{"type":56,"value":715},{"type":29,"tag":127,"props":11720,"children":11721},{"style":718},[11722],{"type":56,"value":11723},"'\u003Cgitlab.example.com>'\n",{"type":29,"tag":127,"props":11725,"children":11726},{"class":675,"line":664},[11727,11731],{"type":29,"tag":127,"props":11728,"children":11729},{"style":680},[11730],{"type":56,"value":10034},{"type":29,"tag":127,"props":11732,"children":11733},{"style":686},[11734],{"type":56,"value":689},{"type":29,"tag":127,"props":11736,"children":11737},{"class":675,"line":665},[11738,11743,11747],{"type":29,"tag":127,"props":11739,"children":11740},{"style":680},[11741],{"type":56,"value":11742},"      GITLAB_OMNIBUS_CONFIG",{"type":29,"tag":127,"props":11744,"children":11745},{"style":686},[11746],{"type":56,"value":715},{"type":29,"tag":127,"props":11748,"children":11749},{"style":4927},[11750],{"type":56,"value":11751},"|\n",{"type":29,"tag":127,"props":11753,"children":11754},{"class":675,"line":666},[11755],{"type":29,"tag":127,"props":11756,"children":11757},{"style":718},[11758],{"type":56,"value":11759},"        # Add any other gitlab.rb configuration here, each on its own line\n",{"type":29,"tag":127,"props":11761,"children":11762},{"class":675,"line":1325},[11763],{"type":29,"tag":127,"props":11764,"children":11765},{"style":718},[11766],{"type":56,"value":11767},"        external_url 'https://\u003Cgitlab.example.com>'\n",{"type":29,"tag":127,"props":11769,"children":11770},{"class":675,"line":1338},[11771,11776],{"type":29,"tag":127,"props":11772,"children":11773},{"style":680},[11774],{"type":56,"value":11775},"    ports",{"type":29,"tag":127,"props":11777,"children":11778},{"style":686},[11779],{"type":56,"value":689},{"type":29,"tag":127,"props":11781,"children":11782},{"class":675,"line":118},[11783,11787],{"type":29,"tag":127,"props":11784,"children":11785},{"style":686},[11786],{"type":56,"value":744},{"type":29,"tag":127,"props":11788,"children":11789},{"style":718},[11790],{"type":56,"value":11791},"'80:80'\n",{"type":29,"tag":127,"props":11793,"children":11794},{"class":675,"line":1363},[11795,11799],{"type":29,"tag":127,"props":11796,"children":11797},{"style":686},[11798],{"type":56,"value":744},{"type":29,"tag":127,"props":11800,"children":11801},{"style":718},[11802],{"type":56,"value":11803},"'443:443'\n",{"type":29,"tag":127,"props":11805,"children":11806},{"class":675,"line":1376},[11807,11811],{"type":29,"tag":127,"props":11808,"children":11809},{"style":686},[11810],{"type":56,"value":744},{"type":29,"tag":127,"props":11812,"children":11813},{"style":718},[11814],{"type":56,"value":11815},"'22:22'\n",{"type":29,"tag":127,"props":11817,"children":11818},{"class":675,"line":1389},[11819,11823],{"type":29,"tag":127,"props":11820,"children":11821},{"style":680},[11822],{"type":56,"value":1525},{"type":29,"tag":127,"props":11824,"children":11825},{"style":686},[11826],{"type":56,"value":689},{"type":29,"tag":127,"props":11828,"children":11829},{"class":675,"line":1398},[11830,11834],{"type":29,"tag":127,"props":11831,"children":11832},{"style":686},[11833],{"type":56,"value":744},{"type":29,"tag":127,"props":11835,"children":11836},{"style":718},[11837],{"type":56,"value":11838},"'$GITLAB_HOME/config:/etc/gitlab'\n",{"type":29,"tag":127,"props":11840,"children":11841},{"class":675,"line":1411},[11842,11846],{"type":29,"tag":127,"props":11843,"children":11844},{"style":686},[11845],{"type":56,"value":744},{"type":29,"tag":127,"props":11847,"children":11848},{"style":718},[11849],{"type":56,"value":11850},"'$GITLAB_HOME/logs:/var/log/gitlab'\n",{"type":29,"tag":127,"props":11852,"children":11853},{"class":675,"line":1424},[11854,11858],{"type":29,"tag":127,"props":11855,"children":11856},{"style":686},[11857],{"type":56,"value":744},{"type":29,"tag":127,"props":11859,"children":11860},{"style":718},[11861],{"type":56,"value":11862},"'$GITLAB_HOME/data:/var/opt/gitlab'\n",{"type":29,"tag":127,"props":11864,"children":11865},{"class":675,"line":1433},[11866,11871,11875],{"type":29,"tag":127,"props":11867,"children":11868},{"style":680},[11869],{"type":56,"value":11870},"    shm_size",{"type":29,"tag":127,"props":11872,"children":11873},{"style":686},[11874],{"type":56,"value":715},{"type":29,"tag":127,"props":11876,"children":11877},{"style":718},[11878],{"type":56,"value":11879},"'256m'\n",{"type":29,"tag":48,"props":11881,"children":11882},{},[11883],{"type":56,"value":11884},"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":29,"tag":90,"props":11886,"children":11888},{"id":11887},"integrating-gitlab-alongside-other-deployments",[11889],{"type":56,"value":11890},"Integrating GitLab alongside other deployments",{"type":29,"tag":48,"props":11892,"children":11893},{},[11894],{"type":56,"value":11895},"What if you can't or don't want to install GitLab on a dedicated server?",{"type":29,"tag":48,"props":11897,"children":11898},{},[11899],{"type":56,"value":11900},"Maybe you just want a single server for all you services?",{"type":29,"tag":48,"props":11902,"children":11903},{},[11904],{"type":56,"value":11905},"This is an example structure how you could organize your deployments:",{"type":29,"tag":657,"props":11907,"children":11909},{"className":3008,"code":11908,"language":3010,"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",[11910],{"type":29,"tag":670,"props":11911,"children":11912},{"__ignoreMap":7},[11913,11920,11937,11954,11971,11988],{"type":29,"tag":127,"props":11914,"children":11915},{"class":675,"line":676},[11916],{"type":29,"tag":127,"props":11917,"children":11918},{"style":9799},[11919],{"type":56,"value":9802},{"type":29,"tag":127,"props":11921,"children":11922},{"class":675,"line":342},[11923,11927,11932],{"type":29,"tag":127,"props":11924,"children":11925},{"style":3020},[11926],{"type":56,"value":9824},{"type":29,"tag":127,"props":11928,"children":11929},{"style":718},[11930],{"type":56,"value":11931}," gitlab/",{"type":29,"tag":127,"props":11933,"children":11934},{"style":9813},[11935],{"type":56,"value":11936},"                # GitLab service stack\n",{"type":29,"tag":127,"props":11938,"children":11939},{"class":675,"line":704},[11940,11944,11949],{"type":29,"tag":127,"props":11941,"children":11942},{"style":3020},[11943],{"type":56,"value":9824},{"type":29,"tag":127,"props":11945,"children":11946},{"style":718},[11947],{"type":56,"value":11948}," gitlab-runner/",{"type":29,"tag":127,"props":11950,"children":11951},{"style":9813},[11952],{"type":56,"value":11953},"         # GitLab Runner for CI/CD\n",{"type":29,"tag":127,"props":11955,"children":11956},{"class":675,"line":724},[11957,11961,11966],{"type":29,"tag":127,"props":11958,"children":11959},{"style":3020},[11960],{"type":56,"value":9824},{"type":29,"tag":127,"props":11962,"children":11963},{"style":718},[11964],{"type":56,"value":11965}," mattermost/",{"type":29,"tag":127,"props":11967,"children":11968},{"style":9813},[11969],{"type":56,"value":11970},"            # Mattermost team collaboration\n",{"type":29,"tag":127,"props":11972,"children":11973},{"class":675,"line":662},[11974,11978,11983],{"type":29,"tag":127,"props":11975,"children":11976},{"style":3020},[11977],{"type":56,"value":9824},{"type":29,"tag":127,"props":11979,"children":11980},{"style":718},[11981],{"type":56,"value":11982}," nextcloud/",{"type":29,"tag":127,"props":11984,"children":11985},{"style":9813},[11986],{"type":56,"value":11987},"             # Nextcloud file hosting and collaboration\n",{"type":29,"tag":127,"props":11989,"children":11990},{"class":675,"line":663},[11991,11995,12000],{"type":29,"tag":127,"props":11992,"children":11993},{"style":3020},[11994],{"type":56,"value":9877},{"type":29,"tag":127,"props":11996,"children":11997},{"style":718},[11998],{"type":56,"value":11999}," traefik/",{"type":29,"tag":127,"props":12001,"children":12002},{"style":9813},[12003],{"type":56,"value":12004},"               # Traefik reverse proxy configuration\n",{"type":29,"tag":122,"props":12006,"children":12008},{"id":12007},"using-a-dedicated-ip",[12009],{"type":56,"value":12010},"Using a dedicated IP",{"type":29,"tag":48,"props":12012,"children":12013},{},[12014],{"type":56,"value":12015},"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":29,"tag":657,"props":12017,"children":12020},{"className":667,"code":12018,"filename":11632,"highlights":12019,"language":508,"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",[118,1363,1376],[12021],{"type":29,"tag":670,"props":12022,"children":12023},{"__ignoreMap":7},[12024,12035,12046,12061,12076,12091,12106,12117,12132,12139,12146,12157,12170,12183,12196,12207,12218,12229,12240],{"type":29,"tag":127,"props":12025,"children":12026},{"class":675,"line":676},[12027,12031],{"type":29,"tag":127,"props":12028,"children":12029},{"style":680},[12030],{"type":56,"value":683},{"type":29,"tag":127,"props":12032,"children":12033},{"style":686},[12034],{"type":56,"value":689},{"type":29,"tag":127,"props":12036,"children":12037},{"class":675,"line":342},[12038,12042],{"type":29,"tag":127,"props":12039,"children":12040},{"style":680},[12041],{"type":56,"value":11655},{"type":29,"tag":127,"props":12043,"children":12044},{"style":686},[12045],{"type":56,"value":689},{"type":29,"tag":127,"props":12047,"children":12048},{"class":675,"line":704},[12049,12053,12057],{"type":29,"tag":127,"props":12050,"children":12051},{"style":680},[12052],{"type":56,"value":710},{"type":29,"tag":127,"props":12054,"children":12055},{"style":686},[12056],{"type":56,"value":715},{"type":29,"tag":127,"props":12058,"children":12059},{"style":718},[12060],{"type":56,"value":11675},{"type":29,"tag":127,"props":12062,"children":12063},{"class":675,"line":724},[12064,12068,12072],{"type":29,"tag":127,"props":12065,"children":12066},{"style":680},[12067],{"type":56,"value":1263},{"type":29,"tag":127,"props":12069,"children":12070},{"style":686},[12071],{"type":56,"value":715},{"type":29,"tag":127,"props":12073,"children":12074},{"style":718},[12075],{"type":56,"value":11691},{"type":29,"tag":127,"props":12077,"children":12078},{"class":675,"line":662},[12079,12083,12087],{"type":29,"tag":127,"props":12080,"children":12081},{"style":680},[12082],{"type":56,"value":1280},{"type":29,"tag":127,"props":12084,"children":12085},{"style":686},[12086],{"type":56,"value":715},{"type":29,"tag":127,"props":12088,"children":12089},{"style":718},[12090],{"type":56,"value":1289},{"type":29,"tag":127,"props":12092,"children":12093},{"class":675,"line":663},[12094,12098,12102],{"type":29,"tag":127,"props":12095,"children":12096},{"style":680},[12097],{"type":56,"value":11714},{"type":29,"tag":127,"props":12099,"children":12100},{"style":686},[12101],{"type":56,"value":715},{"type":29,"tag":127,"props":12103,"children":12104},{"style":718},[12105],{"type":56,"value":11723},{"type":29,"tag":127,"props":12107,"children":12108},{"class":675,"line":664},[12109,12113],{"type":29,"tag":127,"props":12110,"children":12111},{"style":680},[12112],{"type":56,"value":10034},{"type":29,"tag":127,"props":12114,"children":12115},{"style":686},[12116],{"type":56,"value":689},{"type":29,"tag":127,"props":12118,"children":12119},{"class":675,"line":665},[12120,12124,12128],{"type":29,"tag":127,"props":12121,"children":12122},{"style":680},[12123],{"type":56,"value":11742},{"type":29,"tag":127,"props":12125,"children":12126},{"style":686},[12127],{"type":56,"value":715},{"type":29,"tag":127,"props":12129,"children":12130},{"style":4927},[12131],{"type":56,"value":11751},{"type":29,"tag":127,"props":12133,"children":12134},{"class":675,"line":666},[12135],{"type":29,"tag":127,"props":12136,"children":12137},{"style":718},[12138],{"type":56,"value":11759},{"type":29,"tag":127,"props":12140,"children":12141},{"class":675,"line":1325},[12142],{"type":29,"tag":127,"props":12143,"children":12144},{"style":718},[12145],{"type":56,"value":11767},{"type":29,"tag":127,"props":12147,"children":12148},{"class":675,"line":1338},[12149,12153],{"type":29,"tag":127,"props":12150,"children":12151},{"style":680},[12152],{"type":56,"value":11775},{"type":29,"tag":127,"props":12154,"children":12155},{"style":686},[12156],{"type":56,"value":689},{"type":29,"tag":127,"props":12158,"children":12160},{"class":12159,"line":118},[675,738],[12161,12165],{"type":29,"tag":127,"props":12162,"children":12163},{"style":686},[12164],{"type":56,"value":744},{"type":29,"tag":127,"props":12166,"children":12167},{"style":718},[12168],{"type":56,"value":12169},"'192.168.0.1:80:80'\n",{"type":29,"tag":127,"props":12171,"children":12173},{"class":12172,"line":1363},[675,738],[12174,12178],{"type":29,"tag":127,"props":12175,"children":12176},{"style":686},[12177],{"type":56,"value":744},{"type":29,"tag":127,"props":12179,"children":12180},{"style":718},[12181],{"type":56,"value":12182},"'192.168.0.1:443:443'\n",{"type":29,"tag":127,"props":12184,"children":12186},{"class":12185,"line":1376},[675,738],[12187,12191],{"type":29,"tag":127,"props":12188,"children":12189},{"style":686},[12190],{"type":56,"value":744},{"type":29,"tag":127,"props":12192,"children":12193},{"style":718},[12194],{"type":56,"value":12195},"'192.168.0.1:22:22'\n",{"type":29,"tag":127,"props":12197,"children":12198},{"class":675,"line":1389},[12199,12203],{"type":29,"tag":127,"props":12200,"children":12201},{"style":680},[12202],{"type":56,"value":1525},{"type":29,"tag":127,"props":12204,"children":12205},{"style":686},[12206],{"type":56,"value":689},{"type":29,"tag":127,"props":12208,"children":12209},{"class":675,"line":1398},[12210,12214],{"type":29,"tag":127,"props":12211,"children":12212},{"style":686},[12213],{"type":56,"value":744},{"type":29,"tag":127,"props":12215,"children":12216},{"style":718},[12217],{"type":56,"value":11838},{"type":29,"tag":127,"props":12219,"children":12220},{"class":675,"line":1411},[12221,12225],{"type":29,"tag":127,"props":12222,"children":12223},{"style":686},[12224],{"type":56,"value":744},{"type":29,"tag":127,"props":12226,"children":12227},{"style":718},[12228],{"type":56,"value":11850},{"type":29,"tag":127,"props":12230,"children":12231},{"class":675,"line":1424},[12232,12236],{"type":29,"tag":127,"props":12233,"children":12234},{"style":686},[12235],{"type":56,"value":744},{"type":29,"tag":127,"props":12237,"children":12238},{"style":718},[12239],{"type":56,"value":11862},{"type":29,"tag":127,"props":12241,"children":12242},{"class":675,"line":1433},[12243,12247,12251],{"type":29,"tag":127,"props":12244,"children":12245},{"style":680},[12246],{"type":56,"value":11870},{"type":29,"tag":127,"props":12248,"children":12249},{"style":686},[12250],{"type":56,"value":715},{"type":29,"tag":127,"props":12252,"children":12253},{"style":718},[12254],{"type":56,"value":11879},{"type":29,"tag":122,"props":12256,"children":12258},{"id":12257},"using-traefik-as-a-reverse-proxy",[12259],{"type":56,"value":12260},"Using Traefik as a reverse proxy",{"type":29,"tag":48,"props":12262,"children":12263},{},[12264],{"type":56,"value":12265},"In this case I assume that you:",{"type":29,"tag":808,"props":12267,"children":12268},{},[12269,12274,12279],{"type":29,"tag":812,"props":12270,"children":12271},{},[12272],{"type":56,"value":12273},"can't or don't want to assign a dedicated IP for GitLab",{"type":29,"tag":812,"props":12275,"children":12276},{},[12277],{"type":56,"value":12278},"can't or don't want to change you default ssh port",{"type":29,"tag":812,"props":12280,"children":12281},{},[12282],{"type":56,"value":12283},"want to use Traefik as a reverse proxy",{"type":29,"tag":12285,"props":12286,"children":12288},"h4",{"id":12287},"the-traefik-deployment",[12289],{"type":56,"value":12290},"The Traefik deployment",{"type":29,"tag":48,"props":12292,"children":12293},{},[12294,12296,12305],{"type":56,"value":12295},"Remember to replace ",{"type":29,"tag":52,"props":12297,"children":12298},{},[12299],{"type":29,"tag":670,"props":12300,"children":12302},{"className":12301},[],[12303],{"type":56,"value":12304},"\u003Cinfo@example.com>",{"type":56,"value":12306}," with your own email.",{"type":29,"tag":657,"props":12308,"children":12310},{"className":667,"code":12309,"filename":1195,"language":508,"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",[12311],{"type":29,"tag":670,"props":12312,"children":12313},{"__ignoreMap":7},[12314,12325,12336,12343,12354,12365,12380,12395,12410,12425,12436,12447,12459,12470,12482,12489,12500,12511,12522,12529,12540,12551,12558,12570,12582,12589,12601,12612,12623],{"type":29,"tag":127,"props":12315,"children":12316},{"class":675,"line":676},[12317,12321],{"type":29,"tag":127,"props":12318,"children":12319},{"style":680},[12320],{"type":56,"value":1208},{"type":29,"tag":127,"props":12322,"children":12323},{"style":686},[12324],{"type":56,"value":689},{"type":29,"tag":127,"props":12326,"children":12327},{"class":675,"line":342},[12328,12332],{"type":29,"tag":127,"props":12329,"children":12330},{"style":680},[12331],{"type":56,"value":1220},{"type":29,"tag":127,"props":12333,"children":12334},{"style":686},[12335],{"type":56,"value":689},{"type":29,"tag":127,"props":12337,"children":12338},{"class":675,"line":704},[12339],{"type":29,"tag":127,"props":12340,"children":12341},{"emptyLinePlaceholder":500},[12342],{"type":56,"value":1395},{"type":29,"tag":127,"props":12344,"children":12345},{"class":675,"line":724},[12346,12350],{"type":29,"tag":127,"props":12347,"children":12348},{"style":680},[12349],{"type":56,"value":683},{"type":29,"tag":127,"props":12351,"children":12352},{"style":686},[12353],{"type":56,"value":689},{"type":29,"tag":127,"props":12355,"children":12356},{"class":675,"line":662},[12357,12361],{"type":29,"tag":127,"props":12358,"children":12359},{"style":680},[12360],{"type":56,"value":1251},{"type":29,"tag":127,"props":12362,"children":12363},{"style":686},[12364],{"type":56,"value":689},{"type":29,"tag":127,"props":12366,"children":12367},{"class":675,"line":663},[12368,12372,12376],{"type":29,"tag":127,"props":12369,"children":12370},{"style":680},[12371],{"type":56,"value":710},{"type":29,"tag":127,"props":12373,"children":12374},{"style":686},[12375],{"type":56,"value":715},{"type":29,"tag":127,"props":12377,"children":12378},{"style":718},[12379],{"type":56,"value":1305},{"type":29,"tag":127,"props":12381,"children":12382},{"class":675,"line":664},[12383,12387,12391],{"type":29,"tag":127,"props":12384,"children":12385},{"style":680},[12386],{"type":56,"value":1263},{"type":29,"tag":127,"props":12388,"children":12389},{"style":686},[12390],{"type":56,"value":715},{"type":29,"tag":127,"props":12392,"children":12393},{"style":718},[12394],{"type":56,"value":1272},{"type":29,"tag":127,"props":12396,"children":12397},{"class":675,"line":665},[12398,12402,12406],{"type":29,"tag":127,"props":12399,"children":12400},{"style":680},[12401],{"type":56,"value":1280},{"type":29,"tag":127,"props":12403,"children":12404},{"style":686},[12405],{"type":56,"value":715},{"type":29,"tag":127,"props":12407,"children":12408},{"style":718},[12409],{"type":56,"value":1289},{"type":29,"tag":127,"props":12411,"children":12412},{"class":675,"line":666},[12413,12417,12421],{"type":29,"tag":127,"props":12414,"children":12415},{"style":680},[12416],{"type":56,"value":1313},{"type":29,"tag":127,"props":12418,"children":12419},{"style":686},[12420],{"type":56,"value":715},{"type":29,"tag":127,"props":12422,"children":12423},{"style":718},[12424],{"type":56,"value":1322},{"type":29,"tag":127,"props":12426,"children":12427},{"class":675,"line":1325},[12428,12432],{"type":29,"tag":127,"props":12429,"children":12430},{"style":680},[12431],{"type":56,"value":1525},{"type":29,"tag":127,"props":12433,"children":12434},{"style":686},[12435],{"type":56,"value":689},{"type":29,"tag":127,"props":12437,"children":12438},{"class":675,"line":1338},[12439,12443],{"type":29,"tag":127,"props":12440,"children":12441},{"style":686},[12442],{"type":56,"value":744},{"type":29,"tag":127,"props":12444,"children":12445},{"style":718},[12446],{"type":56,"value":1542},{"type":29,"tag":127,"props":12448,"children":12449},{"class":675,"line":118},[12450,12454],{"type":29,"tag":127,"props":12451,"children":12452},{"style":686},[12453],{"type":56,"value":744},{"type":29,"tag":127,"props":12455,"children":12456},{"style":718},[12457],{"type":56,"value":12458},"letsencrypt:/letsencrypt\n",{"type":29,"tag":127,"props":12460,"children":12461},{"class":675,"line":1363},[12462,12466],{"type":29,"tag":127,"props":12463,"children":12464},{"style":680},[12465],{"type":56,"value":1331},{"type":29,"tag":127,"props":12467,"children":12468},{"style":686},[12469],{"type":56,"value":689},{"type":29,"tag":127,"props":12471,"children":12472},{"class":675,"line":1376},[12473,12477],{"type":29,"tag":127,"props":12474,"children":12475},{"style":686},[12476],{"type":56,"value":744},{"type":29,"tag":127,"props":12478,"children":12479},{"style":718},[12480],{"type":56,"value":12481},"--log.level=INFO\n",{"type":29,"tag":127,"props":12483,"children":12484},{"class":675,"line":1389},[12485],{"type":29,"tag":127,"props":12486,"children":12487},{"emptyLinePlaceholder":500},[12488],{"type":56,"value":1395},{"type":29,"tag":127,"props":12490,"children":12491},{"class":675,"line":1398},[12492,12496],{"type":29,"tag":127,"props":12493,"children":12494},{"style":686},[12495],{"type":56,"value":744},{"type":29,"tag":127,"props":12497,"children":12498},{"style":718},[12499],{"type":56,"value":1408},{"type":29,"tag":127,"props":12501,"children":12502},{"class":675,"line":1411},[12503,12507],{"type":29,"tag":127,"props":12504,"children":12505},{"style":686},[12506],{"type":56,"value":744},{"type":29,"tag":127,"props":12508,"children":12509},{"style":718},[12510],{"type":56,"value":1443},{"type":29,"tag":127,"props":12512,"children":12513},{"class":675,"line":1424},[12514,12518],{"type":29,"tag":127,"props":12515,"children":12516},{"style":686},[12517],{"type":56,"value":744},{"type":29,"tag":127,"props":12519,"children":12520},{"style":718},[12521],{"type":56,"value":1456},{"type":29,"tag":127,"props":12523,"children":12524},{"class":675,"line":1433},[12525],{"type":29,"tag":127,"props":12526,"children":12527},{"emptyLinePlaceholder":500},[12528],{"type":56,"value":1395},{"type":29,"tag":127,"props":12530,"children":12531},{"class":675,"line":1446},[12532,12536],{"type":29,"tag":127,"props":12533,"children":12534},{"style":686},[12535],{"type":56,"value":744},{"type":29,"tag":127,"props":12537,"children":12538},{"style":718},[12539],{"type":56,"value":1421},{"type":29,"tag":127,"props":12541,"children":12542},{"class":675,"line":1459},[12543,12547],{"type":29,"tag":127,"props":12544,"children":12545},{"style":686},[12546],{"type":56,"value":744},{"type":29,"tag":127,"props":12548,"children":12549},{"style":718},[12550],{"type":56,"value":1469},{"type":29,"tag":127,"props":12552,"children":12553},{"class":675,"line":1472},[12554],{"type":29,"tag":127,"props":12555,"children":12556},{"emptyLinePlaceholder":500},[12557],{"type":56,"value":1395},{"type":29,"tag":127,"props":12559,"children":12560},{"class":675,"line":1480},[12561,12565],{"type":29,"tag":127,"props":12562,"children":12563},{"style":686},[12564],{"type":56,"value":744},{"type":29,"tag":127,"props":12566,"children":12567},{"style":718},[12568],{"type":56,"value":12569},"--providers.docker=true\n",{"type":29,"tag":127,"props":12571,"children":12572},{"class":675,"line":1493},[12573,12577],{"type":29,"tag":127,"props":12574,"children":12575},{"style":686},[12576],{"type":56,"value":744},{"type":29,"tag":127,"props":12578,"children":12579},{"style":718},[12580],{"type":56,"value":12581},"--providers.docker.exposedByDefault=false\n",{"type":29,"tag":127,"props":12583,"children":12584},{"class":675,"line":1506},[12585],{"type":29,"tag":127,"props":12586,"children":12587},{"emptyLinePlaceholder":500},[12588],{"type":56,"value":1395},{"type":29,"tag":127,"props":12590,"children":12591},{"class":675,"line":1519},[12592,12596],{"type":29,"tag":127,"props":12593,"children":12594},{"style":686},[12595],{"type":56,"value":744},{"type":29,"tag":127,"props":12597,"children":12598},{"style":718},[12599],{"type":56,"value":12600},"--certificatesresolvers.letsencrypt.acme.email=\u003Cinfo@example.com>\n",{"type":29,"tag":127,"props":12602,"children":12603},{"class":675,"line":1532},[12604,12608],{"type":29,"tag":127,"props":12605,"children":12606},{"style":686},[12607],{"type":56,"value":744},{"type":29,"tag":127,"props":12609,"children":12610},{"style":718},[12611],{"type":56,"value":1373},{"type":29,"tag":127,"props":12613,"children":12614},{"class":675,"line":1545},[12615,12619],{"type":29,"tag":127,"props":12616,"children":12617},{"style":686},[12618],{"type":56,"value":744},{"type":29,"tag":127,"props":12620,"children":12621},{"style":718},[12622],{"type":56,"value":1348},{"type":29,"tag":127,"props":12624,"children":12625},{"class":675,"line":2398},[12626,12630],{"type":29,"tag":127,"props":12627,"children":12628},{"style":686},[12629],{"type":56,"value":744},{"type":29,"tag":127,"props":12631,"children":12632},{"style":718},[12633],{"type":56,"value":1386},{"type":29,"tag":48,"props":12635,"children":12636},{},[12637],{"type":56,"value":12638},"This setup will:",{"type":29,"tag":808,"props":12640,"children":12641},{},[12642,12651,12660,12665,12682,12691],{"type":29,"tag":812,"props":12643,"children":12644},{},[12645],{"type":29,"tag":643,"props":12646,"children":12648},{"href":12647},"https://doc.traefik.io/traefik/reference/install-configuration/providers/docker/",[12649],{"type":56,"value":12650},"enable the docker provider",{"type":29,"tag":812,"props":12652,"children":12653},{},[12654],{"type":29,"tag":643,"props":12655,"children":12657},{"href":12656},"https://doc.traefik.io/traefik/providers/docker/#exposedbydefault",[12658],{"type":56,"value":12659},"disable the container discovery",{"type":29,"tag":812,"props":12661,"children":12662},{},[12663],{"type":56,"value":12664},"redirect all HTTP traffic to HTTPS",{"type":29,"tag":812,"props":12666,"children":12667},{},[12668],{"type":29,"tag":643,"props":12669,"children":12671},{"href":12670},"https://doc.traefik.io/traefik/https/acme/#httpchallenge",[12672,12674,12680],{"type":56,"value":12673},"configure Let's Encrypt with ",{"type":29,"tag":670,"props":12675,"children":12677},{"className":12676},[],[12678],{"type":56,"value":12679},"HTTP-01",{"type":56,"value":12681}," challenge",{"type":29,"tag":812,"props":12683,"children":12684},{},[12685],{"type":29,"tag":643,"props":12686,"children":12688},{"href":12687},"https://doc.traefik.io/traefik/routing/entrypoints/#tls",[12689],{"type":56,"value":12690},"apply the TLS configuration to all routes",{"type":29,"tag":812,"props":12692,"children":12693},{},[12694,12700],{"type":29,"tag":643,"props":12695,"children":12697},{"href":12696},"https://docs.docker.com/engine/network/tutorials/host/",[12698],{"type":56,"value":12699},"start the Traefik container bound directly to host's network",{"type":56,"value":12701},", so no addition configuration is required for traefik",{"type":29,"tag":12285,"props":12703,"children":12705},{"id":12704},"the-gitlab-deployment",[12706],{"type":56,"value":12707},"The GitLab deployment",{"type":29,"tag":48,"props":12709,"children":12710},{},[12711,12712,12721],{"type":56,"value":12295},{"type":29,"tag":52,"props":12713,"children":12714},{},[12715],{"type":29,"tag":670,"props":12716,"children":12718},{"className":12717},[],[12719],{"type":56,"value":12720},"\u003Cgitlab.example.com>",{"type":56,"value":12722}," with your own domain.",{"type":29,"tag":48,"props":12724,"children":12725},{},[12726,12728,12734,12736,12745],{"type":56,"value":12727},"Please take a look in the ",{"type":29,"tag":643,"props":12729,"children":12731},{"href":12730},"https://docs.gitlab.com/install/docker/installation/#create-a-directory-for-the-volumes",[12732],{"type":56,"value":12733},"official dokumentation",{"type":56,"value":12735}," about ",{"type":29,"tag":52,"props":12737,"children":12738},{},[12739],{"type":29,"tag":670,"props":12740,"children":12742},{"className":12741},[],[12743],{"type":56,"value":12744},"GITLAB_HOME",{"type":56,"value":12746}," directory",{"type":29,"tag":657,"props":12748,"children":12751},{"className":667,"code":12749,"filename":11632,"highlights":12750,"language":508,"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",[662,663,664,665,666,1411,1433,1446,1459,1472,1480,1493,1519,1545],[12752],{"type":29,"tag":670,"props":12753,"children":12754},{"__ignoreMap":7},[12755,12766,12777,12793,12808,12820,12832,12845,12858,12871,12886,12902,12913,12928,12935,12943,12951,12960,12967,12976,12985,12994,13003,13012,13020,13027,13036,13047,13060,13071,13082,13093,13104],{"type":29,"tag":127,"props":12756,"children":12757},{"class":675,"line":676},[12758,12762],{"type":29,"tag":127,"props":12759,"children":12760},{"style":680},[12761],{"type":56,"value":683},{"type":29,"tag":127,"props":12763,"children":12764},{"style":686},[12765],{"type":56,"value":689},{"type":29,"tag":127,"props":12767,"children":12768},{"class":675,"line":342},[12769,12773],{"type":29,"tag":127,"props":12770,"children":12771},{"style":680},[12772],{"type":56,"value":11655},{"type":29,"tag":127,"props":12774,"children":12775},{"style":686},[12776],{"type":56,"value":689},{"type":29,"tag":127,"props":12778,"children":12779},{"class":675,"line":704},[12780,12784,12788],{"type":29,"tag":127,"props":12781,"children":12782},{"style":680},[12783],{"type":56,"value":710},{"type":29,"tag":127,"props":12785,"children":12786},{"style":686},[12787],{"type":56,"value":715},{"type":29,"tag":127,"props":12789,"children":12790},{"style":718},[12791],{"type":56,"value":12792},"gitlab/gitlab-ce:\u003Cversion>-ce.0\n",{"type":29,"tag":127,"props":12794,"children":12795},{"class":675,"line":724},[12796,12800,12804],{"type":29,"tag":127,"props":12797,"children":12798},{"style":680},[12799],{"type":56,"value":1263},{"type":29,"tag":127,"props":12801,"children":12802},{"style":686},[12803],{"type":56,"value":715},{"type":29,"tag":127,"props":12805,"children":12806},{"style":718},[12807],{"type":56,"value":11691},{"type":29,"tag":127,"props":12809,"children":12811},{"class":12810,"line":662},[675,738],[12812,12816],{"type":29,"tag":127,"props":12813,"children":12814},{"style":680},[12815],{"type":56,"value":730},{"type":29,"tag":127,"props":12817,"children":12818},{"style":686},[12819],{"type":56,"value":689},{"type":29,"tag":127,"props":12821,"children":12823},{"class":12822,"line":663},[675,738],[12824,12828],{"type":29,"tag":127,"props":12825,"children":12826},{"style":686},[12827],{"type":56,"value":744},{"type":29,"tag":127,"props":12829,"children":12830},{"style":718},[12831],{"type":56,"value":749},{"type":29,"tag":127,"props":12833,"children":12835},{"class":12834,"line":664},[675,738],[12836,12840],{"type":29,"tag":127,"props":12837,"children":12838},{"style":686},[12839],{"type":56,"value":744},{"type":29,"tag":127,"props":12841,"children":12842},{"style":718},[12843],{"type":56,"value":12844},"\"traefik.http.routers.gitlab.rule=Host(`\u003Cgitlab.example.com>`)\"\n",{"type":29,"tag":127,"props":12846,"children":12848},{"class":12847,"line":665},[675,738],[12849,12853],{"type":29,"tag":127,"props":12850,"children":12851},{"style":686},[12852],{"type":56,"value":744},{"type":29,"tag":127,"props":12854,"children":12855},{"style":718},[12856],{"type":56,"value":12857},"\"traefik.http.routers.gitlab.service=gitlab\"\n",{"type":29,"tag":127,"props":12859,"children":12861},{"class":12860,"line":666},[675,738],[12862,12866],{"type":29,"tag":127,"props":12863,"children":12864},{"style":686},[12865],{"type":56,"value":744},{"type":29,"tag":127,"props":12867,"children":12868},{"style":718},[12869],{"type":56,"value":12870},"\"traefik.http.services.gitlab.loadbalancer.server.port=80\"\n",{"type":29,"tag":127,"props":12872,"children":12873},{"class":675,"line":1325},[12874,12878,12882],{"type":29,"tag":127,"props":12875,"children":12876},{"style":680},[12877],{"type":56,"value":1280},{"type":29,"tag":127,"props":12879,"children":12880},{"style":686},[12881],{"type":56,"value":715},{"type":29,"tag":127,"props":12883,"children":12884},{"style":718},[12885],{"type":56,"value":1289},{"type":29,"tag":127,"props":12887,"children":12888},{"class":675,"line":1338},[12889,12893,12897],{"type":29,"tag":127,"props":12890,"children":12891},{"style":680},[12892],{"type":56,"value":11714},{"type":29,"tag":127,"props":12894,"children":12895},{"style":686},[12896],{"type":56,"value":715},{"type":29,"tag":127,"props":12898,"children":12899},{"style":718},[12900],{"type":56,"value":12901},"'gitlab.example.com'\n",{"type":29,"tag":127,"props":12903,"children":12904},{"class":675,"line":118},[12905,12909],{"type":29,"tag":127,"props":12906,"children":12907},{"style":680},[12908],{"type":56,"value":10034},{"type":29,"tag":127,"props":12910,"children":12911},{"style":686},[12912],{"type":56,"value":689},{"type":29,"tag":127,"props":12914,"children":12915},{"class":675,"line":1363},[12916,12920,12924],{"type":29,"tag":127,"props":12917,"children":12918},{"style":680},[12919],{"type":56,"value":11742},{"type":29,"tag":127,"props":12921,"children":12922},{"style":686},[12923],{"type":56,"value":715},{"type":29,"tag":127,"props":12925,"children":12926},{"style":4927},[12927],{"type":56,"value":11751},{"type":29,"tag":127,"props":12929,"children":12930},{"class":675,"line":1376},[12931],{"type":29,"tag":127,"props":12932,"children":12933},{"style":718},[12934],{"type":56,"value":11759},{"type":29,"tag":127,"props":12936,"children":12937},{"class":675,"line":1389},[12938],{"type":29,"tag":127,"props":12939,"children":12940},{"style":718},[12941],{"type":56,"value":12942},"        external_url '\u003Chttps://gitlab.example.com>'\n",{"type":29,"tag":127,"props":12944,"children":12945},{"class":675,"line":1398},[12946],{"type":29,"tag":127,"props":12947,"children":12948},{"style":718},[12949],{"type":56,"value":12950},"        \n",{"type":29,"tag":127,"props":12952,"children":12954},{"class":12953,"line":1411},[675,738],[12955],{"type":29,"tag":127,"props":12956,"children":12957},{"style":718},[12958],{"type":56,"value":12959},"        letsencrypt['enable'] = false\n",{"type":29,"tag":127,"props":12961,"children":12962},{"class":675,"line":1424},[12963],{"type":29,"tag":127,"props":12964,"children":12965},{"style":718},[12966],{"type":56,"value":12950},{"type":29,"tag":127,"props":12968,"children":12970},{"class":12969,"line":1433},[675,738],[12971],{"type":29,"tag":127,"props":12972,"children":12973},{"style":718},[12974],{"type":56,"value":12975},"        nginx['listen_port'] = 80\n",{"type":29,"tag":127,"props":12977,"children":12979},{"class":12978,"line":1446},[675,738],[12980],{"type":29,"tag":127,"props":12981,"children":12982},{"style":718},[12983],{"type":56,"value":12984},"        nginx['listen_https'] = false\n",{"type":29,"tag":127,"props":12986,"children":12988},{"class":12987,"line":1459},[675,738],[12989],{"type":29,"tag":127,"props":12990,"children":12991},{"style":718},[12992],{"type":56,"value":12993},"        nginx['proxy_set_headers'] = {\n",{"type":29,"tag":127,"props":12995,"children":12997},{"class":12996,"line":1472},[675,738],[12998],{"type":29,"tag":127,"props":12999,"children":13000},{"style":718},[13001],{"type":56,"value":13002},"          \"X-Forwarded-Proto\" => \"https\",\n",{"type":29,"tag":127,"props":13004,"children":13006},{"class":13005,"line":1480},[675,738],[13007],{"type":29,"tag":127,"props":13008,"children":13009},{"style":718},[13010],{"type":56,"value":13011},"          \"X-Forwarded-Ssl\" => \"on\"\n",{"type":29,"tag":127,"props":13013,"children":13015},{"class":13014,"line":1493},[675,738],[13016],{"type":29,"tag":127,"props":13017,"children":13018},{"style":718},[13019],{"type":56,"value":3527},{"type":29,"tag":127,"props":13021,"children":13022},{"class":675,"line":1506},[13023],{"type":29,"tag":127,"props":13024,"children":13025},{"style":718},[13026],{"type":56,"value":12950},{"type":29,"tag":127,"props":13028,"children":13030},{"class":13029,"line":1519},[675,738],[13031],{"type":29,"tag":127,"props":13032,"children":13033},{"style":718},[13034],{"type":56,"value":13035},"        gitlab_rails['gitlab_shell_ssh_port'] = 2424\n",{"type":29,"tag":127,"props":13037,"children":13038},{"class":675,"line":1532},[13039,13043],{"type":29,"tag":127,"props":13040,"children":13041},{"style":680},[13042],{"type":56,"value":11775},{"type":29,"tag":127,"props":13044,"children":13045},{"style":686},[13046],{"type":56,"value":689},{"type":29,"tag":127,"props":13048,"children":13050},{"class":13049,"line":1545},[675,738],[13051,13055],{"type":29,"tag":127,"props":13052,"children":13053},{"style":686},[13054],{"type":56,"value":744},{"type":29,"tag":127,"props":13056,"children":13057},{"style":718},[13058],{"type":56,"value":13059},"'2424:22'\n",{"type":29,"tag":127,"props":13061,"children":13062},{"class":675,"line":2398},[13063,13067],{"type":29,"tag":127,"props":13064,"children":13065},{"style":680},[13066],{"type":56,"value":1525},{"type":29,"tag":127,"props":13068,"children":13069},{"style":686},[13070],{"type":56,"value":689},{"type":29,"tag":127,"props":13072,"children":13073},{"class":675,"line":2406},[13074,13078],{"type":29,"tag":127,"props":13075,"children":13076},{"style":686},[13077],{"type":56,"value":744},{"type":29,"tag":127,"props":13079,"children":13080},{"style":718},[13081],{"type":56,"value":11838},{"type":29,"tag":127,"props":13083,"children":13084},{"class":675,"line":2426},[13085,13089],{"type":29,"tag":127,"props":13086,"children":13087},{"style":686},[13088],{"type":56,"value":744},{"type":29,"tag":127,"props":13090,"children":13091},{"style":718},[13092],{"type":56,"value":11850},{"type":29,"tag":127,"props":13094,"children":13095},{"class":675,"line":2447},[13096,13100],{"type":29,"tag":127,"props":13097,"children":13098},{"style":686},[13099],{"type":56,"value":744},{"type":29,"tag":127,"props":13101,"children":13102},{"style":718},[13103],{"type":56,"value":11862},{"type":29,"tag":127,"props":13105,"children":13106},{"class":675,"line":2459},[13107,13111,13115],{"type":29,"tag":127,"props":13108,"children":13109},{"style":680},[13110],{"type":56,"value":11870},{"type":29,"tag":127,"props":13112,"children":13113},{"style":686},[13114],{"type":56,"value":715},{"type":29,"tag":127,"props":13116,"children":13117},{"style":718},[13118],{"type":56,"value":11879},{"type":29,"tag":48,"props":13120,"children":13121},{},[13122],{"type":56,"value":12638},{"type":29,"tag":808,"props":13124,"children":13125},{},[13126,13131,13136,13141,13146],{"type":29,"tag":812,"props":13127,"children":13128},{},[13129],{"type":56,"value":13130},"disable the Let's Encrypt",{"type":29,"tag":812,"props":13132,"children":13133},{},[13134],{"type":56,"value":13135},"disable listening on https and listen on port 80",{"type":29,"tag":812,"props":13137,"children":13138},{},[13139],{"type":56,"value":13140},"set the required proxy headers",{"type":29,"tag":812,"props":13142,"children":13143},{},[13144],{"type":56,"value":13145},"change the ssh port to 2424",{"type":29,"tag":812,"props":13147,"children":13148},{},[13149,13151,13157],{"type":56,"value":13150},"instruct Traefik to route all traffic for ",{"type":29,"tag":670,"props":13152,"children":13154},{"className":13153},[],[13155],{"type":56,"value":13156},"gitlab.example.com",{"type":56,"value":13158}," to port 80 of the container",{"type":29,"tag":1663,"props":13160,"children":13161},{},[],{"type":29,"tag":48,"props":13163,"children":13164},{},[13165],{"type":29,"tag":127,"props":13166,"children":13168},{"className":13167},[5242],[13169],{"type":56,"value":7292},{"type":29,"tag":1663,"props":13171,"children":13172},{},[],{"type":29,"tag":1184,"props":13174,"children":13175},{},[],{"type":29,"tag":122,"props":13177,"children":13179},{"id":13178},"gitlab-container-registry",[13180],{"type":56,"value":13181},"GitLab Container registry",{"type":29,"tag":48,"props":13183,"children":13184},{},[13185,13187],{"type":56,"value":13186},"When you got so far, you probably also want to set up the ",{"type":29,"tag":643,"props":13188,"children":13190},{"href":13189},"https://docs.gitlab.com/administration/packages/container_registry/",[13191],{"type":56,"value":13192},"container registry",{"type":29,"tag":12285,"props":13194,"children":13196},{"id":13195},"configure-container-registry-under-its-own-domain",[13197],{"type":29,"tag":643,"props":13198,"children":13200},{"href":13199},"https://docs.gitlab.com/administration/packages/container_registry/#configure-container-registry-under-its-own-domain",[13201],{"type":56,"value":13202},"Configure container registry under its own domain",{"type":29,"tag":48,"props":13204,"children":13205},{},[13206,13208,13214],{"type":56,"value":13207},"This setup is easy. We just need to set the ",{"type":29,"tag":670,"props":13209,"children":13211},{"className":13210},[],[13212],{"type":56,"value":13213},"registry_external_url",{"type":56,"value":13215}," and instruct Traefik where to route the requests",{"type":29,"tag":1663,"props":13217,"children":13218},{},[],{"type":29,"tag":13220,"props":13221,"children":13223},"h5",{"id":13222},"update-the-gitlab-config",[13224],{"type":56,"value":13225},"Update the GitLab config",{"type":29,"tag":657,"props":13227,"children":13230},{"className":667,"code":13228,"filename":11632,"highlights":13229,"language":508,"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",[1325,1338,2406,2426],[13231],{"type":29,"tag":670,"props":13232,"children":13233},{"__ignoreMap":7},[13234,13245,13256,13271,13286,13297,13308,13319,13330,13341,13354,13367,13382,13397,13408,13423,13430,13437,13444,13451,13458,13465,13472,13479,13486,13493,13500,13507,13514,13521,13530,13539,13550,13561,13572,13583,13594,13605],{"type":29,"tag":127,"props":13235,"children":13236},{"class":675,"line":676},[13237,13241],{"type":29,"tag":127,"props":13238,"children":13239},{"style":680},[13240],{"type":56,"value":683},{"type":29,"tag":127,"props":13242,"children":13243},{"style":686},[13244],{"type":56,"value":689},{"type":29,"tag":127,"props":13246,"children":13247},{"class":675,"line":342},[13248,13252],{"type":29,"tag":127,"props":13249,"children":13250},{"style":680},[13251],{"type":56,"value":11655},{"type":29,"tag":127,"props":13253,"children":13254},{"style":686},[13255],{"type":56,"value":689},{"type":29,"tag":127,"props":13257,"children":13258},{"class":675,"line":704},[13259,13263,13267],{"type":29,"tag":127,"props":13260,"children":13261},{"style":680},[13262],{"type":56,"value":710},{"type":29,"tag":127,"props":13264,"children":13265},{"style":686},[13266],{"type":56,"value":715},{"type":29,"tag":127,"props":13268,"children":13269},{"style":718},[13270],{"type":56,"value":12792},{"type":29,"tag":127,"props":13272,"children":13273},{"class":675,"line":724},[13274,13278,13282],{"type":29,"tag":127,"props":13275,"children":13276},{"style":680},[13277],{"type":56,"value":1263},{"type":29,"tag":127,"props":13279,"children":13280},{"style":686},[13281],{"type":56,"value":715},{"type":29,"tag":127,"props":13283,"children":13284},{"style":718},[13285],{"type":56,"value":11691},{"type":29,"tag":127,"props":13287,"children":13288},{"class":675,"line":662},[13289,13293],{"type":29,"tag":127,"props":13290,"children":13291},{"style":680},[13292],{"type":56,"value":730},{"type":29,"tag":127,"props":13294,"children":13295},{"style":686},[13296],{"type":56,"value":689},{"type":29,"tag":127,"props":13298,"children":13299},{"class":675,"line":663},[13300,13304],{"type":29,"tag":127,"props":13301,"children":13302},{"style":686},[13303],{"type":56,"value":744},{"type":29,"tag":127,"props":13305,"children":13306},{"style":718},[13307],{"type":56,"value":749},{"type":29,"tag":127,"props":13309,"children":13310},{"class":675,"line":664},[13311,13315],{"type":29,"tag":127,"props":13312,"children":13313},{"style":686},[13314],{"type":56,"value":744},{"type":29,"tag":127,"props":13316,"children":13317},{"style":718},[13318],{"type":56,"value":12844},{"type":29,"tag":127,"props":13320,"children":13321},{"class":675,"line":665},[13322,13326],{"type":29,"tag":127,"props":13323,"children":13324},{"style":686},[13325],{"type":56,"value":744},{"type":29,"tag":127,"props":13327,"children":13328},{"style":718},[13329],{"type":56,"value":12857},{"type":29,"tag":127,"props":13331,"children":13332},{"class":675,"line":666},[13333,13337],{"type":29,"tag":127,"props":13334,"children":13335},{"style":686},[13336],{"type":56,"value":744},{"type":29,"tag":127,"props":13338,"children":13339},{"style":718},[13340],{"type":56,"value":12870},{"type":29,"tag":127,"props":13342,"children":13344},{"class":13343,"line":1325},[675,738],[13345,13349],{"type":29,"tag":127,"props":13346,"children":13347},{"style":686},[13348],{"type":56,"value":744},{"type":29,"tag":127,"props":13350,"children":13351},{"style":718},[13352],{"type":56,"value":13353},"\"traefik.http.routers.container-registry.rule=Host(`registry.gitlab.example.com`)\"\n",{"type":29,"tag":127,"props":13355,"children":13357},{"class":13356,"line":1338},[675,738],[13358,13362],{"type":29,"tag":127,"props":13359,"children":13360},{"style":686},[13361],{"type":56,"value":744},{"type":29,"tag":127,"props":13363,"children":13364},{"style":718},[13365],{"type":56,"value":13366},"\"traefik.http.services.container-registry.loadbalancer.server.port=5000\"\n",{"type":29,"tag":127,"props":13368,"children":13369},{"class":675,"line":118},[13370,13374,13378],{"type":29,"tag":127,"props":13371,"children":13372},{"style":680},[13373],{"type":56,"value":1280},{"type":29,"tag":127,"props":13375,"children":13376},{"style":686},[13377],{"type":56,"value":715},{"type":29,"tag":127,"props":13379,"children":13380},{"style":718},[13381],{"type":56,"value":1289},{"type":29,"tag":127,"props":13383,"children":13384},{"class":675,"line":1363},[13385,13389,13393],{"type":29,"tag":127,"props":13386,"children":13387},{"style":680},[13388],{"type":56,"value":11714},{"type":29,"tag":127,"props":13390,"children":13391},{"style":686},[13392],{"type":56,"value":715},{"type":29,"tag":127,"props":13394,"children":13395},{"style":718},[13396],{"type":56,"value":12901},{"type":29,"tag":127,"props":13398,"children":13399},{"class":675,"line":1376},[13400,13404],{"type":29,"tag":127,"props":13401,"children":13402},{"style":680},[13403],{"type":56,"value":10034},{"type":29,"tag":127,"props":13405,"children":13406},{"style":686},[13407],{"type":56,"value":689},{"type":29,"tag":127,"props":13409,"children":13410},{"class":675,"line":1389},[13411,13415,13419],{"type":29,"tag":127,"props":13412,"children":13413},{"style":680},[13414],{"type":56,"value":11742},{"type":29,"tag":127,"props":13416,"children":13417},{"style":686},[13418],{"type":56,"value":715},{"type":29,"tag":127,"props":13420,"children":13421},{"style":4927},[13422],{"type":56,"value":11751},{"type":29,"tag":127,"props":13424,"children":13425},{"class":675,"line":1398},[13426],{"type":29,"tag":127,"props":13427,"children":13428},{"style":718},[13429],{"type":56,"value":11759},{"type":29,"tag":127,"props":13431,"children":13432},{"class":675,"line":1411},[13433],{"type":29,"tag":127,"props":13434,"children":13435},{"style":718},[13436],{"type":56,"value":12942},{"type":29,"tag":127,"props":13438,"children":13439},{"class":675,"line":1424},[13440],{"type":29,"tag":127,"props":13441,"children":13442},{"emptyLinePlaceholder":500},[13443],{"type":56,"value":1395},{"type":29,"tag":127,"props":13445,"children":13446},{"class":675,"line":1433},[13447],{"type":29,"tag":127,"props":13448,"children":13449},{"style":718},[13450],{"type":56,"value":12959},{"type":29,"tag":127,"props":13452,"children":13453},{"class":675,"line":1446},[13454],{"type":29,"tag":127,"props":13455,"children":13456},{"emptyLinePlaceholder":500},[13457],{"type":56,"value":1395},{"type":29,"tag":127,"props":13459,"children":13460},{"class":675,"line":1459},[13461],{"type":29,"tag":127,"props":13462,"children":13463},{"style":718},[13464],{"type":56,"value":12975},{"type":29,"tag":127,"props":13466,"children":13467},{"class":675,"line":1472},[13468],{"type":29,"tag":127,"props":13469,"children":13470},{"style":718},[13471],{"type":56,"value":12984},{"type":29,"tag":127,"props":13473,"children":13474},{"class":675,"line":1480},[13475],{"type":29,"tag":127,"props":13476,"children":13477},{"style":718},[13478],{"type":56,"value":12993},{"type":29,"tag":127,"props":13480,"children":13481},{"class":675,"line":1493},[13482],{"type":29,"tag":127,"props":13483,"children":13484},{"style":718},[13485],{"type":56,"value":13002},{"type":29,"tag":127,"props":13487,"children":13488},{"class":675,"line":1506},[13489],{"type":29,"tag":127,"props":13490,"children":13491},{"style":718},[13492],{"type":56,"value":13011},{"type":29,"tag":127,"props":13494,"children":13495},{"class":675,"line":1519},[13496],{"type":29,"tag":127,"props":13497,"children":13498},{"style":718},[13499],{"type":56,"value":3527},{"type":29,"tag":127,"props":13501,"children":13502},{"class":675,"line":1532},[13503],{"type":29,"tag":127,"props":13504,"children":13505},{"emptyLinePlaceholder":500},[13506],{"type":56,"value":1395},{"type":29,"tag":127,"props":13508,"children":13509},{"class":675,"line":1545},[13510],{"type":29,"tag":127,"props":13511,"children":13512},{"style":718},[13513],{"type":56,"value":13035},{"type":29,"tag":127,"props":13515,"children":13516},{"class":675,"line":2398},[13517],{"type":29,"tag":127,"props":13518,"children":13519},{"emptyLinePlaceholder":500},[13520],{"type":56,"value":1395},{"type":29,"tag":127,"props":13522,"children":13524},{"class":13523,"line":2406},[675,738],[13525],{"type":29,"tag":127,"props":13526,"children":13527},{"style":718},[13528],{"type":56,"value":13529},"        registry_external_url '\u003Chttps://registry.gitlab.example.com>'\n",{"type":29,"tag":127,"props":13531,"children":13533},{"class":13532,"line":2426},[675,738],[13534],{"type":29,"tag":127,"props":13535,"children":13536},{"style":718},[13537],{"type":56,"value":13538},"        registry_nginx['enable'] = false\n",{"type":29,"tag":127,"props":13540,"children":13541},{"class":675,"line":2447},[13542,13546],{"type":29,"tag":127,"props":13543,"children":13544},{"style":680},[13545],{"type":56,"value":11775},{"type":29,"tag":127,"props":13547,"children":13548},{"style":686},[13549],{"type":56,"value":689},{"type":29,"tag":127,"props":13551,"children":13552},{"class":675,"line":2459},[13553,13557],{"type":29,"tag":127,"props":13554,"children":13555},{"style":686},[13556],{"type":56,"value":744},{"type":29,"tag":127,"props":13558,"children":13559},{"style":718},[13560],{"type":56,"value":13059},{"type":29,"tag":127,"props":13562,"children":13563},{"class":675,"line":2475},[13564,13568],{"type":29,"tag":127,"props":13565,"children":13566},{"style":680},[13567],{"type":56,"value":1525},{"type":29,"tag":127,"props":13569,"children":13570},{"style":686},[13571],{"type":56,"value":689},{"type":29,"tag":127,"props":13573,"children":13574},{"class":675,"line":2483},[13575,13579],{"type":29,"tag":127,"props":13576,"children":13577},{"style":686},[13578],{"type":56,"value":744},{"type":29,"tag":127,"props":13580,"children":13581},{"style":718},[13582],{"type":56,"value":11838},{"type":29,"tag":127,"props":13584,"children":13585},{"class":675,"line":1957},[13586,13590],{"type":29,"tag":127,"props":13587,"children":13588},{"style":686},[13589],{"type":56,"value":744},{"type":29,"tag":127,"props":13591,"children":13592},{"style":718},[13593],{"type":56,"value":11850},{"type":29,"tag":127,"props":13595,"children":13596},{"class":675,"line":1958},[13597,13601],{"type":29,"tag":127,"props":13598,"children":13599},{"style":686},[13600],{"type":56,"value":744},{"type":29,"tag":127,"props":13602,"children":13603},{"style":718},[13604],{"type":56,"value":11862},{"type":29,"tag":127,"props":13606,"children":13607},{"class":675,"line":1959},[13608,13612,13616],{"type":29,"tag":127,"props":13609,"children":13610},{"style":680},[13611],{"type":56,"value":11870},{"type":29,"tag":127,"props":13613,"children":13614},{"style":686},[13615],{"type":56,"value":715},{"type":29,"tag":127,"props":13617,"children":13618},{"style":718},[13619],{"type":56,"value":11879},{"type":29,"tag":48,"props":13621,"children":13622},{},[13623],{"type":56,"value":12638},{"type":29,"tag":808,"props":13625,"children":13626},{},[13627,13632,13637],{"type":29,"tag":812,"props":13628,"children":13629},{},[13630],{"type":56,"value":13631},"set the registry external url",{"type":29,"tag":812,"props":13633,"children":13634},{},[13635],{"type":56,"value":13636},"disable the nginx for the registry",{"type":29,"tag":812,"props":13638,"children":13639},{},[13640,13641,13647],{"type":56,"value":13150},{"type":29,"tag":670,"props":13642,"children":13644},{"className":13643},[],[13645],{"type":56,"value":13646},"registry.gitlab.example.com",{"type":56,"value":13648}," to port 5000 of the container",{"type":29,"tag":1663,"props":13650,"children":13651},{},[],{"type":29,"tag":1184,"props":13653,"children":13654},{},[],{"type":29,"tag":12285,"props":13656,"children":13658},{"id":13657},"configure-container-registry-under-an-existing-gitlab-domain",[13659],{"type":29,"tag":643,"props":13660,"children":13662},{"href":13661},"https://docs.gitlab.com/administration/packages/container_registry/#configure-container-registry-under-an-existing-gitlab-domain",[13663],{"type":56,"value":13664},"Configure container registry under an existing GitLab domain",{"type":29,"tag":13220,"props":13666,"children":13668},{"id":13667},"update-the-traefik-config",[13669],{"type":56,"value":13670},"Update the Traefik config",{"type":29,"tag":657,"props":13672,"children":13675},{"className":667,"code":13673,"filename":1195,"highlights":13674,"language":508,"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",[1480,1493],[13676],{"type":29,"tag":670,"props":13677,"children":13678},{"__ignoreMap":7},[13679,13690,13701,13708,13719,13730,13745,13760,13775,13790,13801,13812,13823,13834,13845,13852,13863,13874,13885,13892,13903,13914,13921,13934,13947,13954,13965,13976,13983,13994,14005,14016],{"type":29,"tag":127,"props":13680,"children":13681},{"class":675,"line":676},[13682,13686],{"type":29,"tag":127,"props":13683,"children":13684},{"style":680},[13685],{"type":56,"value":1208},{"type":29,"tag":127,"props":13687,"children":13688},{"style":686},[13689],{"type":56,"value":689},{"type":29,"tag":127,"props":13691,"children":13692},{"class":675,"line":342},[13693,13697],{"type":29,"tag":127,"props":13694,"children":13695},{"style":680},[13696],{"type":56,"value":1220},{"type":29,"tag":127,"props":13698,"children":13699},{"style":686},[13700],{"type":56,"value":689},{"type":29,"tag":127,"props":13702,"children":13703},{"class":675,"line":704},[13704],{"type":29,"tag":127,"props":13705,"children":13706},{"emptyLinePlaceholder":500},[13707],{"type":56,"value":1395},{"type":29,"tag":127,"props":13709,"children":13710},{"class":675,"line":724},[13711,13715],{"type":29,"tag":127,"props":13712,"children":13713},{"style":680},[13714],{"type":56,"value":683},{"type":29,"tag":127,"props":13716,"children":13717},{"style":686},[13718],{"type":56,"value":689},{"type":29,"tag":127,"props":13720,"children":13721},{"class":675,"line":662},[13722,13726],{"type":29,"tag":127,"props":13723,"children":13724},{"style":680},[13725],{"type":56,"value":1251},{"type":29,"tag":127,"props":13727,"children":13728},{"style":686},[13729],{"type":56,"value":689},{"type":29,"tag":127,"props":13731,"children":13732},{"class":675,"line":663},[13733,13737,13741],{"type":29,"tag":127,"props":13734,"children":13735},{"style":680},[13736],{"type":56,"value":710},{"type":29,"tag":127,"props":13738,"children":13739},{"style":686},[13740],{"type":56,"value":715},{"type":29,"tag":127,"props":13742,"children":13743},{"style":718},[13744],{"type":56,"value":1305},{"type":29,"tag":127,"props":13746,"children":13747},{"class":675,"line":664},[13748,13752,13756],{"type":29,"tag":127,"props":13749,"children":13750},{"style":680},[13751],{"type":56,"value":1263},{"type":29,"tag":127,"props":13753,"children":13754},{"style":686},[13755],{"type":56,"value":715},{"type":29,"tag":127,"props":13757,"children":13758},{"style":718},[13759],{"type":56,"value":1272},{"type":29,"tag":127,"props":13761,"children":13762},{"class":675,"line":665},[13763,13767,13771],{"type":29,"tag":127,"props":13764,"children":13765},{"style":680},[13766],{"type":56,"value":1280},{"type":29,"tag":127,"props":13768,"children":13769},{"style":686},[13770],{"type":56,"value":715},{"type":29,"tag":127,"props":13772,"children":13773},{"style":718},[13774],{"type":56,"value":1289},{"type":29,"tag":127,"props":13776,"children":13777},{"class":675,"line":666},[13778,13782,13786],{"type":29,"tag":127,"props":13779,"children":13780},{"style":680},[13781],{"type":56,"value":1313},{"type":29,"tag":127,"props":13783,"children":13784},{"style":686},[13785],{"type":56,"value":715},{"type":29,"tag":127,"props":13787,"children":13788},{"style":718},[13789],{"type":56,"value":1322},{"type":29,"tag":127,"props":13791,"children":13792},{"class":675,"line":1325},[13793,13797],{"type":29,"tag":127,"props":13794,"children":13795},{"style":680},[13796],{"type":56,"value":1525},{"type":29,"tag":127,"props":13798,"children":13799},{"style":686},[13800],{"type":56,"value":689},{"type":29,"tag":127,"props":13802,"children":13803},{"class":675,"line":1338},[13804,13808],{"type":29,"tag":127,"props":13805,"children":13806},{"style":686},[13807],{"type":56,"value":744},{"type":29,"tag":127,"props":13809,"children":13810},{"style":718},[13811],{"type":56,"value":1542},{"type":29,"tag":127,"props":13813,"children":13814},{"class":675,"line":118},[13815,13819],{"type":29,"tag":127,"props":13816,"children":13817},{"style":686},[13818],{"type":56,"value":744},{"type":29,"tag":127,"props":13820,"children":13821},{"style":718},[13822],{"type":56,"value":12458},{"type":29,"tag":127,"props":13824,"children":13825},{"class":675,"line":1363},[13826,13830],{"type":29,"tag":127,"props":13827,"children":13828},{"style":680},[13829],{"type":56,"value":1331},{"type":29,"tag":127,"props":13831,"children":13832},{"style":686},[13833],{"type":56,"value":689},{"type":29,"tag":127,"props":13835,"children":13836},{"class":675,"line":1376},[13837,13841],{"type":29,"tag":127,"props":13838,"children":13839},{"style":686},[13840],{"type":56,"value":744},{"type":29,"tag":127,"props":13842,"children":13843},{"style":718},[13844],{"type":56,"value":12481},{"type":29,"tag":127,"props":13846,"children":13847},{"class":675,"line":1389},[13848],{"type":29,"tag":127,"props":13849,"children":13850},{"emptyLinePlaceholder":500},[13851],{"type":56,"value":1395},{"type":29,"tag":127,"props":13853,"children":13854},{"class":675,"line":1398},[13855,13859],{"type":29,"tag":127,"props":13856,"children":13857},{"style":686},[13858],{"type":56,"value":744},{"type":29,"tag":127,"props":13860,"children":13861},{"style":718},[13862],{"type":56,"value":1408},{"type":29,"tag":127,"props":13864,"children":13865},{"class":675,"line":1411},[13866,13870],{"type":29,"tag":127,"props":13867,"children":13868},{"style":686},[13869],{"type":56,"value":744},{"type":29,"tag":127,"props":13871,"children":13872},{"style":718},[13873],{"type":56,"value":1443},{"type":29,"tag":127,"props":13875,"children":13876},{"class":675,"line":1424},[13877,13881],{"type":29,"tag":127,"props":13878,"children":13879},{"style":686},[13880],{"type":56,"value":744},{"type":29,"tag":127,"props":13882,"children":13883},{"style":718},[13884],{"type":56,"value":1456},{"type":29,"tag":127,"props":13886,"children":13887},{"class":675,"line":1433},[13888],{"type":29,"tag":127,"props":13889,"children":13890},{"emptyLinePlaceholder":500},[13891],{"type":56,"value":1395},{"type":29,"tag":127,"props":13893,"children":13894},{"class":675,"line":1446},[13895,13899],{"type":29,"tag":127,"props":13896,"children":13897},{"style":686},[13898],{"type":56,"value":744},{"type":29,"tag":127,"props":13900,"children":13901},{"style":718},[13902],{"type":56,"value":1421},{"type":29,"tag":127,"props":13904,"children":13905},{"class":675,"line":1459},[13906,13910],{"type":29,"tag":127,"props":13907,"children":13908},{"style":686},[13909],{"type":56,"value":744},{"type":29,"tag":127,"props":13911,"children":13912},{"style":718},[13913],{"type":56,"value":1469},{"type":29,"tag":127,"props":13915,"children":13916},{"class":675,"line":1472},[13917],{"type":29,"tag":127,"props":13918,"children":13919},{"style":686},[13920],{"type":56,"value":12950},{"type":29,"tag":127,"props":13922,"children":13924},{"class":13923,"line":1480},[675,738],[13925,13929],{"type":29,"tag":127,"props":13926,"children":13927},{"style":686},[13928],{"type":56,"value":744},{"type":29,"tag":127,"props":13930,"children":13931},{"style":718},[13932],{"type":56,"value":13933},"--entrypoints.container-registry.address=:5050\n",{"type":29,"tag":127,"props":13935,"children":13937},{"class":13936,"line":1493},[675,738],[13938,13942],{"type":29,"tag":127,"props":13939,"children":13940},{"style":686},[13941],{"type":56,"value":744},{"type":29,"tag":127,"props":13943,"children":13944},{"style":718},[13945],{"type":56,"value":13946},"--entrypoints.container-registry.http.tls.certresolver=letsencrypt\n",{"type":29,"tag":127,"props":13948,"children":13949},{"class":675,"line":1506},[13950],{"type":29,"tag":127,"props":13951,"children":13952},{"emptyLinePlaceholder":500},[13953],{"type":56,"value":1395},{"type":29,"tag":127,"props":13955,"children":13956},{"class":675,"line":1519},[13957,13961],{"type":29,"tag":127,"props":13958,"children":13959},{"style":686},[13960],{"type":56,"value":744},{"type":29,"tag":127,"props":13962,"children":13963},{"style":718},[13964],{"type":56,"value":12569},{"type":29,"tag":127,"props":13966,"children":13967},{"class":675,"line":1532},[13968,13972],{"type":29,"tag":127,"props":13969,"children":13970},{"style":686},[13971],{"type":56,"value":744},{"type":29,"tag":127,"props":13973,"children":13974},{"style":718},[13975],{"type":56,"value":12581},{"type":29,"tag":127,"props":13977,"children":13978},{"class":675,"line":1545},[13979],{"type":29,"tag":127,"props":13980,"children":13981},{"emptyLinePlaceholder":500},[13982],{"type":56,"value":1395},{"type":29,"tag":127,"props":13984,"children":13985},{"class":675,"line":2398},[13986,13990],{"type":29,"tag":127,"props":13987,"children":13988},{"style":686},[13989],{"type":56,"value":744},{"type":29,"tag":127,"props":13991,"children":13992},{"style":718},[13993],{"type":56,"value":12600},{"type":29,"tag":127,"props":13995,"children":13996},{"class":675,"line":2406},[13997,14001],{"type":29,"tag":127,"props":13998,"children":13999},{"style":686},[14000],{"type":56,"value":744},{"type":29,"tag":127,"props":14002,"children":14003},{"style":718},[14004],{"type":56,"value":1373},{"type":29,"tag":127,"props":14006,"children":14007},{"class":675,"line":2426},[14008,14012],{"type":29,"tag":127,"props":14009,"children":14010},{"style":686},[14011],{"type":56,"value":744},{"type":29,"tag":127,"props":14013,"children":14014},{"style":718},[14015],{"type":56,"value":1348},{"type":29,"tag":127,"props":14017,"children":14018},{"class":675,"line":2447},[14019,14023],{"type":29,"tag":127,"props":14020,"children":14021},{"style":686},[14022],{"type":56,"value":744},{"type":29,"tag":127,"props":14024,"children":14025},{"style":718},[14026],{"type":56,"value":1386},{"type":29,"tag":48,"props":14028,"children":14029},{},[14030],{"type":56,"value":12638},{"type":29,"tag":808,"props":14032,"children":14033},{},[14034,14039],{"type":29,"tag":812,"props":14035,"children":14036},{},[14037],{"type":56,"value":14038},"add a new entry point for the container registry",{"type":29,"tag":812,"props":14040,"children":14041},{},[14042],{"type":56,"value":14043},"apply the TLS configuration to all routes in this entrypoint",{"type":29,"tag":1663,"props":14045,"children":14046},{},[],{"type":29,"tag":13220,"props":14048,"children":14050},{"id":14049},"update-the-gitlab-config-1",[14051],{"type":56,"value":13225},{"type":29,"tag":657,"props":14053,"children":14056},{"className":667,"code":14054,"filename":11632,"highlights":14055,"language":508,"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",[665,1338,118,1363,1376,2459],[14057],{"type":29,"tag":670,"props":14058,"children":14059},{"__ignoreMap":7},[14060,14071,14082,14097,14112,14123,14134,14145,14158,14169,14180,14193,14206,14219,14231,14246,14261,14272,14287,14294,14301,14308,14315,14322,14329,14336,14343,14350,14357,14364,14371,14378,14385,14394,14401,14412,14423,14434,14445,14456,14467],{"type":29,"tag":127,"props":14061,"children":14062},{"class":675,"line":676},[14063,14067],{"type":29,"tag":127,"props":14064,"children":14065},{"style":680},[14066],{"type":56,"value":683},{"type":29,"tag":127,"props":14068,"children":14069},{"style":686},[14070],{"type":56,"value":689},{"type":29,"tag":127,"props":14072,"children":14073},{"class":675,"line":342},[14074,14078],{"type":29,"tag":127,"props":14075,"children":14076},{"style":680},[14077],{"type":56,"value":11655},{"type":29,"tag":127,"props":14079,"children":14080},{"style":686},[14081],{"type":56,"value":689},{"type":29,"tag":127,"props":14083,"children":14084},{"class":675,"line":704},[14085,14089,14093],{"type":29,"tag":127,"props":14086,"children":14087},{"style":680},[14088],{"type":56,"value":710},{"type":29,"tag":127,"props":14090,"children":14091},{"style":686},[14092],{"type":56,"value":715},{"type":29,"tag":127,"props":14094,"children":14095},{"style":718},[14096],{"type":56,"value":12792},{"type":29,"tag":127,"props":14098,"children":14099},{"class":675,"line":724},[14100,14104,14108],{"type":29,"tag":127,"props":14101,"children":14102},{"style":680},[14103],{"type":56,"value":1263},{"type":29,"tag":127,"props":14105,"children":14106},{"style":686},[14107],{"type":56,"value":715},{"type":29,"tag":127,"props":14109,"children":14110},{"style":718},[14111],{"type":56,"value":11691},{"type":29,"tag":127,"props":14113,"children":14114},{"class":675,"line":662},[14115,14119],{"type":29,"tag":127,"props":14116,"children":14117},{"style":680},[14118],{"type":56,"value":730},{"type":29,"tag":127,"props":14120,"children":14121},{"style":686},[14122],{"type":56,"value":689},{"type":29,"tag":127,"props":14124,"children":14125},{"class":675,"line":663},[14126,14130],{"type":29,"tag":127,"props":14127,"children":14128},{"style":686},[14129],{"type":56,"value":744},{"type":29,"tag":127,"props":14131,"children":14132},{"style":718},[14133],{"type":56,"value":749},{"type":29,"tag":127,"props":14135,"children":14136},{"class":675,"line":664},[14137,14141],{"type":29,"tag":127,"props":14138,"children":14139},{"style":686},[14140],{"type":56,"value":744},{"type":29,"tag":127,"props":14142,"children":14143},{"style":718},[14144],{"type":56,"value":12844},{"type":29,"tag":127,"props":14146,"children":14148},{"class":14147,"line":665},[675,738],[14149,14153],{"type":29,"tag":127,"props":14150,"children":14151},{"style":686},[14152],{"type":56,"value":744},{"type":29,"tag":127,"props":14154,"children":14155},{"style":718},[14156],{"type":56,"value":14157},"\"traefik.http.routers.gitlab.entrypoints=web,websecure\"\n",{"type":29,"tag":127,"props":14159,"children":14160},{"class":675,"line":666},[14161,14165],{"type":29,"tag":127,"props":14162,"children":14163},{"style":686},[14164],{"type":56,"value":744},{"type":29,"tag":127,"props":14166,"children":14167},{"style":718},[14168],{"type":56,"value":12857},{"type":29,"tag":127,"props":14170,"children":14171},{"class":675,"line":1325},[14172,14176],{"type":29,"tag":127,"props":14173,"children":14174},{"style":686},[14175],{"type":56,"value":744},{"type":29,"tag":127,"props":14177,"children":14178},{"style":718},[14179],{"type":56,"value":12870},{"type":29,"tag":127,"props":14181,"children":14183},{"class":14182,"line":1338},[675,738],[14184,14188],{"type":29,"tag":127,"props":14185,"children":14186},{"style":686},[14187],{"type":56,"value":744},{"type":29,"tag":127,"props":14189,"children":14190},{"style":718},[14191],{"type":56,"value":14192},"\"traefik.http.routers.container-registry.rule=Host(`gitlab.example.com`)\"\n",{"type":29,"tag":127,"props":14194,"children":14196},{"class":14195,"line":118},[675,738],[14197,14201],{"type":29,"tag":127,"props":14198,"children":14199},{"style":686},[14200],{"type":56,"value":744},{"type":29,"tag":127,"props":14202,"children":14203},{"style":718},[14204],{"type":56,"value":14205},"\"traefik.http.routers.container-registry.entrypoints=container-registry\"\n",{"type":29,"tag":127,"props":14207,"children":14209},{"class":14208,"line":1363},[675,738],[14210,14214],{"type":29,"tag":127,"props":14211,"children":14212},{"style":686},[14213],{"type":56,"value":744},{"type":29,"tag":127,"props":14215,"children":14216},{"style":718},[14217],{"type":56,"value":14218},"\"traefik.http.routers.container-registry.service=container-registry\"\n",{"type":29,"tag":127,"props":14220,"children":14222},{"class":14221,"line":1376},[675,738],[14223,14227],{"type":29,"tag":127,"props":14224,"children":14225},{"style":686},[14226],{"type":56,"value":744},{"type":29,"tag":127,"props":14228,"children":14229},{"style":718},[14230],{"type":56,"value":13366},{"type":29,"tag":127,"props":14232,"children":14233},{"class":675,"line":1389},[14234,14238,14242],{"type":29,"tag":127,"props":14235,"children":14236},{"style":680},[14237],{"type":56,"value":1280},{"type":29,"tag":127,"props":14239,"children":14240},{"style":686},[14241],{"type":56,"value":715},{"type":29,"tag":127,"props":14243,"children":14244},{"style":718},[14245],{"type":56,"value":1289},{"type":29,"tag":127,"props":14247,"children":14248},{"class":675,"line":1398},[14249,14253,14257],{"type":29,"tag":127,"props":14250,"children":14251},{"style":680},[14252],{"type":56,"value":11714},{"type":29,"tag":127,"props":14254,"children":14255},{"style":686},[14256],{"type":56,"value":715},{"type":29,"tag":127,"props":14258,"children":14259},{"style":718},[14260],{"type":56,"value":12901},{"type":29,"tag":127,"props":14262,"children":14263},{"class":675,"line":1411},[14264,14268],{"type":29,"tag":127,"props":14265,"children":14266},{"style":680},[14267],{"type":56,"value":10034},{"type":29,"tag":127,"props":14269,"children":14270},{"style":686},[14271],{"type":56,"value":689},{"type":29,"tag":127,"props":14273,"children":14274},{"class":675,"line":1424},[14275,14279,14283],{"type":29,"tag":127,"props":14276,"children":14277},{"style":680},[14278],{"type":56,"value":11742},{"type":29,"tag":127,"props":14280,"children":14281},{"style":686},[14282],{"type":56,"value":715},{"type":29,"tag":127,"props":14284,"children":14285},{"style":4927},[14286],{"type":56,"value":11751},{"type":29,"tag":127,"props":14288,"children":14289},{"class":675,"line":1433},[14290],{"type":29,"tag":127,"props":14291,"children":14292},{"style":718},[14293],{"type":56,"value":11759},{"type":29,"tag":127,"props":14295,"children":14296},{"class":675,"line":1446},[14297],{"type":29,"tag":127,"props":14298,"children":14299},{"style":718},[14300],{"type":56,"value":12942},{"type":29,"tag":127,"props":14302,"children":14303},{"class":675,"line":1459},[14304],{"type":29,"tag":127,"props":14305,"children":14306},{"emptyLinePlaceholder":500},[14307],{"type":56,"value":1395},{"type":29,"tag":127,"props":14309,"children":14310},{"class":675,"line":1472},[14311],{"type":29,"tag":127,"props":14312,"children":14313},{"style":718},[14314],{"type":56,"value":12959},{"type":29,"tag":127,"props":14316,"children":14317},{"class":675,"line":1480},[14318],{"type":29,"tag":127,"props":14319,"children":14320},{"emptyLinePlaceholder":500},[14321],{"type":56,"value":1395},{"type":29,"tag":127,"props":14323,"children":14324},{"class":675,"line":1493},[14325],{"type":29,"tag":127,"props":14326,"children":14327},{"style":718},[14328],{"type":56,"value":12975},{"type":29,"tag":127,"props":14330,"children":14331},{"class":675,"line":1506},[14332],{"type":29,"tag":127,"props":14333,"children":14334},{"style":718},[14335],{"type":56,"value":12984},{"type":29,"tag":127,"props":14337,"children":14338},{"class":675,"line":1519},[14339],{"type":29,"tag":127,"props":14340,"children":14341},{"style":718},[14342],{"type":56,"value":12993},{"type":29,"tag":127,"props":14344,"children":14345},{"class":675,"line":1532},[14346],{"type":29,"tag":127,"props":14347,"children":14348},{"style":718},[14349],{"type":56,"value":13002},{"type":29,"tag":127,"props":14351,"children":14352},{"class":675,"line":1545},[14353],{"type":29,"tag":127,"props":14354,"children":14355},{"style":718},[14356],{"type":56,"value":13011},{"type":29,"tag":127,"props":14358,"children":14359},{"class":675,"line":2398},[14360],{"type":29,"tag":127,"props":14361,"children":14362},{"style":718},[14363],{"type":56,"value":3527},{"type":29,"tag":127,"props":14365,"children":14366},{"class":675,"line":2406},[14367],{"type":29,"tag":127,"props":14368,"children":14369},{"emptyLinePlaceholder":500},[14370],{"type":56,"value":1395},{"type":29,"tag":127,"props":14372,"children":14373},{"class":675,"line":2426},[14374],{"type":29,"tag":127,"props":14375,"children":14376},{"style":718},[14377],{"type":56,"value":13035},{"type":29,"tag":127,"props":14379,"children":14380},{"class":675,"line":2447},[14381],{"type":29,"tag":127,"props":14382,"children":14383},{"emptyLinePlaceholder":500},[14384],{"type":56,"value":1395},{"type":29,"tag":127,"props":14386,"children":14388},{"class":14387,"line":2459},[675,738],[14389],{"type":29,"tag":127,"props":14390,"children":14391},{"style":718},[14392],{"type":56,"value":14393},"        registry_external_url '\u003Chttps://gitlab.example.com:5050>'\n",{"type":29,"tag":127,"props":14395,"children":14396},{"class":675,"line":2475},[14397],{"type":29,"tag":127,"props":14398,"children":14399},{"style":718},[14400],{"type":56,"value":13538},{"type":29,"tag":127,"props":14402,"children":14403},{"class":675,"line":2483},[14404,14408],{"type":29,"tag":127,"props":14405,"children":14406},{"style":680},[14407],{"type":56,"value":11775},{"type":29,"tag":127,"props":14409,"children":14410},{"style":686},[14411],{"type":56,"value":689},{"type":29,"tag":127,"props":14413,"children":14414},{"class":675,"line":1957},[14415,14419],{"type":29,"tag":127,"props":14416,"children":14417},{"style":686},[14418],{"type":56,"value":744},{"type":29,"tag":127,"props":14420,"children":14421},{"style":718},[14422],{"type":56,"value":13059},{"type":29,"tag":127,"props":14424,"children":14425},{"class":675,"line":1958},[14426,14430],{"type":29,"tag":127,"props":14427,"children":14428},{"style":680},[14429],{"type":56,"value":1525},{"type":29,"tag":127,"props":14431,"children":14432},{"style":686},[14433],{"type":56,"value":689},{"type":29,"tag":127,"props":14435,"children":14436},{"class":675,"line":1959},[14437,14441],{"type":29,"tag":127,"props":14438,"children":14439},{"style":686},[14440],{"type":56,"value":744},{"type":29,"tag":127,"props":14442,"children":14443},{"style":718},[14444],{"type":56,"value":11838},{"type":29,"tag":127,"props":14446,"children":14447},{"class":675,"line":1960},[14448,14452],{"type":29,"tag":127,"props":14449,"children":14450},{"style":686},[14451],{"type":56,"value":744},{"type":29,"tag":127,"props":14453,"children":14454},{"style":718},[14455],{"type":56,"value":11850},{"type":29,"tag":127,"props":14457,"children":14458},{"class":675,"line":2546},[14459,14463],{"type":29,"tag":127,"props":14460,"children":14461},{"style":686},[14462],{"type":56,"value":744},{"type":29,"tag":127,"props":14464,"children":14465},{"style":718},[14466],{"type":56,"value":11862},{"type":29,"tag":127,"props":14468,"children":14469},{"class":675,"line":2555},[14470,14474,14478],{"type":29,"tag":127,"props":14471,"children":14472},{"style":680},[14473],{"type":56,"value":11870},{"type":29,"tag":127,"props":14475,"children":14476},{"style":686},[14477],{"type":56,"value":715},{"type":29,"tag":127,"props":14479,"children":14480},{"style":718},[14481],{"type":56,"value":11879},{"type":29,"tag":48,"props":14483,"children":14484},{},[14485],{"type":56,"value":12638},{"type":29,"tag":808,"props":14487,"children":14488},{},[14489,14493,14497],{"type":29,"tag":812,"props":14490,"children":14491},{},[14492],{"type":56,"value":13631},{"type":29,"tag":812,"props":14494,"children":14495},{},[14496],{"type":56,"value":13636},{"type":29,"tag":812,"props":14498,"children":14499},{},[14500],{"type":56,"value":14501},"instruct Traefik to route all traffic from port 5050 to port 5000 of the container",{"type":29,"tag":1826,"props":14503,"children":14504},{},[14505],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":14507},[14508,14509],{"id":11615,"depth":342,"text":11618},{"id":11887,"depth":342,"text":11890,"children":14510},[14511,14512,14513],{"id":12007,"depth":704,"text":12010},{"id":12257,"depth":704,"text":12260},{"id":13178,"depth":704,"text":13181},{"_path":597,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":598,"description":599,"author":600,"image":519,"releaseDate":601,"blogCategories":14515,"articleTags":14516,"tags":14517,"body":14518,"_type":346,"_id":606,"_source":348,"_file":607,"_stem":608,"_extension":351},[603],[523],[24],{"type":26,"children":14519,"toc":15751},[14520,14526,14545,14551,14597,14660,14672,14678,14688,14729,14738,14770,14810,14819,14852,14871,14914,14920,14929,14961,15006,15031,15041,15056,15062,15071,15100,15221,15225,15269,15275,15284,15336,15367,15391,15422,15440,15446,15455,15486,15505,15541,15560,15586,15598,15604,15613,15639,15695,15701,15729,15741],{"type":29,"tag":61,"props":14521,"children":14525},{"alt":14522,"aspect-ratio":14523,"height":1850,"object-fit":1851,"src":14524},"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":29,"tag":127,"props":14527,"children":14531},{"className":14528},[14529,14530],"text-right","text-caption",[14532],{"type":29,"tag":48,"props":14533,"children":14534},{},[14535],{"type":29,"tag":14536,"props":14537,"children":14538},"em",{},[14539],{"type":29,"tag":643,"props":14540,"children":14542},{"href":14541},"https://www.pexels.com/photo/person-holding-a-sticker-11035393/",[14543],{"type":56,"value":14544},"Photo by RealToughCandy.com",{"type":29,"tag":90,"props":14546,"children":14548},{"id":14547},"why-developing-a-web-application-is-only-the-beginning",[14549],{"type":56,"value":14550},"Why developing a (web) application is only the beginning",{"type":29,"tag":48,"props":14552,"children":14553},{},[14554,14556,14561,14563,14568,14570,14574,14576,14581,14583,14588,14590,14595],{"type":56,"value":14555},"Web applications are mostly developed and tested in a ",{"type":29,"tag":14536,"props":14557,"children":14558},{},[14559],{"type":56,"value":14560},"Dev",{"type":56,"value":14562}," environment (Development environment) - however the\nactual endurance test takes place on the ",{"type":29,"tag":14536,"props":14564,"children":14565},{},[14566],{"type":56,"value":14567},"Prod",{"type":56,"value":14569}," systems (Production environment). Here, ",{"type":29,"tag":52,"props":14571,"children":14572},{},[14573],{"type":56,"value":523},{"type":56,"value":14575}," (short for\n",{"type":29,"tag":14536,"props":14577,"children":14578},{},[14579],{"type":56,"value":14580},"Development Operations",{"type":56,"value":14582},", representing the close integration between development and IT operations) plays a key role.\nEspecially with web applications on ",{"type":29,"tag":52,"props":14584,"children":14585},{},[14586],{"type":56,"value":14587},"Linux servers",{"type":56,"value":14589}," with complex ",{"type":29,"tag":52,"props":14591,"children":14592},{},[14593],{"type":56,"value":14594},"network infrastructures",{"type":56,"value":14596},", 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":29,"tag":48,"props":14598,"children":14599},{},[14600,14602,14607,14609,14614,14615,14620,14622,14631,14632,14641,14643,14651,14653,14658],{"type":56,"value":14601},"We will shed light on why development environments reach their limits, why genuine load tests and ",{"type":29,"tag":14536,"props":14603,"children":14604},{},[14605],{"type":56,"value":14606},"Edge Cases",{"type":56,"value":14608}," are\ndifficult to simulate, and why work begins properly only after the launch (namely under ",{"type":29,"tag":14536,"props":14610,"children":14611},{},[14612],{"type":56,"value":14613},"monitoring",{"type":56,"value":9668},{"type":29,"tag":14536,"props":14616,"children":14617},{},[14618],{"type":56,"value":14619},"continuous\nimprovement",{"type":56,"value":14621},"). We will also explore the tools that are indispensable in our daily work, from\n",{"type":29,"tag":643,"props":14623,"children":14625},{"href":14624},"https://sentry.io/",[14626],{"type":29,"tag":52,"props":14627,"children":14628},{},[14629],{"type":56,"value":14630},"Sentry",{"type":56,"value":10167},{"type":29,"tag":643,"props":14633,"children":14635},{"href":14634},"https://grafana.com/",[14636],{"type":29,"tag":52,"props":14637,"children":14638},{},[14639],{"type":56,"value":14640},"Grafana",{"type":56,"value":14642},", to\n",{"type":29,"tag":643,"props":14644,"children":14646},{"href":14645},"https://www.zabbix.com/",[14647],{"type":29,"tag":52,"props":14648,"children":14649},{},[14650],{"type":56,"value":385},{"type":56,"value":14652},", and how ",{"type":29,"tag":52,"props":14654,"children":14655},{},[14656],{"type":56,"value":14657},"CI/CD pipelines",{"type":56,"value":14659}," help even less experienced developers to deploy\nsafely.",{"type":29,"tag":127,"props":14661,"children":14663},{"className":14662},[14529],[14664],{"type":29,"tag":48,"props":14665,"children":14666},{},[14667],{"type":29,"tag":14536,"props":14668,"children":14669},{},[14670],{"type":56,"value":14671},"Reading duration: approx. 20 minutes",{"type":29,"tag":90,"props":14673,"children":14675},{"id":14674},"development-environment-vs-reality-limited-performance-and-unknown-edge-cases",[14676],{"type":56,"value":14677},"Development environment vs. reality: Limited performance and unknown edge cases",{"type":29,"tag":48,"props":14679,"children":14680},{},[14681,14686],{"type":29,"tag":52,"props":14682,"children":14683},{},[14684],{"type":56,"value":14685},"Thesis:",{"type":56,"value":14687}," Software projects and web applications are built in development environments that are limited in performance\nand test data.",{"type":29,"tag":48,"props":14689,"children":14690},{},[14691,14693,14698,14700,14705,14707,14712,14714,14719,14721,14727],{"type":56,"value":14692},"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":29,"tag":52,"props":14694,"children":14695},{},[14696],{"type":56,"value":14697},"Dev environment",{"type":56,"value":14699}," is typically ",{"type":29,"tag":52,"props":14701,"children":14702},{},[14703],{"type":56,"value":14704},"less powerful",{"type":56,"value":14706}," 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":29,"tag":52,"props":14708,"children":14709},{},[14710],{"type":56,"value":14711},"staging",{"type":56,"value":14713}," environment can try to mimic the production environment\nbut it has its ",{"type":29,"tag":52,"props":14715,"children":14716},{},[14717],{"type":56,"value":14718},"limits",{"type":56,"value":14720},": 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":29,"tag":643,"props":14722,"children":14724},{"href":14723},"https://www.browserstack.com/guide/testing-in-production#:~:text=1.%20Real,only%20surface%20under%20specific%20conditions",[14725],{"type":56,"value":14726},"browserstack.com",{"type":56,"value":14728},"\n. In other words: Everything runs \"smoothly\" in the test environment, but reality introduces completely different\nfactors.",{"type":29,"tag":48,"props":14730,"children":14731},{},[14732,14736],{"type":29,"tag":52,"props":14733,"children":14734},{},[14735],{"type":56,"value":14685},{"type":56,"value":14737}," Developers and clients often lack a complete overview of realistic use cases, edge cases, and peak loads.",{"type":29,"tag":48,"props":14739,"children":14740},{},[14741,14743,14748,14750,14755,14757,14761,14763,14768],{"type":56,"value":14742},"Development teams and even clients know the ",{"type":29,"tag":14536,"props":14744,"children":14745},{},[14746],{"type":56,"value":14747},"major use cases",{"type":56,"value":14749}," of their software, but ",{"type":29,"tag":52,"props":14751,"children":14752},{},[14753],{"type":56,"value":14754},"real users",{"type":56,"value":14756},"\noften push applications to their limits. Suddenly they use features in combinations that nobody had thought of,\nor input unexpected data. Such ",{"type":29,"tag":52,"props":14758,"children":14759},{},[14760],{"type":56,"value":14606},{"type":56,"value":14762}," (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":29,"tag":14536,"props":14764,"children":14765},{},[14766],{"type":56,"value":14767},"emoji",{"type":56,"value":14769}," 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":29,"tag":48,"props":14771,"children":14772},{},[14773,14775,14780,14782,14787,14789,14794,14796,14801,14803,14808],{"type":56,"value":14774},"In addition, clients might be familiar with their business processes, but ",{"type":29,"tag":52,"props":14776,"children":14777},{},[14778],{"type":56,"value":14779},"peak loads",{"type":56,"value":14781}," due to marketing actions or\ncompletely atypical\nusage times (e.g., at 3 a.m. on weekends) are easily underestimated. The ",{"type":29,"tag":52,"props":14783,"children":14784},{},[14785],{"type":56,"value":14786},"critical view",{"type":56,"value":14788}," here:\nModern approaches aim to close this gap by advocating that development and production environments should be as\nsimilar as possible (",{"type":29,"tag":14536,"props":14790,"children":14791},{},[14792],{"type":56,"value":14793},"dev/prod parity",{"type":56,"value":14795},") in order to minimize later surprises.\n",{"type":29,"tag":52,"props":14797,"children":14798},{},[14799],{"type":56,"value":14800},"Containerization",{"type":56,"value":14802}," (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":29,"tag":52,"props":14804,"children":14805},{},[14806],{"type":56,"value":14807},"all",{"type":56,"value":14809}," real conditions.",{"type":29,"tag":48,"props":14811,"children":14812},{},[14813,14817],{"type":29,"tag":52,"props":14814,"children":14815},{},[14816],{"type":56,"value":14685},{"type":56,"value":14818}," Behavior under prolonged load, external crawlers, penetration tests, or spam-bots are difficult to simulate.",{"type":29,"tag":48,"props":14820,"children":14821},{},[14822,14824,14829,14831,14836,14838,14843,14845,14850],{"type":56,"value":14823},"Performance tests are good practice, but ",{"type":29,"tag":52,"props":14825,"children":14826},{},[14827],{"type":56,"value":14828},"constant load 24/7",{"type":56,"value":14830}," 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":29,"tag":52,"props":14832,"children":14833},{},[14834],{"type":56,"value":14835},"malicious attacks",{"type":56,"value":14837}," are a topic. External ",{"type":29,"tag":52,"props":14839,"children":14840},{},[14841],{"type":56,"value":14842},"crawlers",{"type":56,"value":14844}," (e.g. by Google, Bing, or others) might massively call up pages\nor ",{"type":29,"tag":52,"props":14846,"children":14847},{},[14848],{"type":56,"value":14849},"spam bots",{"type":56,"value":14851}," 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":29,"tag":48,"props":14853,"children":14854},{},[14855,14857,14862,14864,14869],{"type":56,"value":14856},"The developer and DevOps community are consistent on this: it is ",{"type":29,"tag":52,"props":14858,"children":14859},{},[14860],{"type":56,"value":14861},"incredibly difficult to truly simulate the production\nload",{"type":56,"value":14863},". Even with test environments that resemble the prod environment, unforeseen effects can occur. An interesting\napproach is therefore almost counterintuitive: sometimes, purposefully ",{"type":29,"tag":52,"props":14865,"children":14866},{},[14867],{"type":56,"value":14868},"undersized test environments are used",{"type":56,"value":14870}," 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":29,"tag":48,"props":14872,"children":14873},{},[14874,14875,14880,14882,14887,14889,14894,14896,14904,14906,14912],{"type":56,"value":11162},{"type":29,"tag":52,"props":14876,"children":14877},{},[14878],{"type":56,"value":14879},"overriding opinion",{"type":56,"value":14881}," in the tech community, however, is that ",{"type":29,"tag":52,"props":14883,"children":14884},{},[14885],{"type":56,"value":14886},"nothing measures up to real production tests",{"type":56,"value":14888},".\nBig players like Netflix even propagate ",{"type":29,"tag":14536,"props":14890,"children":14891},{},[14892],{"type":56,"value":14893},"chaos engineering",{"type":56,"value":14895},", 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":29,"tag":14536,"props":14897,"children":14898},{},[14899],{"type":29,"tag":52,"props":14900,"children":14901},{},[14902],{"type":56,"value":14903},"in production",{"type":56,"value":14905}," can one work with factors such as state data, real inputs, and\nthe behavior of external systems“\n",{"type":29,"tag":643,"props":14907,"children":14909},{"href":14908},"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",[14910],{"type":56,"value":14911},"techtarget.com",{"type":56,"value":14913},"\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":29,"tag":90,"props":14915,"children":14917},{"id":14916},"after-the-launch-is-before-the-launch-analysis-and-optimization-during-operation",[14918],{"type":56,"value":14919},"After the launch is before the launch: Analysis and optimization during operation",{"type":29,"tag":48,"props":14921,"children":14922},{},[14923,14927],{"type":29,"tag":52,"props":14924,"children":14925},{},[14926],{"type":56,"value":14685},{"type":56,"value":14928}," Further analysis and optimization after the launch is essential.",{"type":29,"tag":48,"props":14930,"children":14931},{},[14932,14934,14939,14941,14946,14948,14953,14959],{"type":56,"value":14933},"In the past, a software project was considered finished after the go-live - today we know that ",{"type":29,"tag":52,"props":14935,"children":14936},{},[14937],{"type":56,"value":14938},"Continuous Improvement",{"type":56,"value":14940},"\nis a critical part of successful software. It's precisely ",{"type":29,"tag":52,"props":14942,"children":14943},{},[14944],{"type":56,"value":14945},"after the launch",{"type":56,"value":14947}," that the phase begins in which real use\ndata is evaluated, bottlenecks are identified, and optimizations are made. As one expert article emphasizes: ",{"type":29,"tag":14536,"props":14949,"children":14950},{},[14951],{"type":56,"value":14952},"\"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":29,"tag":643,"props":14954,"children":14956},{"href":14955},"https://www.topdevelopers.co/blog/post-launch-support-in-software-development/#:~:text=Even%20with%20rigorous%20pre,a%20large%20number%20of%20users",[14957],{"type":56,"value":14958},"topdevelopers.co",{"type":56,"value":14960},"\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":29,"tag":48,"props":14962,"children":14963},{},[14964,14969,14971,14976,14978,14983,14985,14990,14992,14997,14999,15004],{"type":29,"tag":52,"props":14965,"children":14966},{},[14967],{"type":56,"value":14968},"Critical Perspective:",{"type":56,"value":14970}," 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":29,"tag":52,"props":14972,"children":14973},{},[14974],{"type":56,"value":14975},"stabilize and speed up",{"type":56,"value":14977}," a (web)\napplication. Studies show that ",{"type":29,"tag":14536,"props":14979,"children":14980},{},[14981],{"type":56,"value":14982},"continuous maintenance",{"type":56,"value":14984}," can significantly increase ",{"type":29,"tag":52,"props":14986,"children":14987},{},[14988],{"type":56,"value":14989},"user satisfaction and retention",{"type":56,"value":14991},".\nThis includes regular ",{"type":29,"tag":52,"props":14993,"children":14994},{},[14995],{"type":56,"value":14996},"bug fixes",{"type":56,"value":14998},", performance tuning (e.g., adjusting caching strategies, optimizing database\nindexes), and ",{"type":29,"tag":52,"props":15000,"children":15001},{},[15002],{"type":56,"value":15003},"security patches",{"type":56,"value":15005},". Security vulnerabilities that only emerge gradually must be immediately sealed off\nto prevent damage.",{"type":29,"tag":48,"props":15007,"children":15008},{},[15009,15011,15016,15018,15023,15025,15030],{"type":56,"value":15010},"Another aspect is the ",{"type":29,"tag":52,"props":15012,"children":15013},{},[15014],{"type":56,"value":15015},"feedback loop",{"type":56,"value":15017},": 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":29,"tag":14536,"props":15019,"children":15020},{},[15021],{"type":56,"value":15022},"continuous deployment",{"type":56,"value":15024}," 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":29,"tag":14536,"props":15026,"children":15027},{},[15028],{"type":56,"value":15029},"\"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":56,"value":916},{"type":29,"tag":48,"props":15032,"children":15033},{},[15034,15036],{"type":56,"value":15035},"Current practice in successful companies clearly shows: after the launch is before the launch. ",{"type":29,"tag":52,"props":15037,"children":15038},{},[15039],{"type":56,"value":15040},"Stagnation is dangerous",{"type":29,"tag":808,"props":15042,"children":15043},{},[15044],{"type":29,"tag":812,"props":15045,"children":15046},{},[15047,15049,15054],{"type":56,"value":15048},"anyone who does not invest in ",{"type":29,"tag":52,"props":15050,"children":15051},{},[15052],{"type":56,"value":15053},"monitoring, troubleshooting, and optimization",{"type":56,"value":15055}," 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":29,"tag":90,"props":15057,"children":15059},{"id":15058},"monitoring-and-logging-observation-is-essential",[15060],{"type":56,"value":15061},"Monitoring and Logging: Observation is essential",{"type":29,"tag":48,"props":15063,"children":15064},{},[15065,15069],{"type":29,"tag":52,"props":15066,"children":15067},{},[15068],{"type":56,"value":14685},{"type":56,"value":15070}," Monitoring tools like Sentry or Grafana are essential for logging and error analysis.",{"type":29,"tag":48,"props":15072,"children":15073},{},[15074,15076,15081,15083,15090,15091,15098],{"type":56,"value":15075},"To quickly identify problems in operation, ",{"type":29,"tag":52,"props":15077,"children":15078},{},[15079],{"type":56,"value":15080},"monitoring and logging tools",{"type":56,"value":15082}," are absolutely crucial. Two prominent\nexamples are ",{"type":29,"tag":643,"props":15084,"children":15085},{"href":14624},[15086],{"type":29,"tag":52,"props":15087,"children":15088},{},[15089],{"type":56,"value":14630},{"type":56,"value":9668},{"type":29,"tag":643,"props":15092,"children":15093},{"href":14634},[15094],{"type":29,"tag":52,"props":15095,"children":15096},{},[15097],{"type":56,"value":14640},{"type":56,"value":15099}," (often in combination with\ntime-series databases like Prometheus or log databases like ElasticSearch/Loki).",{"type":29,"tag":808,"props":15101,"children":15102},{},[15103,15154],{"type":29,"tag":812,"props":15104,"children":15105},{},[15106,15113,15115,15120,15122,15127,15129,15138,15140,15145,15147,15152],{"type":29,"tag":643,"props":15107,"children":15108},{"href":14624},[15109],{"type":29,"tag":52,"props":15110,"children":15111},{},[15112],{"type":56,"value":14630},{"type":56,"value":15114}," is a specialized tool for ",{"type":29,"tag":52,"props":15116,"children":15117},{},[15118],{"type":56,"value":15119},"error tracking",{"type":56,"value":15121},". 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":29,"tag":52,"props":15123,"children":15124},{},[15125],{"type":56,"value":15126},"industrial standard",{"type":56,"value":15128}," when it comes to crash reporting\n",{"type":29,"tag":643,"props":15130,"children":15132},{"href":15131},"https://medium.com/@AndrzejSala/efficient-error-tracking-with-sentry-e975c186947c#:~:text=Sentry%20is%20a%20crash,an%20industry%20standard%20by%20TechRadar",[15133,15135],{"type":56,"value":15134},"medium.com",{"type":29,"tag":1663,"props":15136,"children":15137},{},[],{"type":56,"value":15139},".\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":29,"tag":52,"props":15141,"children":15142},{},[15143],{"type":56,"value":15144},"immediately",{"type":56,"value":15146}," when an error happens – and can proactively\nrespond, ",{"type":29,"tag":52,"props":15148,"children":15149},{},[15150],{"type":56,"value":15151},"before",{"type":56,"value":15153}," all users are affected.",{"type":29,"tag":812,"props":15155,"children":15156},{},[15157,15164,15166,15171,15173,15178,15180,15185,15187,15192,15194,15199,15201,15206,15208,15213,15215,15220],{"type":29,"tag":643,"props":15158,"children":15159},{"href":14634},[15160],{"type":29,"tag":52,"props":15161,"children":15162},{},[15163],{"type":56,"value":14640},{"type":56,"value":15165},", on the other hand, addresses ",{"type":29,"tag":52,"props":15167,"children":15168},{},[15169],{"type":56,"value":15170},"performance monitoring and visualization",{"type":56,"value":15172}," 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":29,"tag":52,"props":15174,"children":15175},{},[15176],{"type":56,"value":15177},"Prometheus",{"type":56,"value":15179}," (for\nmetric collection) or ",{"type":29,"tag":52,"props":15181,"children":15182},{},[15183],{"type":56,"value":15184},"Loki",{"type":56,"value":15186}," (for log collection), a powerful ",{"type":29,"tag":52,"props":15188,"children":15189},{},[15190],{"type":56,"value":15191},"monitoring cockpit",{"type":56,"value":15193}," is created. You want to be able\nto see ",{"type":29,"tag":14536,"props":15195,"children":15196},{},[15197],{"type":56,"value":15198},"at a glance",{"type":56,"value":15200}," whether all systems are green, where potential bottlenecks may be, or if unusual spikes occur.\nSpecifically, this means: Grafana & Co. help to recognize ",{"type":29,"tag":52,"props":15202,"children":15203},{},[15204],{"type":56,"value":15205},"trends",{"type":56,"value":15207}," (e.g., steadily increasing memory load), track\n",{"type":29,"tag":52,"props":15209,"children":15210},{},[15211],{"type":56,"value":15212},"anomalies",{"type":56,"value":15214}," (e.g., sudden traffic increase at midnight), and in the event of an error, quickly identify the ",{"type":29,"tag":52,"props":15216,"children":15217},{},[15218],{"type":56,"value":15219},"cause",{"type":56,"value":916},{"type":29,"tag":15222,"props":15223,"children":15224},"icons-dev-ops",{},[],{"type":29,"tag":48,"props":15226,"children":15227},{},[15228,15232,15234,15239,15241,15246,15248,15253,15255,15260,15262,15267],{"type":29,"tag":52,"props":15229,"children":15230},{},[15231],{"type":56,"value":14968},{"type":56,"value":15233}," 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":29,"tag":52,"props":15235,"children":15236},{},[15237],{"type":56,"value":15238},"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":56,"value":15240},". 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":29,"tag":52,"props":15242,"children":15243},{},[15244],{"type":56,"value":15245},"flood of data",{"type":56,"value":15247},". 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":29,"tag":14536,"props":15249,"children":15250},{},[15251],{"type":56,"value":15252},"alert fatigue",{"type":56,"value":15254}," – too many false alarms. Here, ",{"type":29,"tag":52,"props":15256,"children":15257},{},[15258],{"type":56,"value":15259},"quality over quantity",{"type":56,"value":15261}," is key. Better a few,\nbut meaningful metrics and alerts. We strongly advise all our customers: ",{"type":29,"tag":14536,"props":15263,"children":15264},{},[15265],{"type":56,"value":15266},"the investment in monitoring and logging tools\nis essential",{"type":56,"value":15268}," in order to remain capable of action in the event of an error!",{"type":29,"tag":90,"props":15270,"children":15272},{"id":15271},"automatic-alerts-zabbix-and-co-as-the-guardians-of-the-systems",[15273],{"type":56,"value":15274},"Automatic Alerts: Zabbix and Co. as the Guardians of the Systems",{"type":29,"tag":48,"props":15276,"children":15277},{},[15278,15282],{"type":29,"tag":52,"props":15279,"children":15280},{},[15281],{"type":56,"value":14685},{"type":56,"value":15283}," Monitoring tools like Zabbix are necessary for alerts during critical system conditions.",{"type":29,"tag":48,"props":15285,"children":15286},{},[15287,15289,15294,15296,15300,15301,15306,15307,15312,15314,15321,15323,15328,15329,15334],{"type":56,"value":15288},"In addition to just observing metrics, of course, we want to be ",{"type":29,"tag":52,"props":15290,"children":15291},{},[15292],{"type":56,"value":15293},"automatically alerted",{"type":56,"value":15295}," when something goes awry. This\nis where system monitoring tools like ",{"type":29,"tag":52,"props":15297,"children":15298},{},[15299],{"type":56,"value":385},{"type":56,"value":10167},{"type":29,"tag":52,"props":15302,"children":15303},{},[15304],{"type":56,"value":15305},"Nagios",{"type":56,"value":10167},{"type":29,"tag":52,"props":15308,"children":15309},{},[15310],{"type":56,"value":15311},"Icinga",{"type":56,"value":15313},", etc., come into play. Let's stick with\n",{"type":29,"tag":643,"props":15315,"children":15316},{"href":14645},[15317],{"type":29,"tag":52,"props":15318,"children":15319},{},[15320],{"type":56,"value":385},{"type":56,"value":15322}," as an example: Zabbix is an open-source monitoring system that offers predefined\n",{"type":29,"tag":52,"props":15324,"children":15325},{},[15326],{"type":56,"value":15327},"triggers",{"type":56,"value":9668},{"type":29,"tag":52,"props":15330,"children":15331},{},[15332],{"type":56,"value":15333},"notifications",{"type":56,"value":15335},". 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":29,"tag":48,"props":15337,"children":15338},{},[15339,15341,15345,15347,15352,15354,15358,15360,15365],{"type":56,"value":15340},"Why do we need this, didn't we just praise Grafana & Co.? The difference: ",{"type":29,"tag":52,"props":15342,"children":15343},{},[15344],{"type":56,"value":14640},{"type":56,"value":15346}," is great for visualization and\nanalysis, but ",{"type":29,"tag":52,"props":15348,"children":15349},{},[15350],{"type":56,"value":15351},"active alerting",{"type":56,"value":15353}," is often taken over by a dedicated tool like Zabbix (or Grafana is combined with an\nalert manager). ",{"type":29,"tag":52,"props":15355,"children":15356},{},[15357],{"type":56,"value":385},{"type":56,"value":15359}," and similar tools are essentially the ",{"type":29,"tag":52,"props":15361,"children":15362},{},[15363],{"type":56,"value":15364},"night watchmen",{"type":56,"value":15366}," who tirelessly monitor for defined\nconditions.",{"type":29,"tag":48,"props":15368,"children":15369},{},[15370,15372,15377,15383,15385,15389],{"type":56,"value":15371},"The importance of such alerts cannot be overstated. A fitting quote from a Linux Journal article: ",{"type":29,"tag":14536,"props":15373,"children":15374},{},[15375],{"type":56,"value":15376},"\"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":29,"tag":643,"props":15378,"children":15380},{"href":15379},"https://www.linuxjournal.com/content/how-monitor-your-system-zabbix#:~:text=Alerts%20and%20triggers%20are%20the,that%20could%20impact%20system%20performance",[15381],{"type":56,"value":15382},"linuxjournal.com",{"type":56,"value":15384},"\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":29,"tag":52,"props":15386,"children":15387},{},[15388],{"type":56,"value":15144},{"type":56,"value":15390}," knows, for example,\nif the web server has failed or if the response times are critically high.",{"type":29,"tag":48,"props":15392,"children":15393},{},[15394,15399,15401,15406,15408,15413,15415,15420],{"type":29,"tag":52,"props":15395,"children":15396},{},[15397],{"type":56,"value":15398},"Practical View:",{"type":56,"value":15400}," 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":29,"tag":14536,"props":15402,"children":15403},{},[15404],{"type":56,"value":15405},"false positives",{"type":56,"value":15407},"), will quickly be ignored. The trick is to define ",{"type":29,"tag":52,"props":15409,"children":15410},{},[15411],{"type":56,"value":15412},"meaningful threshold values",{"type":56,"value":15414},"\nand send ",{"type":29,"tag":52,"props":15416,"children":15417},{},[15418],{"type":56,"value":15419},"context-rich alerts",{"type":56,"value":15421}," (e.g., directly with an indication of which component is affected, attach logs, etc.).",{"type":29,"tag":48,"props":15423,"children":15424},{},[15425,15432,15434,15439],{"type":29,"tag":643,"props":15426,"children":15427},{"href":14645},[15428],{"type":29,"tag":52,"props":15429,"children":15430},{},[15431],{"type":56,"value":385},{"type":56,"value":15433}," has proven itself in many of our projects and is often referred to internally as\nan ",{"type":29,"tag":52,"props":15435,"children":15436},{},[15437],{"type":56,"value":15438},"indispensable tool",{"type":56,"value":916},{"type":29,"tag":90,"props":15441,"children":15443},{"id":15442},"cicd-pipelines-standardized-deployments-also-for-beginners",[15444],{"type":56,"value":15445},"CI/CD Pipelines: Standardized Deployments - Also for Beginners",{"type":29,"tag":48,"props":15447,"children":15448},{},[15449,15453],{"type":29,"tag":52,"props":15450,"children":15451},{},[15452],{"type":56,"value":14685},{"type":56,"value":15454}," CI/CD Pipelines enable standardized, safe deployments even for less experienced developers.",{"type":29,"tag":48,"props":15456,"children":15457},{},[15458,15460,15464,15466,15471,15472,15477,15479,15484],{"type":56,"value":15459},"The terms ",{"type":29,"tag":52,"props":15461,"children":15462},{},[15463],{"type":56,"value":5262},{"type":56,"value":15465}," stand for ",{"type":29,"tag":14536,"props":15467,"children":15468},{},[15469],{"type":56,"value":15470},"Continuous Integration",{"type":56,"value":9668},{"type":29,"tag":14536,"props":15473,"children":15474},{},[15475],{"type":56,"value":15476},"Continuous Delivery/Deployment",{"type":56,"value":15478},". A ",{"type":29,"tag":52,"props":15480,"children":15481},{},[15482],{"type":56,"value":15483},"CI/CD pipeline",{"type":56,"value":15485}," 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":29,"tag":48,"props":15487,"children":15488},{},[15489,15491,15496,15498,15503],{"type":56,"value":15490},"In traditional development workflows, the ",{"type":29,"tag":52,"props":15492,"children":15493},{},[15494],{"type":56,"value":15495},"deployment",{"type":56,"value":15497}," 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":29,"tag":52,"props":15499,"children":15500},{},[15501],{"type":56,"value":15502},"standardized, repeatable operation",{"type":56,"value":15504}," - 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":29,"tag":48,"props":15506,"children":15507},{},[15508,15513,15515,15520,15521,15526,15528,15532,15534,15539],{"type":29,"tag":52,"props":15509,"children":15510},{},[15511],{"type":56,"value":15512},"Safety and quality",{"type":56,"value":15514}," are not neglected - on the contrary. Particularly less experienced developers benefit from the\nfact that the pipeline carries out automated ",{"type":29,"tag":52,"props":15516,"children":15517},{},[15518],{"type":56,"value":15519},"tests",{"type":56,"value":9668},{"type":29,"tag":52,"props":15522,"children":15523},{},[15524],{"type":56,"value":15525},"code checks",{"type":56,"value":15527}," ",{"type":29,"tag":14536,"props":15529,"children":15530},{},[15531],{"type":56,"value":15151},{"type":56,"value":15533}," 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":29,"tag":52,"props":15535,"children":15536},{},[15537],{"type":56,"value":15538},"the same way",{"type":56,"value":15540}," - 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":29,"tag":48,"props":15542,"children":15543},{},[15544,15546,15551,15553,15558],{"type":56,"value":15545},"Of course, setting up a CI/CD pipeline initially requires ",{"type":29,"tag":52,"props":15547,"children":15548},{},[15549],{"type":56,"value":15550},"know-how and effort",{"type":56,"value":15552},". 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":29,"tag":52,"props":15554,"children":15555},{},[15556],{"type":56,"value":15557},"Upon critical examination",{"type":56,"value":15559},", 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":29,"tag":48,"props":15561,"children":15562},{},[15563,15565,15570,15572,15577,15579,15584],{"type":56,"value":15564},"It's important that CI/CD brings not only technical but also ",{"type":29,"tag":52,"props":15566,"children":15567},{},[15568],{"type":56,"value":15569},"cultural changes",{"type":56,"value":15571},". Deployments become smaller but more\nfrequent. This reduces risk and the impact of errors. Teams get used to deployments being ",{"type":29,"tag":14536,"props":15573,"children":15574},{},[15575],{"type":56,"value":15576},"routine",{"type":56,"value":15578}," and not \"major\noperation days\". Especially in ",{"type":29,"tag":52,"props":15580,"children":15581},{},[15582],{"type":56,"value":15583},"Agile Development",{"type":56,"value":15585},", CI/CD is virtually the backbone to enable fast iterations.",{"type":29,"tag":48,"props":15587,"children":15588},{},[15589,15591,15596],{"type":56,"value":15590},"In summary: CI/CD pipelines are a game-changer that enables even less experienced developers to deliver ",{"type":29,"tag":52,"props":15592,"children":15593},{},[15594],{"type":56,"value":15595},"at the push of\na button",{"type":56,"value":15597}," – reliably and repeatably.",{"type":29,"tag":90,"props":15599,"children":15601},{"id":15600},"experience-counts-live-data-specific-errors-and-the-role-of-devops-experts",[15602],{"type":56,"value":15603},"Experience Counts: Live Data, Specific Errors, and the Role of DevOps Experts",{"type":29,"tag":48,"props":15605,"children":15606},{},[15607,15611],{"type":29,"tag":52,"props":15608,"children":15609},{},[15610],{"type":56,"value":14685},{"type":56,"value":15612}," Certain errors and performance problems only manifest with live data and require experienced DevOps\nspecialists.",{"type":29,"tag":48,"props":15614,"children":15615},{},[15616,15618,15623,15625,15630,15632,15637],{"type":56,"value":15617},"Despite all automation and testing, the ",{"type":29,"tag":52,"props":15619,"children":15620},{},[15621],{"type":56,"value":15622},"experience",{"type":56,"value":15624}," in dealing with production systems is irreplaceable. There are\nerror patterns that only occur with real ",{"type":29,"tag":52,"props":15626,"children":15627},{},[15628],{"type":56,"value":15629},"live data and loads",{"type":56,"value":15631}," - 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":29,"tag":52,"props":15633,"children":15634},{},[15635],{"type":56,"value":15636},"memory leak",{"type":56,"value":15638}," 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":29,"tag":48,"props":15640,"children":15641},{},[15642,15644,15649,15651,15657,15658,15664,15666,15672,15674,15679,15681,15686,15688,15693],{"type":56,"value":15643},"A DevOps engineer with a lot of operational experience usually has a repertoire of ",{"type":29,"tag":52,"props":15645,"children":15646},{},[15647],{"type":56,"value":15648},"diagnostic techniques",{"type":56,"value":15650},". For\nexample, experienced people know how to debug on Linux with tools like ",{"type":29,"tag":670,"props":15652,"children":15654},{"className":15653},[],[15655],{"type":56,"value":15656},"htop",{"type":56,"value":10167},{"type":29,"tag":670,"props":15659,"children":15661},{"className":15660},[],[15662],{"type":56,"value":15663},"iotop",{"type":56,"value":15665},", or ",{"type":29,"tag":670,"props":15667,"children":15669},{"className":15668},[],[15670],{"type":56,"value":15671},"strace",{"type":56,"value":15673},", which less routine\ndevelopers may never have needed. Experienced DevOps also know ",{"type":29,"tag":52,"props":15675,"children":15676},{},[15677],{"type":56,"value":15678},"duration load phenomena",{"type":56,"value":15680}," (keywords: ",{"type":29,"tag":14536,"props":15682,"children":15683},{},[15684],{"type":56,"value":15685},"floating-point\nprecision bugs",{"type":56,"value":15687},", memory-induced rounding errors, etc.) from practice. A drastic but real scenario: A memory error occurs\n",{"type":29,"tag":14536,"props":15689,"children":15690},{},[15691],{"type":56,"value":15692},"only",{"type":56,"value":15694}," 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":29,"tag":90,"props":15696,"children":15698},{"id":15697},"conclusion",[15699],{"type":56,"value":15700},"Conclusion",{"type":29,"tag":48,"props":15702,"children":15703},{},[15704,15706,15711,15713,15718,15720,15727],{"type":56,"value":15705},"For (web) applications in productive use, ",{"type":29,"tag":52,"props":15707,"children":15708},{},[15709],{"type":56,"value":15710},"DevOps is not a luxury, but a necessity",{"type":56,"value":15712},". 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":29,"tag":52,"props":15714,"children":15715},{},[15716],{"type":56,"value":15717},"time and resources",{"type":56,"value":15719}," even after the launch to analyze data and implement improvements. Tools like\n",{"type":29,"tag":643,"props":15721,"children":15722},{"href":14624},[15723],{"type":29,"tag":52,"props":15724,"children":15725},{},[15726],{"type":56,"value":14630},{"type":56,"value":15728},", 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":29,"tag":48,"props":15730,"children":15731},{},[15732,15734,15739],{"type":56,"value":15733},"In the end, it shows: ",{"type":29,"tag":52,"props":15735,"children":15736},{},[15737],{"type":56,"value":15738},"People",{"type":56,"value":15740}," make the difference. Experienced DevOps specialists can solve tricky live problems and\nbuild a bridge between developers and operations.",{"type":29,"tag":48,"props":15742,"children":15743},{},[15744,15749],{"type":29,"tag":52,"props":15745,"children":15746},{},[15747],{"type":56,"value":15748},"Note:",{"type":56,"value":15750}," This article was also generated with the support of AI (model: GPT-4).",{"title":7,"searchDepth":342,"depth":342,"links":15752},[15753,15754,15755,15756,15757,15758,15759,15760],{"id":14547,"depth":342,"text":14550},{"id":14674,"depth":342,"text":14677},{"id":14916,"depth":342,"text":14919},{"id":15058,"depth":342,"text":15061},{"id":15271,"depth":342,"text":15274},{"id":15442,"depth":342,"text":15445},{"id":15600,"depth":342,"text":15603},{"id":15697,"depth":342,"text":15700},{"_path":610,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":611,"description":612,"author":170,"image":613,"releaseDate":614,"blogCategories":15762,"articleTags":15763,"tags":15764,"body":15765,"_type":346,"_id":619,"_source":348,"_file":620,"_stem":621,"_extension":351},[522,523],[617],[24],{"type":26,"children":15766,"toc":16315},[15767,15773,15778,15783,15799,15812,15818,15845,15862,15868,15873,15886,15899,15930,15965,15986,16040,16057,16083,16126,16155,16205,16224,16237,16279,16291,16311],{"type":29,"tag":90,"props":15768,"children":15770},{"id":15769},"how-to-resolve-selected-domains-over-vpn-on-linux",[15771],{"type":56,"value":15772},"How to resolve selected domains over VPN on Linux",{"type":29,"tag":48,"props":15774,"children":15775},{},[15776],{"type":56,"value":15777},"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":29,"tag":48,"props":15779,"children":15780},{},[15781],{"type":56,"value":15782},"For example, with Openvpn the option",{"type":29,"tag":657,"props":15784,"children":15788},{"className":15785,"code":15786,"language":15787,"meta":7,"style":7},"language-apache shiki shiki-themes github-dark github-dark monokai","pull-filter ignore redirect-gateway\n","apache",[15789],{"type":29,"tag":670,"props":15790,"children":15791},{"__ignoreMap":7},[15792],{"type":29,"tag":127,"props":15793,"children":15794},{"class":675,"line":676},[15795],{"type":29,"tag":127,"props":15796,"children":15797},{"style":686},[15798],{"type":56,"value":15786},{"type":29,"tag":48,"props":15800,"children":15801},{},[15802,15804,15810],{"type":56,"value":15803},"can be used to tell the ",{"type":29,"tag":670,"props":15805,"children":15807},{"className":15806},[],[15808],{"type":56,"value":15809},"openvpn-client",{"type":56,"value":15811}," to ignore all \"route all\" requests from the server.",{"type":29,"tag":90,"props":15813,"children":15815},{"id":15814},"fritzbox-example",[15816],{"type":56,"value":15817},"FRITZ!Box example",{"type":29,"tag":48,"props":15819,"children":15820},{},[15821,15823,15828,15830,15836,15838,15844],{"type":56,"value":15822},"Recently I had to use a VPN-Connection to a ",{"type":29,"tag":52,"props":15824,"children":15825},{},[15826],{"type":56,"value":15827},"FRITZ!Box",{"type":56,"value":15829},". 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":29,"tag":670,"props":15831,"children":15833},{"className":15832},[],[15834],{"type":56,"value":15835}," workstation",{"type":56,"value":15837}," you can reach it using the \"workstation.fritz.box\" dns name. The fritz-box itself is also available on the\ndns name ",{"type":29,"tag":670,"props":15839,"children":15841},{"className":15840},[],[15842],{"type":56,"value":15843},"fritz.box",{"type":56,"value":916},{"type":29,"tag":48,"props":15846,"children":15847},{},[15848,15850,15855,15857,15861],{"type":56,"value":15849},"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":29,"tag":670,"props":15851,"children":15853},{"className":15852},[],[15854],{"type":56,"value":15843},{"type":56,"value":15856}," suffix to resolve over the ",{"type":29,"tag":52,"props":15858,"children":15859},{},[15860],{"type":56,"value":15827},{"type":56,"value":916},{"type":29,"tag":90,"props":15863,"children":15865},{"id":15864},"solution-using-a-local-dns-server-dnsmasq",[15866],{"type":56,"value":15867},"Solution using a local DNS server - dnsmasq",{"type":29,"tag":48,"props":15869,"children":15870},{},[15871],{"type":56,"value":15872},"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":29,"tag":48,"props":15874,"children":15875},{},[15876,15878,15884],{"type":56,"value":15877},"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":29,"tag":670,"props":15879,"children":15881},{"className":15880},[],[15882],{"type":56,"value":15883},".1",{"type":56,"value":15885}," at the end. You can watch the VPN logs closely to learn which DNS server gets pushed on connect.",{"type":29,"tag":48,"props":15887,"children":15888},{},[15889,15891,15897],{"type":56,"value":15890},"There is a tool called ",{"type":29,"tag":670,"props":15892,"children":15894},{"className":15893},[],[15895],{"type":56,"value":15896},"dig",{"type":56,"value":15898}," which can do dns queries over specified dns servers, for example",{"type":29,"tag":657,"props":15900,"children":15904},{"className":15901,"code":15902,"language":15903,"meta":7,"style":7},"language-bash shiki shiki-themes github-dark github-dark monokai","dig @192.168.1.1 a fritz.box\n","bash",[15905],{"type":29,"tag":670,"props":15906,"children":15907},{"__ignoreMap":7},[15908],{"type":29,"tag":127,"props":15909,"children":15910},{"class":675,"line":676},[15911,15915,15920,15925],{"type":29,"tag":127,"props":15912,"children":15913},{"style":3020},[15914],{"type":56,"value":15896},{"type":29,"tag":127,"props":15916,"children":15917},{"style":718},[15918],{"type":56,"value":15919}," @192.168.1.1",{"type":29,"tag":127,"props":15921,"children":15922},{"style":718},[15923],{"type":56,"value":15924}," a",{"type":29,"tag":127,"props":15926,"children":15927},{"style":718},[15928],{"type":56,"value":15929}," fritz.box\n",{"type":29,"tag":48,"props":15931,"children":15932},{},[15933,15935,15941,15943,15948,15950,15956,15958,15964],{"type":56,"value":15934},"will ask the dns server ",{"type":29,"tag":670,"props":15936,"children":15938},{"className":15937},[],[15939],{"type":56,"value":15940},"192.168.1.1",{"type":56,"value":15942}," for the ip of ",{"type":29,"tag":670,"props":15944,"children":15946},{"className":15945},[],[15947],{"type":56,"value":15843},{"type":56,"value":15949},". ",{"type":29,"tag":670,"props":15951,"children":15953},{"className":15952},[],[15954],{"type":56,"value":15955},"Dig",{"type":56,"value":15957}," 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":29,"tag":670,"props":15959,"children":15961},{"className":15960},[],[15962],{"type":56,"value":15963},"dnsutils",{"type":56,"value":916},{"type":29,"tag":48,"props":15966,"children":15967},{},[15968,15970,15976,15978,15984],{"type":56,"value":15969},"First install ",{"type":29,"tag":670,"props":15971,"children":15973},{"className":15972},[],[15974],{"type":56,"value":15975},"dnsmasq",{"type":56,"value":15977}," on your Linux and edit its configuration (usually lives in ",{"type":29,"tag":670,"props":15979,"children":15981},{"className":15980},[],[15982],{"type":56,"value":15983},"/etc/dnsmasq.conf",{"type":56,"value":15985},"). Add these lines\nhere:",{"type":29,"tag":657,"props":15987,"children":15989},{"className":15785,"code":15988,"language":15787,"meta":7,"style":7},"resolv-file=/etc/resolv.dnsmasq.conf\nserver=/fritz.box/192.168.1.1\n",[15990],{"type":29,"tag":670,"props":15991,"children":15992},{"__ignoreMap":7},[15993,16001],{"type":29,"tag":127,"props":15994,"children":15995},{"class":675,"line":676},[15996],{"type":29,"tag":127,"props":15997,"children":15998},{"style":686},[15999],{"type":56,"value":16000},"resolv-file=/etc/resolv.dnsmasq.conf\n",{"type":29,"tag":127,"props":16002,"children":16003},{"class":675,"line":342},[16004,16009,16014,16018,16023,16027,16031,16035],{"type":29,"tag":127,"props":16005,"children":16006},{"style":686},[16007],{"type":56,"value":16008},"server=/fritz.box/",{"type":29,"tag":127,"props":16010,"children":16011},{"style":2290},[16012],{"type":56,"value":16013},"192",{"type":29,"tag":127,"props":16015,"children":16016},{"style":686},[16017],{"type":56,"value":916},{"type":29,"tag":127,"props":16019,"children":16020},{"style":2290},[16021],{"type":56,"value":16022},"168",{"type":29,"tag":127,"props":16024,"children":16025},{"style":686},[16026],{"type":56,"value":916},{"type":29,"tag":127,"props":16028,"children":16029},{"style":2290},[16030],{"type":56,"value":450},{"type":29,"tag":127,"props":16032,"children":16033},{"style":686},[16034],{"type":56,"value":916},{"type":29,"tag":127,"props":16036,"children":16037},{"style":2290},[16038],{"type":56,"value":16039},"1\n",{"type":29,"tag":48,"props":16041,"children":16042},{},[16043,16048,16050,16055],{"type":29,"tag":670,"props":16044,"children":16046},{"className":16045},[],[16047],{"type":56,"value":15843},{"type":56,"value":16049}," is the domain you want to resolve over the VPN-Dns-server, ",{"type":29,"tag":670,"props":16051,"children":16053},{"className":16052},[],[16054],{"type":56,"value":15940},{"type":56,"value":16056}," in this example.",{"type":29,"tag":48,"props":16058,"children":16059},{},[16060,16061,16066,16068,16073,16075,16081],{"type":56,"value":11162},{"type":29,"tag":52,"props":16062,"children":16063},{},[16064],{"type":56,"value":16065},"Resolv-File",{"type":56,"value":16067}," will tell ",{"type":29,"tag":670,"props":16069,"children":16071},{"className":16070},[],[16072],{"type":56,"value":15975},{"type":56,"value":16074}," how it should resolve its dns queries in case there are no other rules, so let's\ncreate\na ",{"type":29,"tag":670,"props":16076,"children":16078},{"className":16077},[],[16079],{"type":56,"value":16080},"/etc/resolv.dnsmasq.conf",{"type":56,"value":16082},"\nwith content",{"type":29,"tag":657,"props":16084,"children":16086},{"className":15785,"code":16085,"language":15787,"meta":7,"style":7},"nameserver 1.1.1.1\n",[16087],{"type":29,"tag":670,"props":16088,"children":16089},{"__ignoreMap":7},[16090],{"type":29,"tag":127,"props":16091,"children":16092},{"class":675,"line":676},[16093,16098,16102,16106,16110,16114,16118,16122],{"type":29,"tag":127,"props":16094,"children":16095},{"style":686},[16096],{"type":56,"value":16097},"nameserver ",{"type":29,"tag":127,"props":16099,"children":16100},{"style":2290},[16101],{"type":56,"value":450},{"type":29,"tag":127,"props":16103,"children":16104},{"style":686},[16105],{"type":56,"value":916},{"type":29,"tag":127,"props":16107,"children":16108},{"style":2290},[16109],{"type":56,"value":450},{"type":29,"tag":127,"props":16111,"children":16112},{"style":686},[16113],{"type":56,"value":916},{"type":29,"tag":127,"props":16115,"children":16116},{"style":2290},[16117],{"type":56,"value":450},{"type":29,"tag":127,"props":16119,"children":16120},{"style":686},[16121],{"type":56,"value":916},{"type":29,"tag":127,"props":16123,"children":16124},{"style":2290},[16125],{"type":56,"value":16039},{"type":29,"tag":48,"props":16127,"children":16128},{},[16129,16131,16137,16139,16145,16147,16153],{"type":56,"value":16130},"If you use a static network configuration, you now can just edit it to use ",{"type":29,"tag":670,"props":16132,"children":16134},{"className":16133},[],[16135],{"type":56,"value":16136},"127.0.0.1",{"type":56,"value":16138}," 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":29,"tag":670,"props":16140,"children":16142},{"className":16141},[],[16143],{"type":56,"value":16144},"dhclient",{"type":56,"value":16146},". In that case edit ",{"type":29,"tag":670,"props":16148,"children":16150},{"className":16149},[],[16151],{"type":56,"value":16152},"/etc/dhcp/dhclient.conf",{"type":56,"value":16154}," and add:",{"type":29,"tag":657,"props":16156,"children":16158},{"className":15785,"code":16157,"language":15787,"meta":7,"style":7},"prepend domain-name-servers 127.0.0.1;\n",[16159],{"type":29,"tag":670,"props":16160,"children":16161},{"__ignoreMap":7},[16162],{"type":29,"tag":127,"props":16163,"children":16164},{"class":675,"line":676},[16165,16170,16175,16179,16184,16188,16192,16196,16200],{"type":29,"tag":127,"props":16166,"children":16167},{"style":686},[16168],{"type":56,"value":16169},"prepend domain-name-servers ",{"type":29,"tag":127,"props":16171,"children":16172},{"style":2290},[16173],{"type":56,"value":16174},"127",{"type":29,"tag":127,"props":16176,"children":16177},{"style":686},[16178],{"type":56,"value":916},{"type":29,"tag":127,"props":16180,"children":16181},{"style":2290},[16182],{"type":56,"value":16183},"0",{"type":29,"tag":127,"props":16185,"children":16186},{"style":686},[16187],{"type":56,"value":916},{"type":29,"tag":127,"props":16189,"children":16190},{"style":2290},[16191],{"type":56,"value":16183},{"type":29,"tag":127,"props":16193,"children":16194},{"style":686},[16195],{"type":56,"value":916},{"type":29,"tag":127,"props":16197,"children":16198},{"style":2290},[16199],{"type":56,"value":450},{"type":29,"tag":127,"props":16201,"children":16202},{"style":686},[16203],{"type":56,"value":16204},";\n",{"type":29,"tag":48,"props":16206,"children":16207},{},[16208,16210,16215,16217,16222],{"type":56,"value":16209},"That's it. All you have to do now is to restart ",{"type":29,"tag":670,"props":16211,"children":16213},{"className":16212},[],[16214],{"type":56,"value":15975},{"type":56,"value":16216}," so it reloads its config and reconnect/restart ",{"type":29,"tag":670,"props":16218,"children":16220},{"className":16219},[],[16221],{"type":56,"value":16144},{"type":56,"value":16223},"\n(disconnecting and reconnecting the network may work, reboot the machine when in doubt).",{"type":29,"tag":48,"props":16225,"children":16226},{},[16227,16229,16235],{"type":56,"value":16228},"Now you can check if the file ",{"type":29,"tag":670,"props":16230,"children":16232},{"className":16231},[],[16233],{"type":56,"value":16234},"/etc/resolv.conf",{"type":56,"value":16236}," has",{"type":29,"tag":657,"props":16238,"children":16240},{"className":15785,"code":16239,"language":15787,"meta":7,"style":7},"nameserver 127.0.0.1\n",[16241],{"type":29,"tag":670,"props":16242,"children":16243},{"__ignoreMap":7},[16244],{"type":29,"tag":127,"props":16245,"children":16246},{"class":675,"line":676},[16247,16251,16255,16259,16263,16267,16271,16275],{"type":29,"tag":127,"props":16248,"children":16249},{"style":686},[16250],{"type":56,"value":16097},{"type":29,"tag":127,"props":16252,"children":16253},{"style":2290},[16254],{"type":56,"value":16174},{"type":29,"tag":127,"props":16256,"children":16257},{"style":686},[16258],{"type":56,"value":916},{"type":29,"tag":127,"props":16260,"children":16261},{"style":2290},[16262],{"type":56,"value":16183},{"type":29,"tag":127,"props":16264,"children":16265},{"style":686},[16266],{"type":56,"value":916},{"type":29,"tag":127,"props":16268,"children":16269},{"style":2290},[16270],{"type":56,"value":16183},{"type":29,"tag":127,"props":16272,"children":16273},{"style":686},[16274],{"type":56,"value":916},{"type":29,"tag":127,"props":16276,"children":16277},{"style":2290},[16278],{"type":56,"value":16039},{"type":29,"tag":48,"props":16280,"children":16281},{},[16282,16284,16289],{"type":56,"value":16283},"as first nameserver. If it has, the selected domain (",{"type":29,"tag":670,"props":16285,"children":16287},{"className":16286},[],[16288],{"type":56,"value":15843},{"type":56,"value":16290}," in my example) should now resolve.",{"type":29,"tag":48,"props":16292,"children":16293},{},[16294,16296,16301,16303,16309],{"type":56,"value":16295},"On ",{"type":29,"tag":670,"props":16297,"children":16299},{"className":16298},[],[16300],{"type":56,"value":15975},{"type":56,"value":16302},", you can add multiple ",{"type":29,"tag":670,"props":16304,"children":16306},{"className":16305},[],[16307],{"type":56,"value":16308},"server=",{"type":56,"value":16310}," lines, which comes in handy if you have multiple domains that need to be\nresolved over different DNS servers.",{"type":29,"tag":1826,"props":16312,"children":16313},{},[16314],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":16316},[16317,16318,16319],{"id":15769,"depth":342,"text":15772},{"id":15814,"depth":342,"text":15817},{"id":15864,"depth":342,"text":15867},{"_path":623,"_dir":515,"_draft":6,"_partial":6,"_locale":7,"title":624,"description":625,"author":170,"image":626,"releaseDate":627,"blogCategories":16321,"tags":16322,"body":16323,"_type":346,"_id":630,"_source":348,"_file":631,"_stem":632,"_extension":351},[522,590],[24],{"type":26,"children":16324,"toc":16780},[16325,16331,16343,16349,16354,16360,16365,16403,16409,16414,16420,16432,16550,16568,16574,16730,16735,16741,16770,16776],{"type":29,"tag":90,"props":16326,"children":16328},{"id":16327},"what-is-btrfs-fragmentation",[16329],{"type":56,"value":16330},"What is BTRFS fragmentation?",{"type":29,"tag":48,"props":16332,"children":16333},{},[16334,16336,16341],{"type":56,"value":16335},"Most of the best BTRFS features are powered by the ",{"type":29,"tag":14536,"props":16337,"children":16338},{},[16339],{"type":56,"value":16340},"copy-on-write technology",{"type":56,"value":16342},". 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":29,"tag":90,"props":16344,"children":16346},{"id":16345},"btrfs-fragmentation-can-hurt-the-performance-of-your-system",[16347],{"type":56,"value":16348},"BTRFS fragmentation can hurt the performance of your System",{"type":29,"tag":48,"props":16350,"children":16351},{},[16352],{"type":56,"value":16353},"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":29,"tag":90,"props":16355,"children":16357},{"id":16356},"btrfs-fragmentation-can-block-huge-amounts-of-disk-space",[16358],{"type":56,"value":16359},"BTRFS fragmentation can block huge amounts of disk space",{"type":29,"tag":48,"props":16361,"children":16362},{},[16363],{"type":56,"value":16364},"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":29,"tag":48,"props":16366,"children":16367},{},[16368,16370,16375,16376,16381,16382,16387,16389,16394,16396,16401],{"type":56,"value":16369},"If you see your btrfs filesystem using ",{"type":29,"tag":52,"props":16371,"children":16372},{},[16373],{"type":56,"value":16374},"80GB",{"type":56,"value":3264},{"type":29,"tag":14536,"props":16377,"children":16378},{},[16379],{"type":56,"value":16380},"df",{"type":56,"value":9668},{"type":29,"tag":14536,"props":16383,"children":16384},{},[16385],{"type":56,"value":16386},"btrfs fi show",{"type":56,"value":16388}," while ",{"type":29,"tag":14536,"props":16390,"children":16391},{},[16392],{"type":56,"value":16393},"du -hsx",{"type":56,"value":16395}," only shows ",{"type":29,"tag":52,"props":16397,"children":16398},{},[16399],{"type":56,"value":16400},"54GB",{"type":56,"value":16402}," 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":29,"tag":90,"props":16404,"children":16406},{"id":16405},"btrfs-filesystem-defrag",[16407],{"type":56,"value":16408},"BTRFS filesystem defrag",{"type":29,"tag":48,"props":16410,"children":16411},{},[16412],{"type":56,"value":16413},"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":29,"tag":90,"props":16415,"children":16417},{"id":16416},"find-the-most-fragmented-files-on-your-system",[16418],{"type":56,"value":16419},"Find the most fragmented files on your System",{"type":29,"tag":48,"props":16421,"children":16422},{},[16423,16425,16430],{"type":56,"value":16424},"There is a linux-tool called ",{"type":29,"tag":14536,"props":16426,"children":16427},{},[16428],{"type":56,"value":16429},"filefrag",{"type":56,"value":16431}," 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":29,"tag":657,"props":16433,"children":16435},{"className":15901,"code":16434,"language":15903,"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",[16436],{"type":29,"tag":670,"props":16437,"children":16438},{"__ignoreMap":7},[16439],{"type":29,"tag":127,"props":16440,"children":16441},{"class":675,"line":676},[16442,16447,16452,16457,16462,16467,16472,16477,16482,16487,16492,16497,16502,16507,16511,16516,16521,16526,16531,16535,16540,16545],{"type":29,"tag":127,"props":16443,"children":16444},{"style":3020},[16445],{"type":56,"value":16446},"find",{"type":29,"tag":127,"props":16448,"children":16449},{"style":718},[16450],{"type":56,"value":16451}," /",{"type":29,"tag":127,"props":16453,"children":16454},{"style":2290},[16455],{"type":56,"value":16456}," -xdev",{"type":29,"tag":127,"props":16458,"children":16459},{"style":2290},[16460],{"type":56,"value":16461}," -type",{"type":29,"tag":127,"props":16463,"children":16464},{"style":718},[16465],{"type":56,"value":16466}," f",{"type":29,"tag":127,"props":16468,"children":16469},{"style":4927},[16470],{"type":56,"value":16471},"|",{"type":29,"tag":127,"props":16473,"children":16474},{"style":3020},[16475],{"type":56,"value":16476}," xargs",{"type":29,"tag":127,"props":16478,"children":16479},{"style":718},[16480],{"type":56,"value":16481}," filefrag",{"type":29,"tag":127,"props":16483,"children":16484},{"style":4927},[16485],{"type":56,"value":16486}," 2>",{"type":29,"tag":127,"props":16488,"children":16489},{"style":718},[16490],{"type":56,"value":16491},"/dev/null",{"type":29,"tag":127,"props":16493,"children":16494},{"style":4927},[16495],{"type":56,"value":16496}," |",{"type":29,"tag":127,"props":16498,"children":16499},{"style":3020},[16500],{"type":56,"value":16501}," sed",{"type":29,"tag":127,"props":16503,"children":16504},{"style":718},[16505],{"type":56,"value":16506}," 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/'",{"type":29,"tag":127,"props":16508,"children":16509},{"style":4927},[16510],{"type":56,"value":16496},{"type":29,"tag":127,"props":16512,"children":16513},{"style":3020},[16514],{"type":56,"value":16515}," awk",{"type":29,"tag":127,"props":16517,"children":16518},{"style":2290},[16519],{"type":56,"value":16520}," -F",{"type":29,"tag":127,"props":16522,"children":16523},{"style":718},[16524],{"type":56,"value":16525}," ' '",{"type":29,"tag":127,"props":16527,"children":16528},{"style":718},[16529],{"type":56,"value":16530}," '$1 > 500'",{"type":29,"tag":127,"props":16532,"children":16533},{"style":4927},[16534],{"type":56,"value":16496},{"type":29,"tag":127,"props":16536,"children":16537},{"style":3020},[16538],{"type":56,"value":16539}," sort",{"type":29,"tag":127,"props":16541,"children":16542},{"style":2290},[16543],{"type":56,"value":16544}," -n",{"type":29,"tag":127,"props":16546,"children":16547},{"style":2290},[16548],{"type":56,"value":16549}," -r\n",{"type":29,"tag":48,"props":16551,"children":16552},{},[16553,16555,16560,16562,16566],{"type":56,"value":16554},"You should review this list. If there is something with 10k+ extends, it is a candidate to be flagged as ",{"type":29,"tag":14536,"props":16556,"children":16557},{},[16558],{"type":56,"value":16559},"nodatacow",{"type":56,"value":16561},". 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":29,"tag":14536,"props":16563,"children":16564},{},[16565],{"type":56,"value":16559},{"type":56,"value":16567},", 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":29,"tag":90,"props":16569,"children":16571},{"id":16570},"if-everything-is-fine-you-can-go-ahead-and-defrag-all-files-on-that-list",[16572],{"type":56,"value":16573},"If everything is fine, you can go ahead and defrag all files on that list",{"type":29,"tag":657,"props":16575,"children":16577},{"className":15901,"code":16576,"language":15903,"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",[16578],{"type":29,"tag":670,"props":16579,"children":16580},{"__ignoreMap":7},[16581,16641],{"type":29,"tag":127,"props":16582,"children":16583},{"class":675,"line":676},[16584,16588,16592,16596,16600,16604,16608,16612,16616,16620,16624,16628,16632,16636],{"type":29,"tag":127,"props":16585,"children":16586},{"style":3020},[16587],{"type":56,"value":16446},{"type":29,"tag":127,"props":16589,"children":16590},{"style":718},[16591],{"type":56,"value":16451},{"type":29,"tag":127,"props":16593,"children":16594},{"style":2290},[16595],{"type":56,"value":16456},{"type":29,"tag":127,"props":16597,"children":16598},{"style":2290},[16599],{"type":56,"value":16461},{"type":29,"tag":127,"props":16601,"children":16602},{"style":718},[16603],{"type":56,"value":16466},{"type":29,"tag":127,"props":16605,"children":16606},{"style":4927},[16607],{"type":56,"value":16471},{"type":29,"tag":127,"props":16609,"children":16610},{"style":3020},[16611],{"type":56,"value":16476},{"type":29,"tag":127,"props":16613,"children":16614},{"style":718},[16615],{"type":56,"value":16481},{"type":29,"tag":127,"props":16617,"children":16618},{"style":4927},[16619],{"type":56,"value":16486},{"type":29,"tag":127,"props":16621,"children":16622},{"style":718},[16623],{"type":56,"value":16491},{"type":29,"tag":127,"props":16625,"children":16626},{"style":4927},[16627],{"type":56,"value":16496},{"type":29,"tag":127,"props":16629,"children":16630},{"style":3020},[16631],{"type":56,"value":16501},{"type":29,"tag":127,"props":16633,"children":16634},{"style":718},[16635],{"type":56,"value":16506},{"type":29,"tag":127,"props":16637,"children":16638},{"style":4927},[16639],{"type":56,"value":16640}," |\n",{"type":29,"tag":127,"props":16642,"children":16643},{"class":675,"line":342},[16644,16649,16653,16657,16661,16665,16670,16675,16679,16684,16688,16692,16696,16700,16705,16710,16715,16720,16725],{"type":29,"tag":127,"props":16645,"children":16646},{"style":3020},[16647],{"type":56,"value":16648},"awk",{"type":29,"tag":127,"props":16650,"children":16651},{"style":2290},[16652],{"type":56,"value":16520},{"type":29,"tag":127,"props":16654,"children":16655},{"style":718},[16656],{"type":56,"value":16525},{"type":29,"tag":127,"props":16658,"children":16659},{"style":718},[16660],{"type":56,"value":16530},{"type":29,"tag":127,"props":16662,"children":16663},{"style":4927},[16664],{"type":56,"value":16496},{"type":29,"tag":127,"props":16666,"children":16667},{"style":3020},[16668],{"type":56,"value":16669}," cut",{"type":29,"tag":127,"props":16671,"children":16672},{"style":2290},[16673],{"type":56,"value":16674}," -d",{"type":29,"tag":127,"props":16676,"children":16677},{"style":718},[16678],{"type":56,"value":16525},{"type":29,"tag":127,"props":16680,"children":16681},{"style":2290},[16682],{"type":56,"value":16683}," -f2",{"type":29,"tag":127,"props":16685,"children":16686},{"style":4927},[16687],{"type":56,"value":16486},{"type":29,"tag":127,"props":16689,"children":16690},{"style":718},[16691],{"type":56,"value":16491},{"type":29,"tag":127,"props":16693,"children":16694},{"style":4927},[16695],{"type":56,"value":16496},{"type":29,"tag":127,"props":16697,"children":16698},{"style":3020},[16699],{"type":56,"value":16476},{"type":29,"tag":127,"props":16701,"children":16702},{"style":2290},[16703],{"type":56,"value":16704}," -r",{"type":29,"tag":127,"props":16706,"children":16707},{"style":718},[16708],{"type":56,"value":16709}," btrfs",{"type":29,"tag":127,"props":16711,"children":16712},{"style":718},[16713],{"type":56,"value":16714}," fi",{"type":29,"tag":127,"props":16716,"children":16717},{"style":718},[16718],{"type":56,"value":16719}," defrag",{"type":29,"tag":127,"props":16721,"children":16722},{"style":2290},[16723],{"type":56,"value":16724}," -f",{"type":29,"tag":127,"props":16726,"children":16727},{"style":2290},[16728],{"type":56,"value":16729}," -v\n",{"type":29,"tag":48,"props":16731,"children":16732},{},[16733],{"type":56,"value":16734},"This will print out all filenames that are processed.",{"type":29,"tag":90,"props":16736,"children":16738},{"id":16737},"a-short-explanation-of-the-command",[16739],{"type":56,"value":16740},"A short explanation of the command",{"type":29,"tag":48,"props":16742,"children":16743},{},[16744,16748,16750,16754,16756,16761,16763,16768],{"type":29,"tag":14536,"props":16745,"children":16746},{},[16747],{"type":56,"value":16446},{"type":56,"value":16749}," gets all files on the specified path (/) without descending into other mounted filesystems (-xdev). Then ",{"type":29,"tag":14536,"props":16751,"children":16752},{},[16753],{"type":56,"value":16429},{"type":56,"value":16755}," determines the fragmentation, the ",{"type":29,"tag":14536,"props":16757,"children":16758},{},[16759],{"type":56,"value":16760},"sed",{"type":56,"value":16762}," 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":29,"tag":14536,"props":16764,"children":16765},{},[16766],{"type":56,"value":16767},"defrag",{"type":56,"value":16769}," 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":29,"tag":90,"props":16771,"children":16773},{"id":16772},"have-fun",[16774],{"type":56,"value":16775},"Have fun!",{"type":29,"tag":1826,"props":16777,"children":16778},{},[16779],{"type":56,"value":1830},{"title":7,"searchDepth":342,"depth":342,"links":16781},[16782,16783,16784,16785,16786,16787,16788,16789],{"id":16327,"depth":342,"text":16330},{"id":16345,"depth":342,"text":16348},{"id":16356,"depth":342,"text":16359},{"id":16405,"depth":342,"text":16408},{"id":16416,"depth":342,"text":16419},{"id":16570,"depth":342,"text":16573},{"id":16737,"depth":342,"text":16740},{"id":16772,"depth":342,"text":16775},{"_path":16791,"_dir":354,"_draft":6,"_partial":6,"_locale":7,"slug":518,"teams":16792,"primaryTeam":357,"firstName":16794,"lastName":16795,"prefixTitle":7,"suffixTitle":16796,"education":16797,"role":16802,"workingSince":16803,"inTheCompanySince":16804,"techSkills":16805,"skills":16828,"projects":16841,"contactDetails":16850,"_image":16853,"image":16854,"_id":16855,"_type":454,"title":16856,"_source":354,"_file":16857,"_stem":16858,"_extension":454},"/employees/robert-juzak",[16793,357],"appDev","Robert","Juzak","B.Sc.",[16798],[16799,16800,16801],"Bachelor of Computer Science","Technische Universität Breslau","2016",[371,471,370,373],"2015","2018",[16806,16807,16808,16811,16814,16817,16818,16821,16822,16823,16824,16825,16826],{"name":378,"level":379,"icon":380},{"name":9684,"level":379},{"name":16809,"level":379,"icon":16810},"Kubernetes","/images/Kubernetes.svg",{"name":16812,"level":379,"icon":16813},"PHPUnit","/images/PHP-Unit.svg",{"name":16815,"level":379,"icon":16816},"Portainer","/images/Portainer.svg",{"name":14630,"level":379},{"name":16819,"level":379,"icon":16820},"Sonarqube","/images/Sonarqube.svg",{"name":382,"level":379,"icon":383},{"name":411,"level":405,"icon":412},{"name":414,"level":405,"icon":415},{"name":395,"level":405},{"name":401,"level":405,"icon":402},{"name":16827,"level":405,"icon":421},"VueJS",[16829,16830,16831,16832,16834,16836,16838,16839,16840],{"name":5262,"level":379},{"name":433,"level":379},{"name":357,"level":379},{"name":16833,"level":379},"testDrivenBugfix",{"name":16835,"level":379},"testDrivenDevelopment",{"name":16837,"level":405},"accessibility",{"name":23,"level":405},{"name":429,"level":405},{"name":431,"level":405},[16842,16846,16848],{"project":439,"position":16843},[16844,16845],"Dev-Ops","Frontend Developer",{"project":16847,"position":16845},"Huawei-Calibration-aaS",{"project":16849,"position":16845},"Huawei-Inspect-3D",{"eMail":16851,"phone":16852,"visibility":450},"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":16860,"_dir":354,"_draft":6,"_partial":6,"_locale":7,"slug":600,"teams":16861,"primaryTeam":16793,"firstName":16862,"lastName":16863,"prefixTitle":16864,"suffixTitle":7,"executiveRole":16865,"education":16866,"role":16873,"workingSince":364,"inTheCompanySince":16870,"techSkills":16875,"skills":16893,"projects":16904,"contactDetails":16908,"certifications":16911,"image":16917,"_id":16918,"_type":454,"title":16919,"_source":354,"_file":16920,"_stem":16921,"_extension":454},"/employees/jens-bornschein",[16793],"Jens","Bornschein","Dr. Ing.","Projektmanager | Consultant",[16867,16871],[16868,16869,16870],"Doktor-Ingenieur der Informatik","TU Dresden","2020",[16872,16869,364],"Diplom-Medieninformatiker (TU)",[470,371,471,16874,16837,373],"UI/UX",[16876,16877,16878,16879,16880,16881,16882,16885,16888,16891],{"name":395,"level":379},{"name":408,"level":379,"icon":409},{"name":411,"level":405,"icon":412},{"name":414,"level":405,"icon":415},{"name":420,"level":405,"icon":421},{"name":397,"level":405},{"name":16883,"level":379,"icon":16884},"Adobe Photoshop","/images/adobeps-logo.svg",{"name":16886,"level":379,"icon":16887},"Adobe Illustrator","/images/adobeai-logo.svg",{"name":16889,"level":405,"icon":16890},"Adobe XD","/images/adobexd-logo.svg",{"name":16892,"level":405},"Gitlab",[16894,16895,16896,16897,16899,16901,16902],{"name":483,"level":379},{"name":16837,"level":379},{"name":16874,"level":379},{"name":16898,"level":405},"consulting",{"name":16900,"level":405},"scrum",{"name":431,"level":405},{"name":16903,"level":405},"training",[16905,16907],{"project":441,"position":16906},"project manager",{"project":446,"position":16906},{"eMail":16909,"phone":16910,"visibility":450},"jens.bornschein@helmundwalter.de","+49 351 799 035 24",[16912],{"image":16913,"link":16914,"title":16915,"pdf":16916},"/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":353,"_dir":354,"_draft":6,"_partial":6,"_locale":7,"slug":170,"teams":16923,"primaryTeam":357,"firstName":358,"lastName":359,"prefixTitle":7,"suffixTitle":7,"education":16924,"executiveRole":365,"role":16926,"workingSince":374,"inTheCompanySince":375,"techSkills":16927,"skills":16944,"projects":16951,"contactDetails":16957,"_image":451,"image":452,"_id":453,"_type":454,"title":455,"_source":354,"_file":456,"_stem":457,"_extension":454},[356,357],[16925],[362,363,364],[367,368,357,369,370,371,372,373],[16928,16929,16930,16931,16932,16933,16934,16935,16936,16937,16938,16939,16940,16941,16942,16943],{"name":378,"level":379,"icon":380},{"name":382,"level":379,"icon":383},{"name":385,"level":379},{"name":387,"level":379,"icon":388},{"name":390,"level":379},{"name":392,"level":379,"icon":393},{"name":395,"level":379},{"name":397,"level":379},{"name":399,"level":379},{"name":401,"level":379,"icon":402},{"name":404,"level":405,"icon":406},{"name":408,"level":405,"icon":409},{"name":411,"level":405,"icon":412},{"name":414,"level":405,"icon":415},{"name":417,"level":405,"icon":418},{"name":420,"level":405,"icon":421},[16945,16946,16947,16948,16949,16950],{"name":424,"level":379},{"name":426,"level":379},{"name":23,"level":379},{"name":429,"level":379},{"name":431,"level":379},{"name":433,"level":405},[16952,16953,16954,16955,16956],{"project":436,"position":437},{"project":439,"position":437},{"project":441,"position":437},{"project":443,"position":444},{"project":446,"position":437},{"eMail":448,"phone":449,"visibility":450},1782284065958]