[{"data":1,"prerenderedAt":23514},["ShallowReactive",2],{"content-query-PW6sk2q5O8":3,"content-query-GCsGFnjSrZ":273,"content-query-DexhC6jnXN":1492,"content-query-pY5GjeCLfZ":3854,"content-query-lDWCmQfCc3":4929,"content-query-TPh1lFGN9c":9256,"content-query-AVfm838iln":10727,"content-query-9RJBkyXCE2":11258,"content-query-8xB9vY4DHX":12761,"content-query-abDu7ax1qT":15671,"content-query-yliWk2uBx7":16951,"content-query-Dmf1CQj4Id":18193,"content-query-t20WiKE4uI":18264,"content-query-ViehLtZIqO":18824,"content-query-Fqgo9f8ijK":19326,"content-query-xGvaff9H60":19796,"content-query-MZ7t3ppMsS":20024,"content-query-D416F8uRcL":20542,"content-query-UXS9ccDnv4":20718,"content-query-WAs8VEyF1n":22263,"content-query-BlErk6DflP":23104,"content-query-pE5ZzlS1MN":23143,"content-query-KtO3wftRle":23250,"content-query-vhr2h3d1hs":23339,"content-query-1PFeYVQSzn":23410,"content-query-EC7xcJJMAZ":23481},[4,26,40,50,60,71,82,98,110,121,132,148,161,173,184,195,208,220,235,248,260],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"author":11,"image":12,"releaseDate":13,"blogCategories":14,"articleTags":17,"tags":18,"_type":20,"_id":21,"_source":22,"_file":23,"_stem":24,"_extension":25},"/en/blog/traefik-magic","blog",false,"","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",[15,16],"What moves us","DevOps",[16],[19],"devops","markdown","common:en:blog:21.traefik-magic.md","common","en/blog/21.traefik-magic.md","en/blog/21.traefik-magic","md",{"_path":27,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":28,"description":29,"author":11,"image":12,"releaseDate":30,"blogCategories":31,"articleTags":32,"tags":35,"_type":20,"_id":37,"_source":22,"_file":38,"_stem":39,"_extension":25},"/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","2026-02-26",[15,16],[16,33,34],"Open Source","Shopware",[36,19],"shopware","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":41,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":42,"description":43,"author":11,"image":12,"releaseDate":30,"blogCategories":44,"articleTags":45,"tags":46,"_type":20,"_id":47,"_source":22,"_file":48,"_stem":49,"_extension":25},"/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",[15,16],[16,33,34],[36,19],"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":51,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":52,"description":53,"author":11,"image":12,"releaseDate":30,"blogCategories":54,"articleTags":55,"tags":56,"_type":20,"_id":57,"_source":22,"_file":58,"_stem":59,"_extension":25},"/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",[15,16],[16,33,34],[36,19],"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":61,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":62,"description":63,"author":11,"image":12,"releaseDate":64,"blogCategories":65,"articleTags":66,"tags":67,"_type":20,"_id":68,"_source":22,"_file":69,"_stem":70,"_extension":25},"/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",[15,16],[16,33],[19],"common:en:blog:17.gitops-docker-renovate.md","en/blog/17.gitops-docker-renovate.md","en/blog/17.gitops-docker-renovate",{"_path":72,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":73,"description":74,"author":11,"image":12,"releaseDate":75,"blogCategories":76,"articleTags":77,"tags":78,"_type":20,"_id":79,"_source":22,"_file":80,"_stem":81,"_extension":25},"/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",[15,16],[16,33],[36,19],"common:en:blog:16.shopware-renovate-bot.md","en/blog/16.shopware-renovate-bot.md","en/blog/16.shopware-renovate-bot",{"_path":83,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":84,"description":85,"author":86,"image":87,"releaseDate":88,"blogCategories":89,"articleTags":91,"tags":93,"_type":20,"_id":95,"_source":22,"_file":96,"_stem":97,"_extension":25},"/en/blog/accessibility-legal-statement-template","Accessibility Statement (AS) – How to Implement the German Accessibility Strengthening Act and Avoid Potential Warnings","Accessibility Statement according to German BFSG: Template and guide for accessibility declarations. Protect yourself from warnings with our template for an individual Accessibility Strengthening Act. The provisions of the German Accessibility Strengthening Act must be implemented to avoid penalties. You can protect yourself from regulatory enforcement procedures by providing a detailed accessibility statement. You can find a commented template for this in this blog post.","jens-bornschein","/images/Accessibility.png","2025-09-05",[90],"What Moves Us",[92],"Accessibility",[94],"frontend","common:en:blog:15.accessibility-legal-statement-template.md","en/blog/15.accessibility-legal-statement-template.md","en/blog/15.accessibility-legal-statement-template",{"_path":99,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":100,"description":101,"author":11,"image":12,"releaseDate":102,"blogCategories":103,"articleTags":105,"tags":106,"_type":20,"_id":107,"_source":22,"_file":108,"_stem":109,"_extension":25},"/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",[15,104],"Infrastructure",[16],[19],"common:en:blog:14.gitlab-behind-traefik.md","en/blog/14.gitlab-behind-traefik.md","en/blog/14.gitlab-behind-traefik",{"_path":111,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":112,"description":113,"author":86,"image":87,"releaseDate":114,"blogCategories":115,"articleTags":116,"tags":117,"_type":20,"_id":118,"_source":22,"_file":119,"_stem":120,"_extension":25},"/en/blog/accessibility-will-be-recommended","Accessibility Empowerment Act - Barrier-free Web Services Required for Almost Everyone from July 2025!","From 28th June 2025, Germany's Accessibility Empowerment Act (BFSG) comes into effect. For the first time, this law obliges private companies to offer specific digital products and services in an accessible format. For many operators of websites, online shops and apps, this means that they must optimize their digital offers for accessibility by the deadline.","2025-04-13",[15],[92],[94],"common:en:blog:13.accessibility-will-be-recommended.md","en/blog/13.accessibility-will-be-recommended.md","en/blog/13.accessibility-will-be-recommended",{"_path":122,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":123,"description":124,"author":86,"image":12,"releaseDate":125,"blogCategories":126,"articleTags":127,"tags":128,"_type":20,"_id":129,"_source":22,"_file":130,"_stem":131,"_extension":25},"/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.","2025-03-31",[90],[16],[19],"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":133,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":134,"description":135,"author":136,"image":137,"releaseDate":138,"blogCategories":139,"articleTags":140,"tags":142,"_type":20,"_id":145,"_source":22,"_file":146,"_stem":147,"_extension":25},"/en/blog/amazon-mws-sp-api-wrapper","Amazon MWS to SP API Wrapper","We have released a wrapper that converts Amazon MWS to SP API, offering developers with outdated systems a simple solution. This open-source project provides a practical alternative to redevelopment and supports the continuation of existing applications.","bernd-helm","/blog/thumbnails/AWS.svg","2024-02-21",[15,16],[141,33],"Amazon",[143,144],"e-commerce","backend","common:en:blog:11.amazon-mws-sp-api-wrapper.md","en/blog/11.amazon-mws-sp-api-wrapper.md","en/blog/11.amazon-mws-sp-api-wrapper",{"_path":149,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":150,"description":151,"author":136,"image":152,"releaseDate":153,"blogCategories":154,"articleTags":155,"tags":157,"_type":20,"_id":158,"_source":22,"_file":159,"_stem":160,"_extension":25},"/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",[15,16],[156],"VPN",[19],"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":162,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":163,"description":164,"author":136,"image":165,"releaseDate":166,"blogCategories":167,"articleTags":168,"tags":169,"_type":20,"_id":170,"_source":22,"_file":171,"_stem":172,"_extension":25},"/en/blog/shopware-5-parallel-thumbnail-generation","Shopware 5 – High-Speed Parallel Thumbnail Generation","How to tune the integrated SW5 mechanism to work more then 22 times faster! Shopware 5 - parallel thumbnail generation after moving a Shopware 5 system to another server. We had a customer with 400k images and 1600k thumbnails that needed to move from an old HDD based server to a new SSD …","/images/shopware.svg","2021-04-29",[34,16],[156],[36],"common:en:blog:9.shopware-5-parallel-thumbnail-generation.md","en/blog/9.shopware-5-parallel-thumbnail-generation.md","en/blog/9.shopware-5-parallel-thumbnail-generation",{"_path":174,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":175,"description":176,"author":136,"image":177,"releaseDate":178,"blogCategories":179,"tags":180,"_type":20,"_id":181,"_source":22,"_file":182,"_stem":183,"_extension":25},"/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",[15,104],[19],"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":185,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":186,"description":187,"author":136,"image":188,"releaseDate":189,"blogCategories":190,"tags":191,"_type":20,"_id":192,"_source":22,"_file":193,"_stem":194,"_extension":25},"/en/blog/proper-chroot-in-rescue-mode-using-arch-chroot","Proper CHROOT in rescue mode using arch-chroot","Most Sysadmins know how to setup a basic chroot on a mounted filesystem (mount-binding dev, proc and sys) but this does not work in any case; for a complete chroot setup you would aso need dev/pts dev/shm, run, tmp, a working resolve.conf and more. After you have set it up, and you want to bring it ...","/images/linux_os-mono.svg","2020-04-17",[15,104],[19],"common:en:blog:7.proper-chroot-in-rescue-mode-using-arch-chroot.md","en/blog/7.proper-chroot-in-rescue-mode-using-arch-chroot.md","en/blog/7.proper-chroot-in-rescue-mode-using-arch-chroot",{"_path":196,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":197,"description":198,"author":136,"image":199,"releaseDate":200,"blogCategories":201,"articleTags":202,"tags":204,"_type":20,"_id":205,"_source":22,"_file":206,"_stem":207,"_extension":25},"/en/blog/why-we-dont-use-samsung-nvme-pro-ssds-anymore","Why we dont use Samsung NVME Pro SSDs anymore","When it comes to buying an NVME SSD for a software developer workstation, you have a choice: buy a cheap one or an expensive one. So far I've gone for the more expensive ones because they promised better performance and longer life - now I see how wrong I was...","/blog/thumbnails/SSD_white.png","2020-04-16",[15,104],[203],"SSD",[19],"common:en:blog:6.why-we-dont-use-samsung-nvme-pro-ssds-anymore.md","en/blog/6.why-we-dont-use-samsung-nvme-pro-ssds-anymore.md","en/blog/6.why-we-dont-use-samsung-nvme-pro-ssds-anymore",{"_path":209,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":210,"description":211,"author":136,"image":212,"releaseDate":213,"blogCategories":214,"articleTags":215,"tags":216,"_type":20,"_id":217,"_source":22,"_file":218,"_stem":219,"_extension":25},"/en/blog/raid5-vs-raid10-performance-benchmark-mdadm","RAID5 vs Raid10 Performance Benchmark MDADM","Comment and investigation in RAID performance RAID 5 vs RAID10 has been discussed for ages; it's common knowledge that RAID10 offers better performance – but how much depends on the actual implementation, hardware and use-case. I just got a server with 4 x 16TB …","/blog/thumbnails/RAID_white.png","2019-11-06",[15,104],[203],[19],"common:en:blog:5.raid5-vs-raid10-performance-benchmark-mdadm.md","en/blog/5.raid5-vs-raid10-performance-benchmark-mdadm.md","en/blog/5.raid5-vs-raid10-performance-benchmark-mdadm",{"_path":221,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":222,"description":223,"author":224,"image":225,"releaseDate":226,"blogCategories":227,"articleTags":229,"tags":230,"_type":20,"_id":232,"_source":22,"_file":233,"_stem":234,"_extension":25},"/en/blog/riak-compact-eleveldb-tombstones-and-reclaim-disk-space","RIAK compact e/leveldb tombstones and reclaim disk space","When attempting to reclaim disk space, deleting data may seem like the obvious first step. However, in Riak this is not necessarily the best thing to do if the disk is nearly full...","daniel-walter","/blog/thumbnails/RIAK_white.png","2017-09-26",[15,228],"Databases",[203],[231,19],"databases","common:en:blog:4.riak-compact-eleveldb-tombstones-and-reclaim-disk-space.md","en/blog/4.riak-compact-eleveldb-tombstones-and-reclaim-disk-space.md","en/blog/4.riak-compact-eleveldb-tombstones-and-reclaim-disk-space",{"_path":236,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":237,"description":238,"author":136,"image":239,"releaseDate":240,"blogCategories":241,"articleTags":243,"tags":244,"_type":20,"_id":245,"_source":22,"_file":246,"_stem":247,"_extension":25},"/en/blog/next-gen-backup-with-btrfs-snapshots-for-root-fs-and-databases","Next-Gen Backup with BTRFS Snapshots for Root-Fs and Databases","next-gen backup with BTRFS snapshots for root-fs and databases linux. What it is good for. This article is about using BTRFS snapshots as backup solution, usable for databases and full root partition backups. This is not a detailed step-by-step guide and requires some linux skills. This post aims to share my experiences and save …","/blog/thumbnails/BTRFS.png","2017-09-06",[15,242],"Database",[203],[19,231],"common:en:blog:3.next-gen-backup-with-btrfs-snapshots-for-root-fs-and-databases.md","en/blog/3.next-gen-backup-with-btrfs-snapshots-for-root-fs-and-databases.md","en/blog/3.next-gen-backup-with-btrfs-snapshots-for-root-fs-and-databases",{"_path":249,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":250,"description":251,"image":252,"author":224,"releaseDate":253,"blogCategories":254,"articleTags":255,"tags":256,"_type":20,"_id":257,"_source":22,"_file":258,"_stem":259,"_extension":25},"/en/blog/basho-riak-documentation-mirror","Basho RIAK KV TS CS Documentation Mirror","As the Basho RIAK KV TS CS documentation is unreachable at the moment, we have created a mirror ...","/blog/thumbnails/RIAK.png","2017-08-08",[15,242],[203],[231,19],"common:en:blog:2.basho-riak-documentation-mirror.md","en/blog/2.basho-riak-documentation-mirror.md","en/blog/2.basho-riak-documentation-mirror",{"_path":261,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":262,"description":263,"image":264,"author":136,"releaseDate":265,"blogCategories":266,"articleTags":268,"tags":269,"_type":20,"_id":270,"_source":22,"_file":271,"_stem":272,"_extension":25},"/en/blog/our-loved-php-cpp-java-scala-dhtmlx-infinidb-zend","PHP & Co.: Our favorites","For developers, for store operators - We don't work with arbitrary frameworks, libraries, plugins and programming languages. We love it professionally. Software created at Helm & Walter should be powerful and lean. Here are our favorites: PHP (recursive acronym for PHP: hypertext preprocessor) is a widely used programming language for ...","/blog/thumbnails/PHP.png","2017-06-27",[15,267],"Frontend",[267],[144,231],"common:en:blog:1.our-loved-php-cpp-java-scala-dhtmlx-infinidb-zend.md","en/blog/1.our-loved-php-cpp-java-scala-dhtmlx-infinidb-zend.md","en/blog/1.our-loved-php-cpp-java-scala-dhtmlx-infinidb-zend",{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"author":11,"image":12,"releaseDate":13,"blogCategories":274,"articleTags":275,"tags":276,"body":277,"_type":20,"_id":21,"_source":22,"_file":23,"_stem":24,"_extension":25},[15,16],[16],[19],{"type":278,"children":279,"toc":1482},"root",[280,295,300,449,454,529,536,565,570,594,607,626,632,649,750,755,760,785,831,835,840,1206,1211,1247,1254,1262,1313,1317,1324,1352,1358,1363,1369,1374,1386,1394,1400,1412,1476],{"type":281,"tag":282,"props":283,"children":284},"element","p",{},[285,293],{"type":281,"tag":286,"props":287,"children":289},"a",{"href":288},"https://doc.traefik.io/traefik/",[290],{"type":291,"value":292},"text","Traefik",{"type":291,"value":294}," is a reverse proxy with excellent docker integration. It uses labeln attached to containers to route traffic to them.",{"type":281,"tag":282,"props":296,"children":297},{},[298],{"type":291,"value":299},"A common label set looks similar to this:",{"type":281,"tag":301,"props":302,"children":313},"pre",{"code":303,"filename":304,"highlights":305,"language":311,"meta":8,"className":312,"style":8},"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",[306,307,308,309,310],5,6,7,8,9,"yaml","language-yaml shiki shiki-themes github-dark github-dark monokai",[314],{"type":281,"tag":315,"props":316,"children":317},"code",{"__ignoreMap":8},[318,336,349,369,382,397,410,423,436],{"type":281,"tag":319,"props":320,"children":323},"span",{"class":321,"line":322},"line",1,[324,330],{"type":281,"tag":319,"props":325,"children":327},{"style":326},"--shiki-default:#85E89D;--shiki-dark:#85E89D;--shiki-sepia:#F92672",[328],{"type":291,"value":329},"services",{"type":281,"tag":319,"props":331,"children":333},{"style":332},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2",[334],{"type":291,"value":335},":\n",{"type":281,"tag":319,"props":337,"children":339},{"class":321,"line":338},2,[340,345],{"type":281,"tag":319,"props":341,"children":342},{"style":326},[343],{"type":291,"value":344},"  whoami",{"type":281,"tag":319,"props":346,"children":347},{"style":332},[348],{"type":291,"value":335},{"type":281,"tag":319,"props":350,"children":352},{"class":321,"line":351},3,[353,358,363],{"type":281,"tag":319,"props":354,"children":355},{"style":326},[356],{"type":291,"value":357},"    image",{"type":281,"tag":319,"props":359,"children":360},{"style":332},[361],{"type":291,"value":362},": ",{"type":281,"tag":319,"props":364,"children":366},{"style":365},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74",[367],{"type":291,"value":368},"traefik/whoami\n",{"type":281,"tag":319,"props":370,"children":372},{"class":321,"line":371},4,[373,378],{"type":281,"tag":319,"props":374,"children":375},{"style":326},[376],{"type":291,"value":377},"    labels",{"type":281,"tag":319,"props":379,"children":380},{"style":332},[381],{"type":291,"value":335},{"type":281,"tag":319,"props":383,"children":386},{"class":384,"line":306},[321,385],"highlight",[387,392],{"type":281,"tag":319,"props":388,"children":389},{"style":332},[390],{"type":291,"value":391},"      - ",{"type":281,"tag":319,"props":393,"children":394},{"style":365},[395],{"type":291,"value":396},"\"traefik.enable=true\"\n",{"type":281,"tag":319,"props":398,"children":400},{"class":399,"line":307},[321,385],[401,405],{"type":281,"tag":319,"props":402,"children":403},{"style":332},[404],{"type":291,"value":391},{"type":281,"tag":319,"props":406,"children":407},{"style":365},[408],{"type":291,"value":409},"\"traefik.http.routers.whoami.rule=Host(`whoami.example.com`)\"\n",{"type":281,"tag":319,"props":411,"children":413},{"class":412,"line":308},[321,385],[414,418],{"type":281,"tag":319,"props":415,"children":416},{"style":332},[417],{"type":291,"value":391},{"type":281,"tag":319,"props":419,"children":420},{"style":365},[421],{"type":291,"value":422},"\"traefik.http.routers.whoami.entrypoints=websecure\"\n",{"type":281,"tag":319,"props":424,"children":426},{"class":425,"line":309},[321,385],[427,431],{"type":281,"tag":319,"props":428,"children":429},{"style":332},[430],{"type":291,"value":391},{"type":281,"tag":319,"props":432,"children":433},{"style":365},[434],{"type":291,"value":435},"\"traefik.http.routers.whoami.tls=true\"\n",{"type":281,"tag":319,"props":437,"children":439},{"class":438,"line":310},[321,385],[440,444],{"type":281,"tag":319,"props":441,"children":442},{"style":332},[443],{"type":291,"value":391},{"type":281,"tag":319,"props":445,"children":446},{"style":365},[447],{"type":291,"value":448},"\"traefik.http.routers.whoami.tls.certresolver=letsencrypt\"\n",{"type":281,"tag":282,"props":450,"children":451},{},[452],{"type":291,"value":453},"In this example:",{"type":281,"tag":455,"props":456,"children":457},"ul",{},[458,470,486,491,503,508],{"type":281,"tag":459,"props":460,"children":461},"li",{},[462,468],{"type":281,"tag":315,"props":463,"children":465},{"className":464},[],[466],{"type":291,"value":467},"whoami",{"type":291,"value":469}," the name of the \"main\" service (2)",{"type":281,"tag":459,"props":471,"children":472},{},[473,478,480],{"type":281,"tag":315,"props":474,"children":476},{"className":475},[],[477],{"type":291,"value":467},{"type":291,"value":479}," the also the default ",{"type":281,"tag":286,"props":481,"children":483},{"href":482},"https://docs.docker.com/compose/how-tos/project-name/",[484],{"type":291,"value":485},"compose project name",{"type":281,"tag":459,"props":487,"children":488},{},[489],{"type":291,"value":490},"Traefik is activated (5)",{"type":281,"tag":459,"props":492,"children":493},{},[494,496,501],{"type":291,"value":495},"It is exposed under ",{"type":281,"tag":315,"props":497,"children":499},{"className":498},[],[500],{"type":291,"value":467},{"type":291,"value":502}," subdomain (6)",{"type":281,"tag":459,"props":504,"children":505},{},[506],{"type":291,"value":507},"It is served over https (7)",{"type":281,"tag":459,"props":509,"children":510},{},[511,513,519,521,527],{"type":291,"value":512},"A preconfigured certresolver named ",{"type":281,"tag":315,"props":514,"children":516},{"className":515},[],[517],{"type":291,"value":518},"letsencrypt",{"type":291,"value":520}," is used for ",{"type":281,"tag":315,"props":522,"children":524},{"className":523},[],[525],{"type":291,"value":526},"tls",{"type":291,"value":528}," (8-9)",{"type":281,"tag":530,"props":531,"children":533},"h2",{"id":532},"the-problem",[534],{"type":291,"value":535},"The problem",{"type":281,"tag":282,"props":537,"children":538},{},[539,541,547,549,555,557,563],{"type":291,"value":540},"In my ",{"type":281,"tag":286,"props":542,"children":544},{"href":543},"/blog/gitops-docker-renovate",[545],{"type":291,"value":546},"other post about gitops with docker",{"type":291,"value":548}," I introduced a concept of using ",{"type":281,"tag":315,"props":550,"children":552},{"className":551},[],[553],{"type":291,"value":554},"git",{"type":291,"value":556},"\nas the sources of truth for docker deployments using ",{"type":281,"tag":286,"props":558,"children":560},{"href":559},"https://docs.docker.com/compose/",[561],{"type":291,"value":562},"docker compose",{"type":291,"value":564},".",{"type":281,"tag":282,"props":566,"children":567},{},[568],{"type":291,"value":569},"Now there are some requirements to this approach:",{"type":281,"tag":455,"props":571,"children":572},{},[573,584],{"type":281,"tag":459,"props":574,"children":575},{},[576,578],{"type":291,"value":577},"every stack is exposer under ",{"type":281,"tag":315,"props":579,"children":581},{"className":580},[],[582],{"type":291,"value":583},"\u003Cstack_name>.\u003Cyour_domain>",{"type":281,"tag":459,"props":585,"children":586},{},[587,589],{"type":291,"value":588},"every stack is protected with ",{"type":281,"tag":315,"props":590,"children":592},{"className":591},[],[593],{"type":291,"value":526},{"type":281,"tag":282,"props":595,"children":596},{},[597,599,605],{"type":291,"value":598},"We could of course edit every ",{"type":281,"tag":315,"props":600,"children":602},{"className":601},[],[603],{"type":291,"value":604},"docker-compose.yaml",{"type":291,"value":606}," file and add the required labels, but it quickly becomes obvious,\nthat all the labels are the same!",{"type":281,"tag":608,"props":609,"children":610},"ol",{},[611,616,621],{"type":281,"tag":459,"props":612,"children":613},{},[614],{"type":291,"value":615},"Enable Traefik",{"type":281,"tag":459,"props":617,"children":618},{},[619],{"type":291,"value":620},"Assign a subdomain",{"type":281,"tag":459,"props":622,"children":623},{},[624],{"type":291,"value":625},"Enable HTTPS",{"type":281,"tag":530,"props":627,"children":629},{"id":628},"the-solution",[630],{"type":291,"value":631},"The solution",{"type":281,"tag":282,"props":633,"children":634},{},[635,637,647],{"type":291,"value":636},"By using ",{"type":281,"tag":286,"props":638,"children":640},{"href":639},"https://docs.docker.com/compose/how-tos/environment-variables/envvars/#compose_project_name",[641],{"type":281,"tag":315,"props":642,"children":644},{"className":643},[],[645],{"type":291,"value":646},"$COMPOSE_PROJECT_NAME",{"type":291,"value":648},"\nvariable we can create a more generic template.\nThis ensures that the Traefik rules are consistent.",{"type":281,"tag":301,"props":650,"children":653},{"code":651,"filename":652,"language":311,"meta":8,"className":312,"style":8},"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",[654],{"type":281,"tag":315,"props":655,"children":656},{"__ignoreMap":8},[657,668,680,691,702,714,726,738],{"type":281,"tag":319,"props":658,"children":659},{"class":321,"line":322},[660,664],{"type":281,"tag":319,"props":661,"children":662},{"style":326},[663],{"type":291,"value":329},{"type":281,"tag":319,"props":665,"children":666},{"style":332},[667],{"type":291,"value":335},{"type":281,"tag":319,"props":669,"children":670},{"class":321,"line":338},[671,676],{"type":281,"tag":319,"props":672,"children":673},{"style":326},[674],{"type":291,"value":675},"  \u003Cmain_service>",{"type":281,"tag":319,"props":677,"children":678},{"style":332},[679],{"type":291,"value":335},{"type":281,"tag":319,"props":681,"children":682},{"class":321,"line":351},[683,687],{"type":281,"tag":319,"props":684,"children":685},{"style":326},[686],{"type":291,"value":377},{"type":281,"tag":319,"props":688,"children":689},{"style":332},[690],{"type":291,"value":335},{"type":281,"tag":319,"props":692,"children":693},{"class":321,"line":371},[694,698],{"type":281,"tag":319,"props":695,"children":696},{"style":332},[697],{"type":291,"value":391},{"type":281,"tag":319,"props":699,"children":700},{"style":365},[701],{"type":291,"value":396},{"type":281,"tag":319,"props":703,"children":704},{"class":321,"line":306},[705,709],{"type":281,"tag":319,"props":706,"children":707},{"style":332},[708],{"type":291,"value":391},{"type":281,"tag":319,"props":710,"children":711},{"style":365},[712],{"type":291,"value":713},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.rule=Host(`\u003Cstack_name>.example.com`)\"\n",{"type":281,"tag":319,"props":715,"children":716},{"class":321,"line":307},[717,721],{"type":281,"tag":319,"props":718,"children":719},{"style":332},[720],{"type":291,"value":391},{"type":281,"tag":319,"props":722,"children":723},{"style":365},[724],{"type":291,"value":725},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.entrypoints=websecure\"\n",{"type":281,"tag":319,"props":727,"children":728},{"class":321,"line":308},[729,733],{"type":281,"tag":319,"props":730,"children":731},{"style":332},[732],{"type":291,"value":391},{"type":281,"tag":319,"props":734,"children":735},{"style":365},[736],{"type":291,"value":737},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls=true\"\n",{"type":281,"tag":319,"props":739,"children":740},{"class":321,"line":309},[741,745],{"type":281,"tag":319,"props":742,"children":743},{"style":332},[744],{"type":291,"value":391},{"type":281,"tag":319,"props":746,"children":747},{"style":365},[748],{"type":291,"value":749},"\"traefik.http.routers.$COMPOSE_PROJECT_NAME.tls.certresolver=letsencrypt\"\n",{"type":281,"tag":282,"props":751,"children":752},{},[753],{"type":291,"value":754},"The good news is that Traefik lets us configure some defaults that will cover the above boilerplate!",{"type":281,"tag":282,"props":756,"children":757},{},[758],{"type":291,"value":759},"Let's us define two simple conventions:",{"type":281,"tag":608,"props":761,"children":762},{},[763,774],{"type":281,"tag":459,"props":764,"children":765},{},[766,772],{"type":281,"tag":315,"props":767,"children":769},{"className":768},[],[770],{"type":291,"value":771},"app",{"type":291,"value":773}," is the main container, where Traefik will route the traffic",{"type":281,"tag":459,"props":775,"children":776},{},[777,783],{"type":281,"tag":315,"props":778,"children":780},{"className":779},[],[781],{"type":291,"value":782},"\u003Cstack_name>",{"type":291,"value":784}," (the compose project name) is the subdomain",{"type":281,"tag":301,"props":786,"children":789},{"code":787,"filename":304,"language":311,"meta":788,"className":312,"style":8},"services:\n  app:\n    image: traefik/whoami\n","(1)",[790],{"type":281,"tag":315,"props":791,"children":792},{"__ignoreMap":8},[793,804,816],{"type":281,"tag":319,"props":794,"children":795},{"class":321,"line":322},[796,800],{"type":281,"tag":319,"props":797,"children":798},{"style":326},[799],{"type":291,"value":329},{"type":281,"tag":319,"props":801,"children":802},{"style":332},[803],{"type":291,"value":335},{"type":281,"tag":319,"props":805,"children":806},{"class":321,"line":338},[807,812],{"type":281,"tag":319,"props":808,"children":809},{"style":326},[810],{"type":291,"value":811},"  app",{"type":281,"tag":319,"props":813,"children":814},{"style":332},[815],{"type":291,"value":335},{"type":281,"tag":319,"props":817,"children":818},{"class":321,"line":351},[819,823,827],{"type":281,"tag":319,"props":820,"children":821},{"style":326},[822],{"type":291,"value":357},{"type":281,"tag":319,"props":824,"children":825},{"style":332},[826],{"type":291,"value":362},{"type":281,"tag":319,"props":828,"children":829},{"style":365},[830],{"type":291,"value":368},{"type":281,"tag":832,"props":833,"children":834},"hr",{},[],{"type":281,"tag":282,"props":836,"children":837},{},[838],{"type":291,"value":839},"Now let's configure traefik to do \"the magic\"",{"type":281,"tag":301,"props":841,"children":845},{"code":842,"filename":843,"language":311,"meta":844,"className":312,"style":8},"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)",[846],{"type":281,"tag":315,"props":847,"children":848},{"__ignoreMap":8},[849,861,873,881,892,904,921,938,954,971,984,997,1010,1023,1036,1046,1059,1072,1081,1094,1107,1120,1128,1141,1154,1167,1180,1193],{"type":281,"tag":319,"props":850,"children":851},{"class":321,"line":322},[852,857],{"type":281,"tag":319,"props":853,"children":854},{"style":326},[855],{"type":291,"value":856},"volumes",{"type":281,"tag":319,"props":858,"children":859},{"style":332},[860],{"type":291,"value":335},{"type":281,"tag":319,"props":862,"children":863},{"class":321,"line":338},[864,869],{"type":281,"tag":319,"props":865,"children":866},{"style":326},[867],{"type":291,"value":868},"  letsencrypt",{"type":281,"tag":319,"props":870,"children":871},{"style":332},[872],{"type":291,"value":335},{"type":281,"tag":319,"props":874,"children":875},{"class":321,"line":351},[876],{"type":281,"tag":319,"props":877,"children":878},{"style":332},[879],{"type":291,"value":880},"    \n",{"type":281,"tag":319,"props":882,"children":883},{"class":321,"line":371},[884,888],{"type":281,"tag":319,"props":885,"children":886},{"style":326},[887],{"type":291,"value":329},{"type":281,"tag":319,"props":889,"children":890},{"style":332},[891],{"type":291,"value":335},{"type":281,"tag":319,"props":893,"children":894},{"class":321,"line":306},[895,900],{"type":281,"tag":319,"props":896,"children":897},{"style":326},[898],{"type":291,"value":899},"  traefik",{"type":281,"tag":319,"props":901,"children":902},{"style":332},[903],{"type":291,"value":335},{"type":281,"tag":319,"props":905,"children":906},{"class":321,"line":307},[907,912,916],{"type":281,"tag":319,"props":908,"children":909},{"style":326},[910],{"type":291,"value":911},"    container_name",{"type":281,"tag":319,"props":913,"children":914},{"style":332},[915],{"type":291,"value":362},{"type":281,"tag":319,"props":917,"children":918},{"style":365},[919],{"type":291,"value":920},"traefik\n",{"type":281,"tag":319,"props":922,"children":923},{"class":321,"line":308},[924,929,933],{"type":281,"tag":319,"props":925,"children":926},{"style":326},[927],{"type":291,"value":928},"    restart",{"type":281,"tag":319,"props":930,"children":931},{"style":332},[932],{"type":291,"value":362},{"type":281,"tag":319,"props":934,"children":935},{"style":365},[936],{"type":291,"value":937},"always\n",{"type":281,"tag":319,"props":939,"children":940},{"class":321,"line":309},[941,945,949],{"type":281,"tag":319,"props":942,"children":943},{"style":326},[944],{"type":291,"value":357},{"type":281,"tag":319,"props":946,"children":947},{"style":332},[948],{"type":291,"value":362},{"type":281,"tag":319,"props":950,"children":951},{"style":365},[952],{"type":291,"value":953},"traefik:3\n",{"type":281,"tag":319,"props":955,"children":956},{"class":321,"line":310},[957,962,966],{"type":281,"tag":319,"props":958,"children":959},{"style":326},[960],{"type":291,"value":961},"    network_mode",{"type":281,"tag":319,"props":963,"children":964},{"style":332},[965],{"type":291,"value":362},{"type":281,"tag":319,"props":967,"children":968},{"style":365},[969],{"type":291,"value":970},"host\n",{"type":281,"tag":319,"props":972,"children":974},{"class":321,"line":973},10,[975,980],{"type":281,"tag":319,"props":976,"children":977},{"style":326},[978],{"type":291,"value":979},"    command",{"type":281,"tag":319,"props":981,"children":982},{"style":332},[983],{"type":291,"value":335},{"type":281,"tag":319,"props":985,"children":987},{"class":321,"line":986},11,[988,992],{"type":281,"tag":319,"props":989,"children":990},{"style":332},[991],{"type":291,"value":391},{"type":281,"tag":319,"props":993,"children":994},{"style":365},[995],{"type":291,"value":996},"--certificatesresolvers.letsencrypt.acme.httpchallenge=true\n",{"type":281,"tag":319,"props":998,"children":1000},{"class":321,"line":999},12,[1001,1005],{"type":281,"tag":319,"props":1002,"children":1003},{"style":332},[1004],{"type":291,"value":391},{"type":281,"tag":319,"props":1006,"children":1007},{"style":365},[1008],{"type":291,"value":1009},"--certificatesresolvers.letsencrypt.acme.email=\u003Cyour_email_here>\n",{"type":281,"tag":319,"props":1011,"children":1013},{"class":321,"line":1012},13,[1014,1018],{"type":281,"tag":319,"props":1015,"children":1016},{"style":332},[1017],{"type":291,"value":391},{"type":281,"tag":319,"props":1019,"children":1020},{"style":365},[1021],{"type":291,"value":1022},"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\n",{"type":281,"tag":319,"props":1024,"children":1026},{"class":321,"line":1025},14,[1027,1031],{"type":281,"tag":319,"props":1028,"children":1029},{"style":332},[1030],{"type":291,"value":391},{"type":281,"tag":319,"props":1032,"children":1033},{"style":365},[1034],{"type":291,"value":1035},"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\n",{"type":281,"tag":319,"props":1037,"children":1039},{"class":321,"line":1038},15,[1040],{"type":281,"tag":319,"props":1041,"children":1043},{"emptyLinePlaceholder":1042},true,[1044],{"type":291,"value":1045},"\n",{"type":281,"tag":319,"props":1047,"children":1049},{"class":321,"line":1048},16,[1050,1054],{"type":281,"tag":319,"props":1051,"children":1052},{"style":332},[1053],{"type":291,"value":391},{"type":281,"tag":319,"props":1055,"children":1056},{"style":365},[1057],{"type":291,"value":1058},"--entrypoints.web.address=:80\n",{"type":281,"tag":319,"props":1060,"children":1062},{"class":321,"line":1061},17,[1063,1067],{"type":281,"tag":319,"props":1064,"children":1065},{"style":332},[1066],{"type":291,"value":391},{"type":281,"tag":319,"props":1068,"children":1069},{"style":365},[1070],{"type":291,"value":1071},"--entrypoints.websecure.address=:443\n",{"type":281,"tag":319,"props":1073,"children":1075},{"class":321,"line":1074},18,[1076],{"type":281,"tag":319,"props":1077,"children":1078},{"style":332},[1079],{"type":291,"value":1080},"      \n",{"type":281,"tag":319,"props":1082,"children":1084},{"class":321,"line":1083},19,[1085,1089],{"type":281,"tag":319,"props":1086,"children":1087},{"style":332},[1088],{"type":291,"value":391},{"type":281,"tag":319,"props":1090,"children":1091},{"style":365},[1092],{"type":291,"value":1093},"--entrypoints.web.http.redirections.entrypoint.to=websecure\n",{"type":281,"tag":319,"props":1095,"children":1097},{"class":321,"line":1096},20,[1098,1102],{"type":281,"tag":319,"props":1099,"children":1100},{"style":332},[1101],{"type":291,"value":391},{"type":281,"tag":319,"props":1103,"children":1104},{"style":365},[1105],{"type":291,"value":1106},"--entrypoints.web.http.redirections.entrypoint.scheme=https\n",{"type":281,"tag":319,"props":1108,"children":1110},{"class":321,"line":1109},21,[1111,1115],{"type":281,"tag":319,"props":1112,"children":1113},{"style":332},[1114],{"type":291,"value":391},{"type":281,"tag":319,"props":1116,"children":1117},{"style":365},[1118],{"type":291,"value":1119},"--entrypoints.websecure.http.tls.certresolver=letsencrypt\n",{"type":281,"tag":319,"props":1121,"children":1123},{"class":321,"line":1122},22,[1124],{"type":281,"tag":319,"props":1125,"children":1126},{"emptyLinePlaceholder":1042},[1127],{"type":291,"value":1045},{"type":281,"tag":319,"props":1129,"children":1131},{"class":321,"line":1130},23,[1132,1136],{"type":281,"tag":319,"props":1133,"children":1134},{"style":332},[1135],{"type":291,"value":391},{"type":281,"tag":319,"props":1137,"children":1138},{"style":365},[1139],{"type":291,"value":1140},"--providers.docker\n",{"type":281,"tag":319,"props":1142,"children":1144},{"class":321,"line":1143},24,[1145,1149],{"type":281,"tag":319,"props":1146,"children":1147},{"style":332},[1148],{"type":291,"value":391},{"type":281,"tag":319,"props":1150,"children":1151},{"style":365},[1152],{"type":291,"value":1153},"--providers.docker.defaultrule=Host(`{{ trimPrefix `app-` .Name }}.example.com`)\n",{"type":281,"tag":319,"props":1155,"children":1157},{"class":321,"line":1156},25,[1158,1162],{"type":281,"tag":319,"props":1159,"children":1160},{"style":332},[1161],{"type":291,"value":391},{"type":281,"tag":319,"props":1163,"children":1164},{"style":365},[1165],{"type":291,"value":1166},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`)\n",{"type":281,"tag":319,"props":1168,"children":1170},{"class":321,"line":1169},26,[1171,1176],{"type":281,"tag":319,"props":1172,"children":1173},{"style":326},[1174],{"type":291,"value":1175},"    volumes",{"type":281,"tag":319,"props":1177,"children":1178},{"style":332},[1179],{"type":291,"value":335},{"type":281,"tag":319,"props":1181,"children":1183},{"class":321,"line":1182},27,[1184,1188],{"type":281,"tag":319,"props":1185,"children":1186},{"style":332},[1187],{"type":291,"value":391},{"type":281,"tag":319,"props":1189,"children":1190},{"style":365},[1191],{"type":291,"value":1192},"/var/run/docker.sock:/var/run/docker.sock:ro\n",{"type":281,"tag":319,"props":1194,"children":1196},{"class":321,"line":1195},28,[1197,1201],{"type":281,"tag":319,"props":1198,"children":1199},{"style":332},[1200],{"type":291,"value":391},{"type":281,"tag":319,"props":1202,"children":1203},{"style":365},[1204],{"type":291,"value":1205},"/letsencrypt:/letsencrypt\n",{"type":281,"tag":282,"props":1207,"children":1208},{},[1209],{"type":291,"value":1210},"Let's explain this a little",{"type":281,"tag":608,"props":1212,"children":1213},{},[1214,1227,1232,1237,1242],{"type":281,"tag":459,"props":1215,"children":1216},{},[1217,1219,1225],{"type":291,"value":1218},"We configure a ",{"type":281,"tag":286,"props":1220,"children":1222},{"href":1221},"https://letsencrypt.org/",[1223],{"type":291,"value":1224},"Let's Encrypt",{"type":291,"value":1226}," certificates resolvers (11-14)",{"type":281,"tag":459,"props":1228,"children":1229},{},[1230],{"type":291,"value":1231},"We listen on port 80 and 443 (16-17)",{"type":281,"tag":459,"props":1233,"children":1234},{},[1235],{"type":291,"value":1236},"We redirect all http traffic to https (19-20)",{"type":281,"tag":459,"props":1238,"children":1239},{},[1240],{"type":291,"value":1241},"and attach the configured certificates resolvers to it (21)",{"type":281,"tag":459,"props":1243,"children":1244},{},[1245],{"type":291,"value":1246},"We setup the docker provider (23-25)",{"type":281,"tag":1248,"props":1249,"children":1251},"h3",{"id":1250},"explanation-for-lines-24-25",[1252],{"type":291,"value":1253},"Explanation for lines 24-25",{"type":281,"tag":301,"props":1255,"children":1257},{"code":1256},"--providers.docker.defaultrule=Host(`{{ trimPrefix 'app-'.Name }}.example.com`)\n",[1258],{"type":281,"tag":315,"props":1259,"children":1260},{"__ignoreMap":8},[1261],{"type":291,"value":1256},{"type":281,"tag":455,"props":1263,"children":1264},{},[1265,1297],{"type":281,"tag":459,"props":1266,"children":1267},{},[1268,1274,1276,1282,1284,1289,1291],{"type":281,"tag":315,"props":1269,"children":1271},{"className":1270},[],[1272],{"type":291,"value":1273},".Name",{"type":291,"value":1275}," is autogenerated as ",{"type":281,"tag":315,"props":1277,"children":1279},{"className":1278},[],[1280],{"type":291,"value":1281},"\u003Cservice-name>-\u003Cstack_name>",{"type":291,"value":1283}," so for your ",{"type":281,"tag":315,"props":1285,"children":1287},{"className":1286},[],[1288],{"type":291,"value":467},{"type":291,"value":1290}," example it would be ",{"type":281,"tag":315,"props":1292,"children":1294},{"className":1293},[],[1295],{"type":291,"value":1296},"app-whoami",{"type":281,"tag":459,"props":1298,"children":1299},{},[1300,1306,1308],{"type":281,"tag":315,"props":1301,"children":1303},{"className":1302},[],[1304],{"type":291,"value":1305},"trimPrefix 'app-'.Name",{"type":291,"value":1307}," resolves in ",{"type":281,"tag":315,"props":1309,"children":1311},{"className":1310},[],[1312],{"type":291,"value":467},{"type":281,"tag":1314,"props":1315,"children":1316},"br",{},[],{"type":281,"tag":301,"props":1318,"children":1319},{"code":1166},[1320],{"type":281,"tag":315,"props":1321,"children":1322},{"__ignoreMap":8},[1323],{"type":291,"value":1166},{"type":281,"tag":282,"props":1325,"children":1326},{},[1327,1329,1334,1336,1342,1344,1350],{"type":291,"value":1328},"All services should be exposed by default but should be filtered down, only to ",{"type":281,"tag":315,"props":1330,"children":1332},{"className":1331},[],[1333],{"type":291,"value":771},{"type":291,"value":1335}," services. The label ",{"type":281,"tag":315,"props":1337,"children":1339},{"className":1338},[],[1340],{"type":291,"value":1341},"com.docker.compose.service",{"type":291,"value":1343}," is added by ",{"type":281,"tag":315,"props":1345,"children":1347},{"className":1346},[],[1348],{"type":291,"value":1349},"docker-compose",{"type":291,"value":1351}," to all containers .",{"type":281,"tag":530,"props":1353,"children":1355},{"id":1354},"bonus-configuration",[1356],{"type":291,"value":1357},"Bonus configuration",{"type":281,"tag":282,"props":1359,"children":1360},{},[1361],{"type":291,"value":1362},"We can tweak this configuration even more.",{"type":281,"tag":1248,"props":1364,"children":1366},{"id":1365},"exposing-other-services-in-the-stack",[1367],{"type":291,"value":1368},"Exposing other services in the stack",{"type":281,"tag":282,"props":1370,"children":1371},{},[1372],{"type":291,"value":1373},"Sometimes you want to expose more than just the app container.",{"type":281,"tag":282,"props":1375,"children":1376},{},[1377,1379,1384],{"type":291,"value":1378},"The current configuration won't route traffic to any other services other than ",{"type":281,"tag":315,"props":1380,"children":1382},{"className":1381},[],[1383],{"type":291,"value":771},{"type":291,"value":1385},".\nTo still be able to use the default configuration method, we need to re-enable it.",{"type":281,"tag":301,"props":1387,"children":1389},{"code":1388},"--providers.docker.constraints=Label(`com.docker.compose.service`,`app`) || Label(`traefik.enable`, `true`)\n",[1390],{"type":281,"tag":315,"props":1391,"children":1392},{"__ignoreMap":8},[1393],{"type":291,"value":1388},{"type":281,"tag":1248,"props":1395,"children":1397},{"id":1396},"stack-name-other-than-directory-name",[1398],{"type":291,"value":1399},"Stack name other than directory name",{"type":281,"tag":282,"props":1401,"children":1402},{},[1403,1405,1410],{"type":291,"value":1404},"When deploying the stacks, the name is generated based on directory name where the ",{"type":281,"tag":315,"props":1406,"children":1408},{"className":1407},[],[1409],{"type":291,"value":604},{"type":291,"value":1411}," file is located.\nWe can change the make in several ways, but here is the easiest one:",{"type":281,"tag":301,"props":1413,"children":1417},{"code":1414,"filename":1415,"highlights":1416,"language":311,"meta":8,"className":312,"style":8},"name: whoami\nservices:\n  app:\n    image: traefik/whoami\n","whoami-example/docker-compose.yaml",[322],[1418],{"type":281,"tag":315,"props":1419,"children":1420},{"__ignoreMap":8},[1421,1439,1450,1461],{"type":281,"tag":319,"props":1422,"children":1424},{"class":1423,"line":322},[321,385],[1425,1430,1434],{"type":281,"tag":319,"props":1426,"children":1427},{"style":326},[1428],{"type":291,"value":1429},"name",{"type":281,"tag":319,"props":1431,"children":1432},{"style":332},[1433],{"type":291,"value":362},{"type":281,"tag":319,"props":1435,"children":1436},{"style":365},[1437],{"type":291,"value":1438},"whoami\n",{"type":281,"tag":319,"props":1440,"children":1441},{"class":321,"line":338},[1442,1446],{"type":281,"tag":319,"props":1443,"children":1444},{"style":326},[1445],{"type":291,"value":329},{"type":281,"tag":319,"props":1447,"children":1448},{"style":332},[1449],{"type":291,"value":335},{"type":281,"tag":319,"props":1451,"children":1452},{"class":321,"line":351},[1453,1457],{"type":281,"tag":319,"props":1454,"children":1455},{"style":326},[1456],{"type":291,"value":811},{"type":281,"tag":319,"props":1458,"children":1459},{"style":332},[1460],{"type":291,"value":335},{"type":281,"tag":319,"props":1462,"children":1463},{"class":321,"line":371},[1464,1468,1472],{"type":281,"tag":319,"props":1465,"children":1466},{"style":326},[1467],{"type":291,"value":357},{"type":281,"tag":319,"props":1469,"children":1470},{"style":332},[1471],{"type":291,"value":362},{"type":281,"tag":319,"props":1473,"children":1474},{"style":365},[1475],{"type":291,"value":368},{"type":281,"tag":1477,"props":1478,"children":1479},"style",{},[1480],{"type":291,"value":1481},"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":8,"searchDepth":338,"depth":338,"links":1483},[1484,1485,1488],{"id":532,"depth":338,"text":535},{"id":628,"depth":338,"text":631,"children":1486},[1487],{"id":1250,"depth":351,"text":1253},{"id":1354,"depth":338,"text":1357,"children":1489},[1490,1491],{"id":1365,"depth":351,"text":1368},{"id":1396,"depth":351,"text":1399},{"_path":27,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":28,"description":29,"author":11,"image":12,"releaseDate":30,"blogCategories":1493,"articleTags":1494,"tags":1495,"body":1496,"_type":20,"_id":37,"_source":22,"_file":38,"_stem":39,"_extension":25},[15,16],[16,33,34],[36,19],{"type":278,"children":1497,"toc":3845},[1498,1506,1511,1562,1568,1581,1593,1641,1654,1662,1673,1679,1684,1965,1970,1975,1980,1985,1996,2001,2026,2032,2044,2856,2860,2888,2893,2899,2904,3841],{"type":281,"tag":1499,"props":1500,"children":1505},"img",{"alt":8,"aspect-ratio":1501,"height":1502,"object-fit":1503,"src":1504},"1.78",300,"fill","/blog/shopware-plugin-test.png",[],{"type":281,"tag":282,"props":1507,"children":1508},{},[1509],{"type":291,"value":1510},"When it comes to testing a Shopware 6 plugin, there are two types of test that can be performed:",{"type":281,"tag":608,"props":1512,"children":1513},{},[1514,1550],{"type":281,"tag":459,"props":1515,"children":1516},{},[1517,1519,1525,1527],{"type":291,"value":1518},"Testing the code itself (",{"type":281,"tag":286,"props":1520,"children":1522},{"href":1521},"https://developer.shopware.com/docs/guides/plugins/plugins/testing/",[1523],{"type":291,"value":1524},"more in the official documentation",{"type":291,"value":1526},")\n",{"type":281,"tag":608,"props":1528,"children":1529},{},[1530,1535,1540,1545],{"type":281,"tag":459,"props":1531,"children":1532},{},[1533],{"type":291,"value":1534},"PHP unit test",{"type":281,"tag":459,"props":1536,"children":1537},{},[1538],{"type":291,"value":1539},"Jest unit tests in Shopware's storefront",{"type":281,"tag":459,"props":1541,"children":1542},{},[1543],{"type":291,"value":1544},"Jest unit tests in Shopware's administration",{"type":281,"tag":459,"props":1546,"children":1547},{},[1548],{"type":291,"value":1549},"End-to-End (E2E) Testing",{"type":281,"tag":459,"props":1551,"children":1552},{},[1553,1555,1560],{"type":291,"value":1554},"Ensuring high code quality (",{"type":281,"tag":286,"props":1556,"children":1558},{"href":1557},"https://developer.shopware.com/docs/products/cli/validation.html",[1559],{"type":291,"value":1524},{"type":291,"value":1561},")",{"type":281,"tag":530,"props":1563,"children":1565},{"id":1564},"code-quality",[1566],{"type":291,"value":1567},"Code quality",{"type":281,"tag":282,"props":1569,"children":1570},{},[1571,1573,1579],{"type":291,"value":1572},"Let's start with code quality because it's easier to run it outside a ",{"type":281,"tag":315,"props":1574,"children":1576},{"className":1575},[],[1577],{"type":291,"value":1578},"CI/CD",{"type":291,"value":1580}," environment.",{"type":281,"tag":282,"props":1582,"children":1583},{},[1584,1586,1592],{"type":291,"value":1585},"We will again use the ",{"type":281,"tag":315,"props":1587,"children":1589},{"className":1588},[],[1590],{"type":291,"value":1591},"shopware-cli",{"type":291,"value":564},{"type":281,"tag":301,"props":1594,"children":1598},{"code":1595,"language":1596,"meta":8,"className":1597,"style":8},"shopware-cli extension validate --full --reporter summary .\n","shell","language-shell shiki shiki-themes github-dark github-dark monokai",[1599],{"type":281,"tag":315,"props":1600,"children":1601},{"__ignoreMap":8},[1602],{"type":281,"tag":319,"props":1603,"children":1604},{"class":321,"line":322},[1605,1610,1615,1620,1626,1631,1636],{"type":281,"tag":319,"props":1606,"children":1608},{"style":1607},"--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E",[1609],{"type":291,"value":1591},{"type":281,"tag":319,"props":1611,"children":1612},{"style":365},[1613],{"type":291,"value":1614}," extension",{"type":281,"tag":319,"props":1616,"children":1617},{"style":365},[1618],{"type":291,"value":1619}," validate",{"type":281,"tag":319,"props":1621,"children":1623},{"style":1622},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF",[1624],{"type":291,"value":1625}," --full",{"type":281,"tag":319,"props":1627,"children":1628},{"style":1622},[1629],{"type":291,"value":1630}," --reporter",{"type":281,"tag":319,"props":1632,"children":1633},{"style":365},[1634],{"type":291,"value":1635}," summary",{"type":281,"tag":319,"props":1637,"children":1638},{"style":365},[1639],{"type":291,"value":1640}," .\n",{"type":281,"tag":282,"props":1642,"children":1643},{},[1644,1646,1652],{"type":291,"value":1645},"This will run all the tests described ",{"type":281,"tag":286,"props":1647,"children":1649},{"href":1648},"https://developer.shopware.com/docs/products/cli/validation.html#running-all-validation-tools",[1650],{"type":291,"value":1651},"here",{"type":291,"value":1653},"\nand hopefully produce an output like this:",{"type":281,"tag":301,"props":1655,"children":1657},{"code":1656},"✖ 0 problems (0 errors, 0 warnings)\n",[1658],{"type":281,"tag":315,"props":1659,"children":1660},{"__ignoreMap":8},[1661],{"type":291,"value":1656},{"type":281,"tag":282,"props":1663,"children":1664},{},[1665,1667,1672],{"type":291,"value":1666},"If there are any errors, refer to the Shopware documentation how to fix them and rerun only the failed tests like described ",{"type":281,"tag":286,"props":1668,"children":1670},{"href":1669},"https://developer.shopware.com/docs/products/cli/validation.html#running-specific-tools",[1671],{"type":291,"value":1651},{"type":291,"value":564},{"type":281,"tag":1248,"props":1674,"children":1676},{"id":1675},"code-quality-pipeline",[1677],{"type":291,"value":1678},"Code quality pipeline",{"type":281,"tag":282,"props":1680,"children":1681},{},[1682],{"type":291,"value":1683},"Now we will run it in GitLab.",{"type":281,"tag":301,"props":1685,"children":1689},{"code":1686,"filename":1687,"highlights":1688,"language":311,"meta":8,"className":312,"style":8},"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","\u003Cplugin-root>/.gitlab-ci.yml",[307,1025,1038,1048,1061,1074],[1690],{"type":281,"tag":315,"props":1691,"children":1692},{"__ignoreMap":8},[1693,1705,1718,1725,1736,1748,1766,1789,1805,1817,1829,1841,1853,1870,1883,1905,1926,1944],{"type":281,"tag":319,"props":1694,"children":1695},{"class":321,"line":322},[1696,1701],{"type":281,"tag":319,"props":1697,"children":1698},{"style":326},[1699],{"type":291,"value":1700},"stages",{"type":281,"tag":319,"props":1702,"children":1703},{"style":332},[1704],{"type":291,"value":335},{"type":281,"tag":319,"props":1706,"children":1707},{"class":321,"line":338},[1708,1713],{"type":281,"tag":319,"props":1709,"children":1710},{"style":332},[1711],{"type":291,"value":1712},"  - ",{"type":281,"tag":319,"props":1714,"children":1715},{"style":365},[1716],{"type":291,"value":1717},"test\n",{"type":281,"tag":319,"props":1719,"children":1720},{"class":321,"line":351},[1721],{"type":281,"tag":319,"props":1722,"children":1723},{"emptyLinePlaceholder":1042},[1724],{"type":291,"value":1045},{"type":281,"tag":319,"props":1726,"children":1727},{"class":321,"line":371},[1728,1732],{"type":281,"tag":319,"props":1729,"children":1730},{"style":326},[1731],{"type":291,"value":1564},{"type":281,"tag":319,"props":1733,"children":1734},{"style":332},[1735],{"type":291,"value":335},{"type":281,"tag":319,"props":1737,"children":1738},{"class":321,"line":306},[1739,1744],{"type":281,"tag":319,"props":1740,"children":1741},{"style":326},[1742],{"type":291,"value":1743},"   image",{"type":281,"tag":319,"props":1745,"children":1746},{"style":332},[1747],{"type":291,"value":335},{"type":281,"tag":319,"props":1749,"children":1751},{"class":1750,"line":307},[321,385],[1752,1757,1761],{"type":281,"tag":319,"props":1753,"children":1754},{"style":326},[1755],{"type":291,"value":1756},"      name",{"type":281,"tag":319,"props":1758,"children":1759},{"style":332},[1760],{"type":291,"value":362},{"type":281,"tag":319,"props":1762,"children":1763},{"style":365},[1764],{"type":291,"value":1765},"ghcr.io/shopware/shopware-cli:latest-php-8.2\n",{"type":281,"tag":319,"props":1767,"children":1768},{"class":321,"line":308},[1769,1774,1779,1784],{"type":281,"tag":319,"props":1770,"children":1771},{"style":326},[1772],{"type":291,"value":1773},"      entrypoint",{"type":281,"tag":319,"props":1775,"children":1776},{"style":332},[1777],{"type":291,"value":1778},": [",{"type":281,"tag":319,"props":1780,"children":1781},{"style":365},[1782],{"type":291,"value":1783},"\"\"",{"type":281,"tag":319,"props":1785,"children":1786},{"style":332},[1787],{"type":291,"value":1788},"]\n",{"type":281,"tag":319,"props":1790,"children":1791},{"class":321,"line":309},[1792,1797,1801],{"type":281,"tag":319,"props":1793,"children":1794},{"style":326},[1795],{"type":291,"value":1796},"   stage",{"type":281,"tag":319,"props":1798,"children":1799},{"style":332},[1800],{"type":291,"value":362},{"type":281,"tag":319,"props":1802,"children":1803},{"style":365},[1804],{"type":291,"value":1717},{"type":281,"tag":319,"props":1806,"children":1807},{"class":321,"line":310},[1808,1813],{"type":281,"tag":319,"props":1809,"children":1810},{"style":326},[1811],{"type":291,"value":1812},"   script",{"type":281,"tag":319,"props":1814,"children":1815},{"style":332},[1816],{"type":291,"value":335},{"type":281,"tag":319,"props":1818,"children":1819},{"class":321,"line":973},[1820,1824],{"type":281,"tag":319,"props":1821,"children":1822},{"style":332},[1823],{"type":291,"value":391},{"type":281,"tag":319,"props":1825,"children":1826},{"style":365},[1827],{"type":291,"value":1828},"shopware-cli extension validate --full . | tee report.json\n",{"type":281,"tag":319,"props":1830,"children":1831},{"class":321,"line":986},[1832,1837],{"type":281,"tag":319,"props":1833,"children":1834},{"style":326},[1835],{"type":291,"value":1836},"   artifacts",{"type":281,"tag":319,"props":1838,"children":1839},{"style":332},[1840],{"type":291,"value":335},{"type":281,"tag":319,"props":1842,"children":1843},{"class":321,"line":999},[1844,1849],{"type":281,"tag":319,"props":1845,"children":1846},{"style":326},[1847],{"type":291,"value":1848},"      reports",{"type":281,"tag":319,"props":1850,"children":1851},{"style":332},[1852],{"type":291,"value":335},{"type":281,"tag":319,"props":1854,"children":1855},{"class":321,"line":1012},[1856,1861,1865],{"type":281,"tag":319,"props":1857,"children":1858},{"style":326},[1859],{"type":291,"value":1860},"         codequality",{"type":281,"tag":319,"props":1862,"children":1863},{"style":332},[1864],{"type":291,"value":362},{"type":281,"tag":319,"props":1866,"children":1867},{"style":365},[1868],{"type":291,"value":1869},"report.json\n",{"type":281,"tag":319,"props":1871,"children":1873},{"class":1872,"line":1025},[321,385],[1874,1879],{"type":281,"tag":319,"props":1875,"children":1876},{"style":326},[1877],{"type":291,"value":1878},"   rules",{"type":281,"tag":319,"props":1880,"children":1881},{"style":332},[1882],{"type":291,"value":335},{"type":281,"tag":319,"props":1884,"children":1886},{"class":1885,"line":1038},[321,385],[1887,1891,1896,1900],{"type":281,"tag":319,"props":1888,"children":1889},{"style":332},[1890],{"type":291,"value":391},{"type":281,"tag":319,"props":1892,"children":1893},{"style":326},[1894],{"type":291,"value":1895},"if",{"type":281,"tag":319,"props":1897,"children":1898},{"style":332},[1899],{"type":291,"value":362},{"type":281,"tag":319,"props":1901,"children":1902},{"style":365},[1903],{"type":291,"value":1904},"$CI_PIPELINE_SOURCE == \"merge_request_event\"\n",{"type":281,"tag":319,"props":1906,"children":1908},{"class":1907,"line":1048},[321,385],[1909,1913,1917,1921],{"type":281,"tag":319,"props":1910,"children":1911},{"style":332},[1912],{"type":291,"value":391},{"type":281,"tag":319,"props":1914,"children":1915},{"style":326},[1916],{"type":291,"value":1895},{"type":281,"tag":319,"props":1918,"children":1919},{"style":332},[1920],{"type":291,"value":362},{"type":281,"tag":319,"props":1922,"children":1923},{"style":365},[1924],{"type":291,"value":1925},"$CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH\n",{"type":281,"tag":319,"props":1927,"children":1929},{"class":1928,"line":1061},[321,385],[1930,1935,1939],{"type":281,"tag":319,"props":1931,"children":1932},{"style":326},[1933],{"type":291,"value":1934},"        when",{"type":281,"tag":319,"props":1936,"children":1937},{"style":332},[1938],{"type":291,"value":362},{"type":281,"tag":319,"props":1940,"children":1941},{"style":365},[1942],{"type":291,"value":1943},"never\n",{"type":281,"tag":319,"props":1945,"children":1947},{"class":1946,"line":1074},[321,385],[1948,1952,1956,1960],{"type":281,"tag":319,"props":1949,"children":1950},{"style":332},[1951],{"type":291,"value":391},{"type":281,"tag":319,"props":1953,"children":1954},{"style":326},[1955],{"type":291,"value":1895},{"type":281,"tag":319,"props":1957,"children":1958},{"style":332},[1959],{"type":291,"value":362},{"type":281,"tag":319,"props":1961,"children":1962},{"style":365},[1963],{"type":291,"value":1964},"$CI_COMMIT_BRANCH\n",{"type":281,"tag":282,"props":1966,"children":1967},{},[1968],{"type":291,"value":1969},"This pipeline will run on the default branch and on merge request pipelines.",{"type":281,"tag":282,"props":1971,"children":1972},{},[1973],{"type":291,"value":1974},"Running on the default branch before build and release prevents from accidentally creating a low-quality release.",{"type":281,"tag":282,"props":1976,"children":1977},{},[1978],{"type":291,"value":1979},"A nice touch to the MR pipeline is the Code Quality report integration!",{"type":281,"tag":530,"props":1981,"children":1983},{"id":1982},"php-unit-test",[1984],{"type":291,"value":1534},{"type":281,"tag":282,"props":1986,"children":1987},{},[1988,1990],{"type":291,"value":1989},"First of all, we need to configure PHPUnit by following the ",{"type":281,"tag":286,"props":1991,"children":1993},{"href":1992},"https://developer.shopware.com/docs/guides/plugins/plugins/testing/php-unit.html",[1994],{"type":291,"value":1995},"official shopware documentation",{"type":281,"tag":282,"props":1997,"children":1998},{},[1999],{"type":291,"value":2000},"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":281,"tag":301,"props":2002,"children":2004},{"code":2003,"language":1596,"meta":8,"className":1597,"style":8},"./vendor/bin/phpunit --configuration=\"custom/static-plugins/SwagBasicExample\"\n",[2005],{"type":281,"tag":315,"props":2006,"children":2007},{"__ignoreMap":8},[2008],{"type":281,"tag":319,"props":2009,"children":2010},{"class":321,"line":322},[2011,2016,2021],{"type":281,"tag":319,"props":2012,"children":2013},{"style":1607},[2014],{"type":291,"value":2015},"./vendor/bin/phpunit",{"type":281,"tag":319,"props":2017,"children":2018},{"style":1622},[2019],{"type":291,"value":2020}," --configuration=",{"type":281,"tag":319,"props":2022,"children":2023},{"style":365},[2024],{"type":291,"value":2025},"\"custom/static-plugins/SwagBasicExample\"\n",{"type":281,"tag":1248,"props":2027,"children":2029},{"id":2028},"phpunit-pipeline",[2030],{"type":291,"value":2031},"PHPUnit pipeline",{"type":281,"tag":282,"props":2033,"children":2034},{},[2035,2037,2042],{"type":291,"value":2036},"Running PHPUnit for a plugin requires a full Shopware instance. Fortunately, ",{"type":281,"tag":315,"props":2038,"children":2040},{"className":2039},[],[2041],{"type":291,"value":1591},{"type":291,"value":2043}," can help us to deal with it.",{"type":281,"tag":301,"props":2045,"children":2057},{"code":2046,"filename":1687,"highlights":2047,"language":311,"meta":8,"className":312,"style":8},"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",[310,973,986,999,1012,1025,1048,1096,1109,1122,1130,1182,1195,2048,2049,2050,2051,2052,2053,2054,2055,2056],29,30,31,32,33,34,35,36,38,[2058],{"type":281,"tag":315,"props":2059,"children":2060},{"__ignoreMap":8},[2061,2072,2084,2091,2103,2119,2131,2147,2167,2180,2202,2220,2233,2251,2269,2281,2299,2316,2333,2340,2358,2376,2394,2412,2419,2436,2448,2461,2474,2487,2500,2513,2526,2539,2552,2565,2577,2590,2603,2611,2624,2646,2659,2673,2691,2704,2717,2730,2748,2766,2779,2799,2819,2836],{"type":281,"tag":319,"props":2062,"children":2063},{"class":321,"line":322},[2064,2068],{"type":281,"tag":319,"props":2065,"children":2066},{"style":326},[2067],{"type":291,"value":1700},{"type":281,"tag":319,"props":2069,"children":2070},{"style":332},[2071],{"type":291,"value":335},{"type":281,"tag":319,"props":2073,"children":2074},{"class":321,"line":338},[2075,2080],{"type":281,"tag":319,"props":2076,"children":2077},{"style":332},[2078],{"type":291,"value":2079},"   - ",{"type":281,"tag":319,"props":2081,"children":2082},{"style":365},[2083],{"type":291,"value":1717},{"type":281,"tag":319,"props":2085,"children":2086},{"class":321,"line":351},[2087],{"type":281,"tag":319,"props":2088,"children":2089},{"emptyLinePlaceholder":1042},[2090],{"type":291,"value":1045},{"type":281,"tag":319,"props":2092,"children":2093},{"class":321,"line":371},[2094,2099],{"type":281,"tag":319,"props":2095,"children":2096},{"style":326},[2097],{"type":291,"value":2098},"phpunit",{"type":281,"tag":319,"props":2100,"children":2101},{"style":332},[2102],{"type":291,"value":335},{"type":281,"tag":319,"props":2104,"children":2105},{"class":321,"line":306},[2106,2111,2115],{"type":281,"tag":319,"props":2107,"children":2108},{"style":326},[2109],{"type":291,"value":2110},"  stage",{"type":281,"tag":319,"props":2112,"children":2113},{"style":332},[2114],{"type":291,"value":362},{"type":281,"tag":319,"props":2116,"children":2117},{"style":365},[2118],{"type":291,"value":1717},{"type":281,"tag":319,"props":2120,"children":2121},{"class":321,"line":307},[2122,2127],{"type":281,"tag":319,"props":2123,"children":2124},{"style":326},[2125],{"type":291,"value":2126},"  image",{"type":281,"tag":319,"props":2128,"children":2129},{"style":332},[2130],{"type":291,"value":335},{"type":281,"tag":319,"props":2132,"children":2133},{"class":321,"line":308},[2134,2139,2143],{"type":281,"tag":319,"props":2135,"children":2136},{"style":326},[2137],{"type":291,"value":2138},"    name",{"type":281,"tag":319,"props":2140,"children":2141},{"style":332},[2142],{"type":291,"value":362},{"type":281,"tag":319,"props":2144,"children":2145},{"style":365},[2146],{"type":291,"value":1765},{"type":281,"tag":319,"props":2148,"children":2149},{"class":321,"line":309},[2150,2155,2159,2163],{"type":281,"tag":319,"props":2151,"children":2152},{"style":326},[2153],{"type":291,"value":2154},"    entrypoint",{"type":281,"tag":319,"props":2156,"children":2157},{"style":332},[2158],{"type":291,"value":1778},{"type":281,"tag":319,"props":2160,"children":2161},{"style":365},[2162],{"type":291,"value":1783},{"type":281,"tag":319,"props":2164,"children":2165},{"style":332},[2166],{"type":291,"value":1788},{"type":281,"tag":319,"props":2168,"children":2170},{"class":2169,"line":310},[321,385],[2171,2176],{"type":281,"tag":319,"props":2172,"children":2173},{"style":326},[2174],{"type":291,"value":2175},"  services",{"type":281,"tag":319,"props":2177,"children":2178},{"style":332},[2179],{"type":291,"value":335},{"type":281,"tag":319,"props":2181,"children":2183},{"class":2182,"line":973},[321,385],[2184,2189,2193,2197],{"type":281,"tag":319,"props":2185,"children":2186},{"style":332},[2187],{"type":291,"value":2188},"    - ",{"type":281,"tag":319,"props":2190,"children":2191},{"style":326},[2192],{"type":291,"value":1429},{"type":281,"tag":319,"props":2194,"children":2195},{"style":332},[2196],{"type":291,"value":362},{"type":281,"tag":319,"props":2198,"children":2199},{"style":365},[2200],{"type":291,"value":2201},"mysql:8.3.0\n",{"type":281,"tag":319,"props":2203,"children":2205},{"class":2204,"line":986},[321,385],[2206,2211,2215],{"type":281,"tag":319,"props":2207,"children":2208},{"style":326},[2209],{"type":291,"value":2210},"      alias",{"type":281,"tag":319,"props":2212,"children":2213},{"style":332},[2214],{"type":291,"value":362},{"type":281,"tag":319,"props":2216,"children":2217},{"style":365},[2218],{"type":291,"value":2219},"test_database\n",{"type":281,"tag":319,"props":2221,"children":2223},{"class":2222,"line":999},[321,385],[2224,2229],{"type":281,"tag":319,"props":2225,"children":2226},{"style":326},[2227],{"type":291,"value":2228},"      variables",{"type":281,"tag":319,"props":2230,"children":2231},{"style":332},[2232],{"type":291,"value":335},{"type":281,"tag":319,"props":2234,"children":2236},{"class":2235,"line":1012},[321,385],[2237,2242,2246],{"type":281,"tag":319,"props":2238,"children":2239},{"style":326},[2240],{"type":291,"value":2241},"        MYSQL_SKIP_TEST_DB",{"type":281,"tag":319,"props":2243,"children":2244},{"style":332},[2245],{"type":291,"value":362},{"type":281,"tag":319,"props":2247,"children":2248},{"style":365},[2249],{"type":291,"value":2250},"'yes'\n",{"type":281,"tag":319,"props":2252,"children":2254},{"class":2253,"line":1025},[321,385],[2255,2260,2264],{"type":281,"tag":319,"props":2256,"children":2257},{"style":326},[2258],{"type":291,"value":2259},"        MYSQL_ALLOW_EMPTY_PASSWORD",{"type":281,"tag":319,"props":2261,"children":2262},{"style":332},[2263],{"type":291,"value":362},{"type":281,"tag":319,"props":2265,"children":2266},{"style":1622},[2267],{"type":291,"value":2268},"yes\n",{"type":281,"tag":319,"props":2270,"children":2271},{"class":321,"line":1038},[2272,2277],{"type":281,"tag":319,"props":2273,"children":2274},{"style":326},[2275],{"type":291,"value":2276},"  variables",{"type":281,"tag":319,"props":2278,"children":2279},{"style":332},[2280],{"type":291,"value":335},{"type":281,"tag":319,"props":2282,"children":2284},{"class":2283,"line":1048},[321,385],[2285,2290,2294],{"type":281,"tag":319,"props":2286,"children":2287},{"style":326},[2288],{"type":291,"value":2289},"    GIT_STRATEGY",{"type":281,"tag":319,"props":2291,"children":2292},{"style":332},[2293],{"type":291,"value":362},{"type":281,"tag":319,"props":2295,"children":2296},{"style":365},[2297],{"type":291,"value":2298},"none\n",{"type":281,"tag":319,"props":2300,"children":2301},{"class":321,"line":1061},[2302,2307,2311],{"type":281,"tag":319,"props":2303,"children":2304},{"style":326},[2305],{"type":291,"value":2306},"    SHOPWARE_ROOT",{"type":281,"tag":319,"props":2308,"children":2309},{"style":332},[2310],{"type":291,"value":362},{"type":281,"tag":319,"props":2312,"children":2313},{"style":365},[2314],{"type":291,"value":2315},"${CI_PROJECT_DIR}/shopware\n",{"type":281,"tag":319,"props":2317,"children":2318},{"class":321,"line":1074},[2319,2324,2328],{"type":281,"tag":319,"props":2320,"children":2321},{"style":326},[2322],{"type":291,"value":2323},"    SHOPWARE_VERSION",{"type":281,"tag":319,"props":2325,"children":2326},{"style":332},[2327],{"type":291,"value":362},{"type":281,"tag":319,"props":2329,"children":2330},{"style":1622},[2331],{"type":291,"value":2332},"6.6.10.13\n",{"type":281,"tag":319,"props":2334,"children":2335},{"class":321,"line":1083},[2336],{"type":281,"tag":319,"props":2337,"children":2338},{"style":332},[2339],{"type":291,"value":880},{"type":281,"tag":319,"props":2341,"children":2343},{"class":2342,"line":1096},[321,385],[2344,2349,2353],{"type":281,"tag":319,"props":2345,"children":2346},{"style":326},[2347],{"type":291,"value":2348},"    APP_SECRET",{"type":281,"tag":319,"props":2350,"children":2351},{"style":332},[2352],{"type":291,"value":362},{"type":281,"tag":319,"props":2354,"children":2355},{"style":365},[2356],{"type":291,"value":2357},"def00000bb5acb32b54ff8ee130270586eec0e878f7337dc7a837acc31d3ff00f93a56b595448b4b29664847dd51991b3314ff65aeeeb761a133b0ec0e070433bff08e48\n",{"type":281,"tag":319,"props":2359,"children":2361},{"class":2360,"line":1109},[321,385],[2362,2367,2371],{"type":281,"tag":319,"props":2363,"children":2364},{"style":326},[2365],{"type":291,"value":2366},"    MESSENGER_TRANSPORT_DSN",{"type":281,"tag":319,"props":2368,"children":2369},{"style":332},[2370],{"type":291,"value":362},{"type":281,"tag":319,"props":2372,"children":2373},{"style":365},[2374],{"type":291,"value":2375},"sync://\n",{"type":281,"tag":319,"props":2377,"children":2379},{"class":2378,"line":1122},[321,385],[2380,2385,2389],{"type":281,"tag":319,"props":2381,"children":2382},{"style":326},[2383],{"type":291,"value":2384},"    DATABASE_URL",{"type":281,"tag":319,"props":2386,"children":2387},{"style":332},[2388],{"type":291,"value":362},{"type":281,"tag":319,"props":2390,"children":2391},{"style":365},[2392],{"type":291,"value":2393},"mysql://root@test_database/shopware\n",{"type":281,"tag":319,"props":2395,"children":2397},{"class":2396,"line":1130},[321,385],[2398,2403,2407],{"type":281,"tag":319,"props":2399,"children":2400},{"style":326},[2401],{"type":291,"value":2402},"    COMPOSER_CACHE_DIR",{"type":281,"tag":319,"props":2404,"children":2405},{"style":332},[2406],{"type":291,"value":362},{"type":281,"tag":319,"props":2408,"children":2409},{"style":365},[2410],{"type":291,"value":2411},"${CI_PROJECT_DIR}/.composer\n",{"type":281,"tag":319,"props":2413,"children":2414},{"class":321,"line":1143},[2415],{"type":281,"tag":319,"props":2416,"children":2417},{"emptyLinePlaceholder":1042},[2418],{"type":291,"value":1045},{"type":281,"tag":319,"props":2420,"children":2421},{"class":321,"line":1156},[2422,2427,2431],{"type":281,"tag":319,"props":2423,"children":2424},{"style":326},[2425],{"type":291,"value":2426},"    XDEBUG_MODE",{"type":281,"tag":319,"props":2428,"children":2429},{"style":332},[2430],{"type":291,"value":362},{"type":281,"tag":319,"props":2432,"children":2433},{"style":365},[2434],{"type":291,"value":2435},"coverage\n",{"type":281,"tag":319,"props":2437,"children":2438},{"class":321,"line":1169},[2439,2444],{"type":281,"tag":319,"props":2440,"children":2441},{"style":326},[2442],{"type":291,"value":2443},"  before_script",{"type":281,"tag":319,"props":2445,"children":2446},{"style":332},[2447],{"type":291,"value":335},{"type":281,"tag":319,"props":2449,"children":2451},{"class":2450,"line":1182},[321,385],[2452,2456],{"type":281,"tag":319,"props":2453,"children":2454},{"style":332},[2455],{"type":291,"value":2188},{"type":281,"tag":319,"props":2457,"children":2458},{"style":365},[2459],{"type":291,"value":2460},"apk add --no-cache php-8.2-xdebug\n",{"type":281,"tag":319,"props":2462,"children":2464},{"class":2463,"line":1195},[321,385],[2465,2469],{"type":281,"tag":319,"props":2466,"children":2467},{"style":332},[2468],{"type":291,"value":2188},{"type":281,"tag":319,"props":2470,"children":2471},{"style":365},[2472],{"type":291,"value":2473},"shopware-cli project create shopware ${SHOPWARE_VERSION}\n",{"type":281,"tag":319,"props":2475,"children":2477},{"class":2476,"line":2048},[321,385],[2478,2482],{"type":281,"tag":319,"props":2479,"children":2480},{"style":332},[2481],{"type":291,"value":2188},{"type":281,"tag":319,"props":2483,"children":2484},{"style":365},[2485],{"type":291,"value":2486},"cd $SHOPWARE_ROOT\n",{"type":281,"tag":319,"props":2488,"children":2490},{"class":2489,"line":2049},[321,385],[2491,2495],{"type":281,"tag":319,"props":2492,"children":2493},{"style":332},[2494],{"type":291,"value":2188},{"type":281,"tag":319,"props":2496,"children":2497},{"style":365},[2498],{"type":291,"value":2499},"composer req --dev shopware/dev-tools phpunit/phpunit\n",{"type":281,"tag":319,"props":2501,"children":2503},{"class":2502,"line":2050},[321,385],[2504,2508],{"type":281,"tag":319,"props":2505,"children":2506},{"style":332},[2507],{"type":291,"value":2188},{"type":281,"tag":319,"props":2509,"children":2510},{"style":365},[2511],{"type":291,"value":2512},"git clone \"https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git\" \"custom/plugins/${CI_PROJECT_NAME}\"\n",{"type":281,"tag":319,"props":2514,"children":2516},{"class":2515,"line":2051},[321,385],[2517,2521],{"type":281,"tag":319,"props":2518,"children":2519},{"style":332},[2520],{"type":291,"value":2188},{"type":281,"tag":319,"props":2522,"children":2523},{"style":365},[2524],{"type":291,"value":2525},"cd custom/plugins/${CI_PROJECT_NAME}\n",{"type":281,"tag":319,"props":2527,"children":2529},{"class":2528,"line":2052},[321,385],[2530,2534],{"type":281,"tag":319,"props":2531,"children":2532},{"style":332},[2533],{"type":291,"value":2188},{"type":281,"tag":319,"props":2535,"children":2536},{"style":365},[2537],{"type":291,"value":2538},"git checkout ${CI_COMMIT_SHA}\n",{"type":281,"tag":319,"props":2540,"children":2542},{"class":2541,"line":2053},[321,385],[2543,2547],{"type":281,"tag":319,"props":2544,"children":2545},{"style":332},[2546],{"type":291,"value":2188},{"type":281,"tag":319,"props":2548,"children":2549},{"style":365},[2550],{"type":291,"value":2551},"cd ${SHOPWARE_ROOT}\n",{"type":281,"tag":319,"props":2553,"children":2555},{"class":2554,"line":2054},[321,385],[2556,2560],{"type":281,"tag":319,"props":2557,"children":2558},{"style":332},[2559],{"type":291,"value":2188},{"type":281,"tag":319,"props":2561,"children":2562},{"style":365},[2563],{"type":291,"value":2564},"composer require $(composer -d custom/plugins/${CI_PROJECT_NAME} config name)\n",{"type":281,"tag":319,"props":2566,"children":2568},{"class":2567,"line":2055},[321,385],[2569,2573],{"type":281,"tag":319,"props":2570,"children":2571},{"style":332},[2572],{"type":291,"value":2188},{"type":281,"tag":319,"props":2574,"children":2575},{"style":365},[2576],{"type":291,"value":2525},{"type":281,"tag":319,"props":2578,"children":2580},{"class":321,"line":2579},37,[2581,2586],{"type":281,"tag":319,"props":2582,"children":2583},{"style":326},[2584],{"type":291,"value":2585},"  script",{"type":281,"tag":319,"props":2587,"children":2588},{"style":332},[2589],{"type":291,"value":335},{"type":281,"tag":319,"props":2591,"children":2593},{"class":2592,"line":2056},[321,385],[2594,2598],{"type":281,"tag":319,"props":2595,"children":2596},{"style":332},[2597],{"type":291,"value":2188},{"type":281,"tag":319,"props":2599,"children":2600},{"style":365},[2601],{"type":291,"value":2602},"${SHOPWARE_ROOT}/vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml\n",{"type":281,"tag":319,"props":2604,"children":2606},{"class":321,"line":2605},39,[2607],{"type":281,"tag":319,"props":2608,"children":2609},{"emptyLinePlaceholder":1042},[2610],{"type":291,"value":1045},{"type":281,"tag":319,"props":2612,"children":2614},{"class":321,"line":2613},40,[2615,2620],{"type":281,"tag":319,"props":2616,"children":2617},{"style":326},[2618],{"type":291,"value":2619},"  cache",{"type":281,"tag":319,"props":2621,"children":2622},{"style":332},[2623],{"type":291,"value":335},{"type":281,"tag":319,"props":2625,"children":2627},{"class":321,"line":2626},41,[2628,2632,2637,2641],{"type":281,"tag":319,"props":2629,"children":2630},{"style":332},[2631],{"type":291,"value":2188},{"type":281,"tag":319,"props":2633,"children":2634},{"style":326},[2635],{"type":291,"value":2636},"key",{"type":281,"tag":319,"props":2638,"children":2639},{"style":332},[2640],{"type":291,"value":362},{"type":281,"tag":319,"props":2642,"children":2643},{"style":365},[2644],{"type":291,"value":2645},"$CI_JOB_NAME\n",{"type":281,"tag":319,"props":2647,"children":2649},{"class":321,"line":2648},42,[2650,2655],{"type":281,"tag":319,"props":2651,"children":2652},{"style":326},[2653],{"type":291,"value":2654},"      paths",{"type":281,"tag":319,"props":2656,"children":2657},{"style":332},[2658],{"type":291,"value":335},{"type":281,"tag":319,"props":2660,"children":2662},{"class":321,"line":2661},43,[2663,2668],{"type":281,"tag":319,"props":2664,"children":2665},{"style":332},[2666],{"type":291,"value":2667},"        - ",{"type":281,"tag":319,"props":2669,"children":2670},{"style":365},[2671],{"type":291,"value":2672},"$COMPOSER_CACHE_DIR\n",{"type":281,"tag":319,"props":2674,"children":2676},{"class":321,"line":2675},44,[2677,2682,2686],{"type":281,"tag":319,"props":2678,"children":2679},{"style":326},[2680],{"type":291,"value":2681},"  coverage",{"type":281,"tag":319,"props":2683,"children":2684},{"style":332},[2685],{"type":291,"value":362},{"type":281,"tag":319,"props":2687,"children":2688},{"style":365},[2689],{"type":291,"value":2690},"/^\\s*Lines:\\s*\\d+.\\d+\\%/\n",{"type":281,"tag":319,"props":2692,"children":2694},{"class":321,"line":2693},45,[2695,2700],{"type":281,"tag":319,"props":2696,"children":2697},{"style":326},[2698],{"type":291,"value":2699},"  artifacts",{"type":281,"tag":319,"props":2701,"children":2702},{"style":332},[2703],{"type":291,"value":335},{"type":281,"tag":319,"props":2705,"children":2707},{"class":321,"line":2706},46,[2708,2713],{"type":281,"tag":319,"props":2709,"children":2710},{"style":326},[2711],{"type":291,"value":2712},"    reports",{"type":281,"tag":319,"props":2714,"children":2715},{"style":332},[2716],{"type":291,"value":335},{"type":281,"tag":319,"props":2718,"children":2720},{"class":321,"line":2719},47,[2721,2726],{"type":281,"tag":319,"props":2722,"children":2723},{"style":326},[2724],{"type":291,"value":2725},"      coverage_report",{"type":281,"tag":319,"props":2727,"children":2728},{"style":332},[2729],{"type":291,"value":335},{"type":281,"tag":319,"props":2731,"children":2733},{"class":321,"line":2732},48,[2734,2739,2743],{"type":281,"tag":319,"props":2735,"children":2736},{"style":326},[2737],{"type":291,"value":2738},"        coverage_format",{"type":281,"tag":319,"props":2740,"children":2741},{"style":332},[2742],{"type":291,"value":362},{"type":281,"tag":319,"props":2744,"children":2745},{"style":365},[2746],{"type":291,"value":2747},"cobertura\n",{"type":281,"tag":319,"props":2749,"children":2751},{"class":321,"line":2750},49,[2752,2757,2761],{"type":281,"tag":319,"props":2753,"children":2754},{"style":326},[2755],{"type":291,"value":2756},"        path",{"type":281,"tag":319,"props":2758,"children":2759},{"style":332},[2760],{"type":291,"value":362},{"type":281,"tag":319,"props":2762,"children":2763},{"style":365},[2764],{"type":291,"value":2765},"coverage.cobertura.xml\n",{"type":281,"tag":319,"props":2767,"children":2769},{"class":321,"line":2768},50,[2770,2775],{"type":281,"tag":319,"props":2771,"children":2772},{"style":326},[2773],{"type":291,"value":2774},"  rules",{"type":281,"tag":319,"props":2776,"children":2777},{"style":332},[2778],{"type":291,"value":335},{"type":281,"tag":319,"props":2780,"children":2782},{"class":321,"line":2781},51,[2783,2787,2791,2795],{"type":281,"tag":319,"props":2784,"children":2785},{"style":332},[2786],{"type":291,"value":2188},{"type":281,"tag":319,"props":2788,"children":2789},{"style":326},[2790],{"type":291,"value":1895},{"type":281,"tag":319,"props":2792,"children":2793},{"style":332},[2794],{"type":291,"value":362},{"type":281,"tag":319,"props":2796,"children":2797},{"style":365},[2798],{"type":291,"value":1904},{"type":281,"tag":319,"props":2800,"children":2802},{"class":321,"line":2801},52,[2803,2807,2811,2815],{"type":281,"tag":319,"props":2804,"children":2805},{"style":332},[2806],{"type":291,"value":2188},{"type":281,"tag":319,"props":2808,"children":2809},{"style":326},[2810],{"type":291,"value":1895},{"type":281,"tag":319,"props":2812,"children":2813},{"style":332},[2814],{"type":291,"value":362},{"type":281,"tag":319,"props":2816,"children":2817},{"style":365},[2818],{"type":291,"value":1925},{"type":281,"tag":319,"props":2820,"children":2822},{"class":321,"line":2821},53,[2823,2828,2832],{"type":281,"tag":319,"props":2824,"children":2825},{"style":326},[2826],{"type":291,"value":2827},"      when",{"type":281,"tag":319,"props":2829,"children":2830},{"style":332},[2831],{"type":291,"value":362},{"type":281,"tag":319,"props":2833,"children":2834},{"style":365},[2835],{"type":291,"value":1943},{"type":281,"tag":319,"props":2837,"children":2839},{"class":321,"line":2838},54,[2840,2844,2848,2852],{"type":281,"tag":319,"props":2841,"children":2842},{"style":332},[2843],{"type":291,"value":2188},{"type":281,"tag":319,"props":2845,"children":2846},{"style":326},[2847],{"type":291,"value":1895},{"type":281,"tag":319,"props":2849,"children":2850},{"style":332},[2851],{"type":291,"value":362},{"type":281,"tag":319,"props":2853,"children":2854},{"style":365},[2855],{"type":291,"value":1964},{"type":281,"tag":282,"props":2857,"children":2858},{},[2859],{"type":291,"value":1210},{"type":281,"tag":608,"props":2861,"children":2862},{},[2863,2868,2873,2878,2883],{"type":281,"tag":459,"props":2864,"children":2865},{},[2866],{"type":291,"value":2867},"We disable automatic repository cloning (16)",{"type":281,"tag":459,"props":2869,"children":2870},{},[2871],{"type":291,"value":2872},"We include a database service (9-14)",{"type":281,"tag":459,"props":2874,"children":2875},{},[2876],{"type":291,"value":2877},"We set some required Shopware env variables (20-23)",{"type":281,"tag":459,"props":2879,"children":2880},{},[2881],{"type":291,"value":2882},"Create an empty shopware project with phpunit and xdebug (27-36)",{"type":281,"tag":459,"props":2884,"children":2885},{},[2886],{"type":291,"value":2887},"Run PHPUnit with code coverage generation as text and in cobertura format (38)",{"type":281,"tag":282,"props":2889,"children":2890},{},[2891],{"type":291,"value":2892},"Like the Code quality pipeline, this takes full advantage of GitLab coverage reporting",{"type":281,"tag":530,"props":2894,"children":2896},{"id":2895},"putting-it-all-together",[2897],{"type":291,"value":2898},"Putting it all together",{"type":281,"tag":282,"props":2900,"children":2901},{},[2902],{"type":291,"value":2903},"For this part, we don't include the build and release part.",{"type":281,"tag":301,"props":2905,"children":2907},{"code":2906,"filename":1687,"language":311,"meta":8,"className":312,"style":8},"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",[2908],{"type":281,"tag":315,"props":2909,"children":2910},{"__ignoreMap":8},[2911,2922,2933,2940,2951,2966,2977,2992,3011,3022,3041,3056,3067,3082,3097,3108,3123,3138,3153,3160,3175,3190,3205,3220,3227,3242,3253,3264,3275,3286,3297,3308,3319,3330,3341,3352,3363,3374,3385,3392,3403,3422,3433,3444,3459,3470,3481,3492,3507,3522,3533,3552,3571,3586,3605,3613,3625,3637,3653,3673,3689,3701,3713,3725,3737,3753,3765,3785,3805,3821],{"type":281,"tag":319,"props":2912,"children":2913},{"class":321,"line":322},[2914,2918],{"type":281,"tag":319,"props":2915,"children":2916},{"style":326},[2917],{"type":291,"value":1700},{"type":281,"tag":319,"props":2919,"children":2920},{"style":332},[2921],{"type":291,"value":335},{"type":281,"tag":319,"props":2923,"children":2924},{"class":321,"line":338},[2925,2929],{"type":281,"tag":319,"props":2926,"children":2927},{"style":332},[2928],{"type":291,"value":2079},{"type":281,"tag":319,"props":2930,"children":2931},{"style":365},[2932],{"type":291,"value":1717},{"type":281,"tag":319,"props":2934,"children":2935},{"class":321,"line":351},[2936],{"type":281,"tag":319,"props":2937,"children":2938},{"emptyLinePlaceholder":1042},[2939],{"type":291,"value":1045},{"type":281,"tag":319,"props":2941,"children":2942},{"class":321,"line":371},[2943,2947],{"type":281,"tag":319,"props":2944,"children":2945},{"style":326},[2946],{"type":291,"value":2098},{"type":281,"tag":319,"props":2948,"children":2949},{"style":332},[2950],{"type":291,"value":335},{"type":281,"tag":319,"props":2952,"children":2953},{"class":321,"line":306},[2954,2958,2962],{"type":281,"tag":319,"props":2955,"children":2956},{"style":326},[2957],{"type":291,"value":2110},{"type":281,"tag":319,"props":2959,"children":2960},{"style":332},[2961],{"type":291,"value":362},{"type":281,"tag":319,"props":2963,"children":2964},{"style":365},[2965],{"type":291,"value":1717},{"type":281,"tag":319,"props":2967,"children":2968},{"class":321,"line":307},[2969,2973],{"type":281,"tag":319,"props":2970,"children":2971},{"style":326},[2972],{"type":291,"value":2126},{"type":281,"tag":319,"props":2974,"children":2975},{"style":332},[2976],{"type":291,"value":335},{"type":281,"tag":319,"props":2978,"children":2979},{"class":321,"line":308},[2980,2984,2988],{"type":281,"tag":319,"props":2981,"children":2982},{"style":326},[2983],{"type":291,"value":2138},{"type":281,"tag":319,"props":2985,"children":2986},{"style":332},[2987],{"type":291,"value":362},{"type":281,"tag":319,"props":2989,"children":2990},{"style":365},[2991],{"type":291,"value":1765},{"type":281,"tag":319,"props":2993,"children":2994},{"class":321,"line":309},[2995,2999,3003,3007],{"type":281,"tag":319,"props":2996,"children":2997},{"style":326},[2998],{"type":291,"value":2154},{"type":281,"tag":319,"props":3000,"children":3001},{"style":332},[3002],{"type":291,"value":1778},{"type":281,"tag":319,"props":3004,"children":3005},{"style":365},[3006],{"type":291,"value":1783},{"type":281,"tag":319,"props":3008,"children":3009},{"style":332},[3010],{"type":291,"value":1788},{"type":281,"tag":319,"props":3012,"children":3013},{"class":321,"line":310},[3014,3018],{"type":281,"tag":319,"props":3015,"children":3016},{"style":326},[3017],{"type":291,"value":2175},{"type":281,"tag":319,"props":3019,"children":3020},{"style":332},[3021],{"type":291,"value":335},{"type":281,"tag":319,"props":3023,"children":3024},{"class":321,"line":973},[3025,3029,3033,3037],{"type":281,"tag":319,"props":3026,"children":3027},{"style":332},[3028],{"type":291,"value":2188},{"type":281,"tag":319,"props":3030,"children":3031},{"style":326},[3032],{"type":291,"value":1429},{"type":281,"tag":319,"props":3034,"children":3035},{"style":332},[3036],{"type":291,"value":362},{"type":281,"tag":319,"props":3038,"children":3039},{"style":365},[3040],{"type":291,"value":2201},{"type":281,"tag":319,"props":3042,"children":3043},{"class":321,"line":986},[3044,3048,3052],{"type":281,"tag":319,"props":3045,"children":3046},{"style":326},[3047],{"type":291,"value":2210},{"type":281,"tag":319,"props":3049,"children":3050},{"style":332},[3051],{"type":291,"value":362},{"type":281,"tag":319,"props":3053,"children":3054},{"style":365},[3055],{"type":291,"value":2219},{"type":281,"tag":319,"props":3057,"children":3058},{"class":321,"line":999},[3059,3063],{"type":281,"tag":319,"props":3060,"children":3061},{"style":326},[3062],{"type":291,"value":2228},{"type":281,"tag":319,"props":3064,"children":3065},{"style":332},[3066],{"type":291,"value":335},{"type":281,"tag":319,"props":3068,"children":3069},{"class":321,"line":1012},[3070,3074,3078],{"type":281,"tag":319,"props":3071,"children":3072},{"style":326},[3073],{"type":291,"value":2241},{"type":281,"tag":319,"props":3075,"children":3076},{"style":332},[3077],{"type":291,"value":362},{"type":281,"tag":319,"props":3079,"children":3080},{"style":365},[3081],{"type":291,"value":2250},{"type":281,"tag":319,"props":3083,"children":3084},{"class":321,"line":1025},[3085,3089,3093],{"type":281,"tag":319,"props":3086,"children":3087},{"style":326},[3088],{"type":291,"value":2259},{"type":281,"tag":319,"props":3090,"children":3091},{"style":332},[3092],{"type":291,"value":362},{"type":281,"tag":319,"props":3094,"children":3095},{"style":1622},[3096],{"type":291,"value":2268},{"type":281,"tag":319,"props":3098,"children":3099},{"class":321,"line":1038},[3100,3104],{"type":281,"tag":319,"props":3101,"children":3102},{"style":326},[3103],{"type":291,"value":2276},{"type":281,"tag":319,"props":3105,"children":3106},{"style":332},[3107],{"type":291,"value":335},{"type":281,"tag":319,"props":3109,"children":3110},{"class":321,"line":1048},[3111,3115,3119],{"type":281,"tag":319,"props":3112,"children":3113},{"style":326},[3114],{"type":291,"value":2289},{"type":281,"tag":319,"props":3116,"children":3117},{"style":332},[3118],{"type":291,"value":362},{"type":281,"tag":319,"props":3120,"children":3121},{"style":365},[3122],{"type":291,"value":2298},{"type":281,"tag":319,"props":3124,"children":3125},{"class":321,"line":1061},[3126,3130,3134],{"type":281,"tag":319,"props":3127,"children":3128},{"style":326},[3129],{"type":291,"value":2306},{"type":281,"tag":319,"props":3131,"children":3132},{"style":332},[3133],{"type":291,"value":362},{"type":281,"tag":319,"props":3135,"children":3136},{"style":365},[3137],{"type":291,"value":2315},{"type":281,"tag":319,"props":3139,"children":3140},{"class":321,"line":1074},[3141,3145,3149],{"type":281,"tag":319,"props":3142,"children":3143},{"style":326},[3144],{"type":291,"value":2323},{"type":281,"tag":319,"props":3146,"children":3147},{"style":332},[3148],{"type":291,"value":362},{"type":281,"tag":319,"props":3150,"children":3151},{"style":1622},[3152],{"type":291,"value":2332},{"type":281,"tag":319,"props":3154,"children":3155},{"class":321,"line":1083},[3156],{"type":281,"tag":319,"props":3157,"children":3158},{"style":332},[3159],{"type":291,"value":880},{"type":281,"tag":319,"props":3161,"children":3162},{"class":321,"line":1096},[3163,3167,3171],{"type":281,"tag":319,"props":3164,"children":3165},{"style":326},[3166],{"type":291,"value":2348},{"type":281,"tag":319,"props":3168,"children":3169},{"style":332},[3170],{"type":291,"value":362},{"type":281,"tag":319,"props":3172,"children":3173},{"style":365},[3174],{"type":291,"value":2357},{"type":281,"tag":319,"props":3176,"children":3177},{"class":321,"line":1109},[3178,3182,3186],{"type":281,"tag":319,"props":3179,"children":3180},{"style":326},[3181],{"type":291,"value":2366},{"type":281,"tag":319,"props":3183,"children":3184},{"style":332},[3185],{"type":291,"value":362},{"type":281,"tag":319,"props":3187,"children":3188},{"style":365},[3189],{"type":291,"value":2375},{"type":281,"tag":319,"props":3191,"children":3192},{"class":321,"line":1122},[3193,3197,3201],{"type":281,"tag":319,"props":3194,"children":3195},{"style":326},[3196],{"type":291,"value":2384},{"type":281,"tag":319,"props":3198,"children":3199},{"style":332},[3200],{"type":291,"value":362},{"type":281,"tag":319,"props":3202,"children":3203},{"style":365},[3204],{"type":291,"value":2393},{"type":281,"tag":319,"props":3206,"children":3207},{"class":321,"line":1130},[3208,3212,3216],{"type":281,"tag":319,"props":3209,"children":3210},{"style":326},[3211],{"type":291,"value":2402},{"type":281,"tag":319,"props":3213,"children":3214},{"style":332},[3215],{"type":291,"value":362},{"type":281,"tag":319,"props":3217,"children":3218},{"style":365},[3219],{"type":291,"value":2411},{"type":281,"tag":319,"props":3221,"children":3222},{"class":321,"line":1143},[3223],{"type":281,"tag":319,"props":3224,"children":3225},{"emptyLinePlaceholder":1042},[3226],{"type":291,"value":1045},{"type":281,"tag":319,"props":3228,"children":3229},{"class":321,"line":1156},[3230,3234,3238],{"type":281,"tag":319,"props":3231,"children":3232},{"style":326},[3233],{"type":291,"value":2426},{"type":281,"tag":319,"props":3235,"children":3236},{"style":332},[3237],{"type":291,"value":362},{"type":281,"tag":319,"props":3239,"children":3240},{"style":365},[3241],{"type":291,"value":2435},{"type":281,"tag":319,"props":3243,"children":3244},{"class":321,"line":1169},[3245,3249],{"type":281,"tag":319,"props":3246,"children":3247},{"style":326},[3248],{"type":291,"value":2443},{"type":281,"tag":319,"props":3250,"children":3251},{"style":332},[3252],{"type":291,"value":335},{"type":281,"tag":319,"props":3254,"children":3255},{"class":321,"line":1182},[3256,3260],{"type":281,"tag":319,"props":3257,"children":3258},{"style":332},[3259],{"type":291,"value":2188},{"type":281,"tag":319,"props":3261,"children":3262},{"style":365},[3263],{"type":291,"value":2460},{"type":281,"tag":319,"props":3265,"children":3266},{"class":321,"line":1195},[3267,3271],{"type":281,"tag":319,"props":3268,"children":3269},{"style":332},[3270],{"type":291,"value":2188},{"type":281,"tag":319,"props":3272,"children":3273},{"style":365},[3274],{"type":291,"value":2473},{"type":281,"tag":319,"props":3276,"children":3277},{"class":321,"line":2048},[3278,3282],{"type":281,"tag":319,"props":3279,"children":3280},{"style":332},[3281],{"type":291,"value":2188},{"type":281,"tag":319,"props":3283,"children":3284},{"style":365},[3285],{"type":291,"value":2486},{"type":281,"tag":319,"props":3287,"children":3288},{"class":321,"line":2049},[3289,3293],{"type":281,"tag":319,"props":3290,"children":3291},{"style":332},[3292],{"type":291,"value":2188},{"type":281,"tag":319,"props":3294,"children":3295},{"style":365},[3296],{"type":291,"value":2499},{"type":281,"tag":319,"props":3298,"children":3299},{"class":321,"line":2050},[3300,3304],{"type":281,"tag":319,"props":3301,"children":3302},{"style":332},[3303],{"type":291,"value":2188},{"type":281,"tag":319,"props":3305,"children":3306},{"style":365},[3307],{"type":291,"value":2512},{"type":281,"tag":319,"props":3309,"children":3310},{"class":321,"line":2051},[3311,3315],{"type":281,"tag":319,"props":3312,"children":3313},{"style":332},[3314],{"type":291,"value":2188},{"type":281,"tag":319,"props":3316,"children":3317},{"style":365},[3318],{"type":291,"value":2525},{"type":281,"tag":319,"props":3320,"children":3321},{"class":321,"line":2052},[3322,3326],{"type":281,"tag":319,"props":3323,"children":3324},{"style":332},[3325],{"type":291,"value":2188},{"type":281,"tag":319,"props":3327,"children":3328},{"style":365},[3329],{"type":291,"value":2538},{"type":281,"tag":319,"props":3331,"children":3332},{"class":321,"line":2053},[3333,3337],{"type":281,"tag":319,"props":3334,"children":3335},{"style":332},[3336],{"type":291,"value":2188},{"type":281,"tag":319,"props":3338,"children":3339},{"style":365},[3340],{"type":291,"value":2551},{"type":281,"tag":319,"props":3342,"children":3343},{"class":321,"line":2054},[3344,3348],{"type":281,"tag":319,"props":3345,"children":3346},{"style":332},[3347],{"type":291,"value":2188},{"type":281,"tag":319,"props":3349,"children":3350},{"style":365},[3351],{"type":291,"value":2564},{"type":281,"tag":319,"props":3353,"children":3354},{"class":321,"line":2055},[3355,3359],{"type":281,"tag":319,"props":3356,"children":3357},{"style":332},[3358],{"type":291,"value":2188},{"type":281,"tag":319,"props":3360,"children":3361},{"style":365},[3362],{"type":291,"value":2525},{"type":281,"tag":319,"props":3364,"children":3365},{"class":321,"line":2579},[3366,3370],{"type":281,"tag":319,"props":3367,"children":3368},{"style":326},[3369],{"type":291,"value":2585},{"type":281,"tag":319,"props":3371,"children":3372},{"style":332},[3373],{"type":291,"value":335},{"type":281,"tag":319,"props":3375,"children":3376},{"class":321,"line":2056},[3377,3381],{"type":281,"tag":319,"props":3378,"children":3379},{"style":332},[3380],{"type":291,"value":2188},{"type":281,"tag":319,"props":3382,"children":3383},{"style":365},[3384],{"type":291,"value":2602},{"type":281,"tag":319,"props":3386,"children":3387},{"class":321,"line":2605},[3388],{"type":281,"tag":319,"props":3389,"children":3390},{"emptyLinePlaceholder":1042},[3391],{"type":291,"value":1045},{"type":281,"tag":319,"props":3393,"children":3394},{"class":321,"line":2613},[3395,3399],{"type":281,"tag":319,"props":3396,"children":3397},{"style":326},[3398],{"type":291,"value":2619},{"type":281,"tag":319,"props":3400,"children":3401},{"style":332},[3402],{"type":291,"value":335},{"type":281,"tag":319,"props":3404,"children":3405},{"class":321,"line":2626},[3406,3410,3414,3418],{"type":281,"tag":319,"props":3407,"children":3408},{"style":332},[3409],{"type":291,"value":2188},{"type":281,"tag":319,"props":3411,"children":3412},{"style":326},[3413],{"type":291,"value":2636},{"type":281,"tag":319,"props":3415,"children":3416},{"style":332},[3417],{"type":291,"value":362},{"type":281,"tag":319,"props":3419,"children":3420},{"style":365},[3421],{"type":291,"value":2645},{"type":281,"tag":319,"props":3423,"children":3424},{"class":321,"line":2648},[3425,3429],{"type":281,"tag":319,"props":3426,"children":3427},{"style":326},[3428],{"type":291,"value":2654},{"type":281,"tag":319,"props":3430,"children":3431},{"style":332},[3432],{"type":291,"value":335},{"type":281,"tag":319,"props":3434,"children":3435},{"class":321,"line":2661},[3436,3440],{"type":281,"tag":319,"props":3437,"children":3438},{"style":332},[3439],{"type":291,"value":2667},{"type":281,"tag":319,"props":3441,"children":3442},{"style":365},[3443],{"type":291,"value":2672},{"type":281,"tag":319,"props":3445,"children":3446},{"class":321,"line":2675},[3447,3451,3455],{"type":281,"tag":319,"props":3448,"children":3449},{"style":326},[3450],{"type":291,"value":2681},{"type":281,"tag":319,"props":3452,"children":3453},{"style":332},[3454],{"type":291,"value":362},{"type":281,"tag":319,"props":3456,"children":3457},{"style":365},[3458],{"type":291,"value":2690},{"type":281,"tag":319,"props":3460,"children":3461},{"class":321,"line":2693},[3462,3466],{"type":281,"tag":319,"props":3463,"children":3464},{"style":326},[3465],{"type":291,"value":2699},{"type":281,"tag":319,"props":3467,"children":3468},{"style":332},[3469],{"type":291,"value":335},{"type":281,"tag":319,"props":3471,"children":3472},{"class":321,"line":2706},[3473,3477],{"type":281,"tag":319,"props":3474,"children":3475},{"style":326},[3476],{"type":291,"value":2712},{"type":281,"tag":319,"props":3478,"children":3479},{"style":332},[3480],{"type":291,"value":335},{"type":281,"tag":319,"props":3482,"children":3483},{"class":321,"line":2719},[3484,3488],{"type":281,"tag":319,"props":3485,"children":3486},{"style":326},[3487],{"type":291,"value":2725},{"type":281,"tag":319,"props":3489,"children":3490},{"style":332},[3491],{"type":291,"value":335},{"type":281,"tag":319,"props":3493,"children":3494},{"class":321,"line":2732},[3495,3499,3503],{"type":281,"tag":319,"props":3496,"children":3497},{"style":326},[3498],{"type":291,"value":2738},{"type":281,"tag":319,"props":3500,"children":3501},{"style":332},[3502],{"type":291,"value":362},{"type":281,"tag":319,"props":3504,"children":3505},{"style":365},[3506],{"type":291,"value":2747},{"type":281,"tag":319,"props":3508,"children":3509},{"class":321,"line":2750},[3510,3514,3518],{"type":281,"tag":319,"props":3511,"children":3512},{"style":326},[3513],{"type":291,"value":2756},{"type":281,"tag":319,"props":3515,"children":3516},{"style":332},[3517],{"type":291,"value":362},{"type":281,"tag":319,"props":3519,"children":3520},{"style":365},[3521],{"type":291,"value":2765},{"type":281,"tag":319,"props":3523,"children":3524},{"class":321,"line":2768},[3525,3529],{"type":281,"tag":319,"props":3526,"children":3527},{"style":326},[3528],{"type":291,"value":2774},{"type":281,"tag":319,"props":3530,"children":3531},{"style":332},[3532],{"type":291,"value":335},{"type":281,"tag":319,"props":3534,"children":3535},{"class":321,"line":2781},[3536,3540,3544,3548],{"type":281,"tag":319,"props":3537,"children":3538},{"style":332},[3539],{"type":291,"value":2188},{"type":281,"tag":319,"props":3541,"children":3542},{"style":326},[3543],{"type":291,"value":1895},{"type":281,"tag":319,"props":3545,"children":3546},{"style":332},[3547],{"type":291,"value":362},{"type":281,"tag":319,"props":3549,"children":3550},{"style":365},[3551],{"type":291,"value":1904},{"type":281,"tag":319,"props":3553,"children":3554},{"class":321,"line":2801},[3555,3559,3563,3567],{"type":281,"tag":319,"props":3556,"children":3557},{"style":332},[3558],{"type":291,"value":2188},{"type":281,"tag":319,"props":3560,"children":3561},{"style":326},[3562],{"type":291,"value":1895},{"type":281,"tag":319,"props":3564,"children":3565},{"style":332},[3566],{"type":291,"value":362},{"type":281,"tag":319,"props":3568,"children":3569},{"style":365},[3570],{"type":291,"value":1925},{"type":281,"tag":319,"props":3572,"children":3573},{"class":321,"line":2821},[3574,3578,3582],{"type":281,"tag":319,"props":3575,"children":3576},{"style":326},[3577],{"type":291,"value":2827},{"type":281,"tag":319,"props":3579,"children":3580},{"style":332},[3581],{"type":291,"value":362},{"type":281,"tag":319,"props":3583,"children":3584},{"style":365},[3585],{"type":291,"value":1943},{"type":281,"tag":319,"props":3587,"children":3588},{"class":321,"line":2838},[3589,3593,3597,3601],{"type":281,"tag":319,"props":3590,"children":3591},{"style":332},[3592],{"type":291,"value":2188},{"type":281,"tag":319,"props":3594,"children":3595},{"style":326},[3596],{"type":291,"value":1895},{"type":281,"tag":319,"props":3598,"children":3599},{"style":332},[3600],{"type":291,"value":362},{"type":281,"tag":319,"props":3602,"children":3603},{"style":365},[3604],{"type":291,"value":1964},{"type":281,"tag":319,"props":3606,"children":3608},{"class":321,"line":3607},55,[3609],{"type":281,"tag":319,"props":3610,"children":3611},{"emptyLinePlaceholder":1042},[3612],{"type":291,"value":1045},{"type":281,"tag":319,"props":3614,"children":3616},{"class":321,"line":3615},56,[3617,3621],{"type":281,"tag":319,"props":3618,"children":3619},{"style":326},[3620],{"type":291,"value":1564},{"type":281,"tag":319,"props":3622,"children":3623},{"style":332},[3624],{"type":291,"value":335},{"type":281,"tag":319,"props":3626,"children":3628},{"class":321,"line":3627},57,[3629,3633],{"type":281,"tag":319,"props":3630,"children":3631},{"style":326},[3632],{"type":291,"value":1743},{"type":281,"tag":319,"props":3634,"children":3635},{"style":332},[3636],{"type":291,"value":335},{"type":281,"tag":319,"props":3638,"children":3640},{"class":321,"line":3639},58,[3641,3645,3649],{"type":281,"tag":319,"props":3642,"children":3643},{"style":326},[3644],{"type":291,"value":1756},{"type":281,"tag":319,"props":3646,"children":3647},{"style":332},[3648],{"type":291,"value":362},{"type":281,"tag":319,"props":3650,"children":3651},{"style":365},[3652],{"type":291,"value":1765},{"type":281,"tag":319,"props":3654,"children":3656},{"class":321,"line":3655},59,[3657,3661,3665,3669],{"type":281,"tag":319,"props":3658,"children":3659},{"style":326},[3660],{"type":291,"value":1773},{"type":281,"tag":319,"props":3662,"children":3663},{"style":332},[3664],{"type":291,"value":1778},{"type":281,"tag":319,"props":3666,"children":3667},{"style":365},[3668],{"type":291,"value":1783},{"type":281,"tag":319,"props":3670,"children":3671},{"style":332},[3672],{"type":291,"value":1788},{"type":281,"tag":319,"props":3674,"children":3676},{"class":321,"line":3675},60,[3677,3681,3685],{"type":281,"tag":319,"props":3678,"children":3679},{"style":326},[3680],{"type":291,"value":1796},{"type":281,"tag":319,"props":3682,"children":3683},{"style":332},[3684],{"type":291,"value":362},{"type":281,"tag":319,"props":3686,"children":3687},{"style":365},[3688],{"type":291,"value":1717},{"type":281,"tag":319,"props":3690,"children":3692},{"class":321,"line":3691},61,[3693,3697],{"type":281,"tag":319,"props":3694,"children":3695},{"style":326},[3696],{"type":291,"value":1812},{"type":281,"tag":319,"props":3698,"children":3699},{"style":332},[3700],{"type":291,"value":335},{"type":281,"tag":319,"props":3702,"children":3704},{"class":321,"line":3703},62,[3705,3709],{"type":281,"tag":319,"props":3706,"children":3707},{"style":332},[3708],{"type":291,"value":391},{"type":281,"tag":319,"props":3710,"children":3711},{"style":365},[3712],{"type":291,"value":1828},{"type":281,"tag":319,"props":3714,"children":3716},{"class":321,"line":3715},63,[3717,3721],{"type":281,"tag":319,"props":3718,"children":3719},{"style":326},[3720],{"type":291,"value":1836},{"type":281,"tag":319,"props":3722,"children":3723},{"style":332},[3724],{"type":291,"value":335},{"type":281,"tag":319,"props":3726,"children":3728},{"class":321,"line":3727},64,[3729,3733],{"type":281,"tag":319,"props":3730,"children":3731},{"style":326},[3732],{"type":291,"value":1848},{"type":281,"tag":319,"props":3734,"children":3735},{"style":332},[3736],{"type":291,"value":335},{"type":281,"tag":319,"props":3738,"children":3740},{"class":321,"line":3739},65,[3741,3745,3749],{"type":281,"tag":319,"props":3742,"children":3743},{"style":326},[3744],{"type":291,"value":1860},{"type":281,"tag":319,"props":3746,"children":3747},{"style":332},[3748],{"type":291,"value":362},{"type":281,"tag":319,"props":3750,"children":3751},{"style":365},[3752],{"type":291,"value":1869},{"type":281,"tag":319,"props":3754,"children":3756},{"class":321,"line":3755},66,[3757,3761],{"type":281,"tag":319,"props":3758,"children":3759},{"style":326},[3760],{"type":291,"value":1878},{"type":281,"tag":319,"props":3762,"children":3763},{"style":332},[3764],{"type":291,"value":335},{"type":281,"tag":319,"props":3766,"children":3768},{"class":321,"line":3767},67,[3769,3773,3777,3781],{"type":281,"tag":319,"props":3770,"children":3771},{"style":332},[3772],{"type":291,"value":391},{"type":281,"tag":319,"props":3774,"children":3775},{"style":326},[3776],{"type":291,"value":1895},{"type":281,"tag":319,"props":3778,"children":3779},{"style":332},[3780],{"type":291,"value":362},{"type":281,"tag":319,"props":3782,"children":3783},{"style":365},[3784],{"type":291,"value":1904},{"type":281,"tag":319,"props":3786,"children":3788},{"class":321,"line":3787},68,[3789,3793,3797,3801],{"type":281,"tag":319,"props":3790,"children":3791},{"style":332},[3792],{"type":291,"value":391},{"type":281,"tag":319,"props":3794,"children":3795},{"style":326},[3796],{"type":291,"value":1895},{"type":281,"tag":319,"props":3798,"children":3799},{"style":332},[3800],{"type":291,"value":362},{"type":281,"tag":319,"props":3802,"children":3803},{"style":365},[3804],{"type":291,"value":1925},{"type":281,"tag":319,"props":3806,"children":3808},{"class":321,"line":3807},69,[3809,3813,3817],{"type":281,"tag":319,"props":3810,"children":3811},{"style":326},[3812],{"type":291,"value":1934},{"type":281,"tag":319,"props":3814,"children":3815},{"style":332},[3816],{"type":291,"value":362},{"type":281,"tag":319,"props":3818,"children":3819},{"style":365},[3820],{"type":291,"value":1943},{"type":281,"tag":319,"props":3822,"children":3824},{"class":321,"line":3823},70,[3825,3829,3833,3837],{"type":281,"tag":319,"props":3826,"children":3827},{"style":332},[3828],{"type":291,"value":391},{"type":281,"tag":319,"props":3830,"children":3831},{"style":326},[3832],{"type":291,"value":1895},{"type":281,"tag":319,"props":3834,"children":3835},{"style":332},[3836],{"type":291,"value":362},{"type":281,"tag":319,"props":3838,"children":3839},{"style":365},[3840],{"type":291,"value":1964},{"type":281,"tag":1477,"props":3842,"children":3843},{},[3844],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":3846},[3847,3850,3853],{"id":1564,"depth":338,"text":1567,"children":3848},[3849],{"id":1675,"depth":351,"text":1678},{"id":1982,"depth":338,"text":1534,"children":3851},[3852],{"id":2028,"depth":351,"text":2031},{"id":2895,"depth":338,"text":2898},{"_path":41,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":42,"description":43,"author":11,"image":12,"releaseDate":30,"blogCategories":3855,"articleTags":3856,"tags":3857,"body":3858,"_type":20,"_id":47,"_source":22,"_file":48,"_stem":49,"_extension":25},[15,16],[16,33,34],[36,19],{"type":278,"children":3859,"toc":4925},[3860,3864,3875,3887,3893,3898,3925,3930,3935,3953,3966,3971,3992,3998,4018,4327,4338,4343,4888,4898,4903,4921],{"type":281,"tag":1499,"props":3861,"children":3863},{"alt":8,"aspect-ratio":1501,"height":1502,"object-fit":1503,"src":3862},"/blog/shopware-plugin-build+release.png",[],{"type":281,"tag":282,"props":3865,"children":3866},{},[3867,3868,3873],{"type":291,"value":540},{"type":281,"tag":286,"props":3869,"children":3870},{"href":51},[3871],{"type":291,"value":3872},"previous post",{"type":291,"value":3874}," I described how to distribute a Shopware 6 plugin over GitLab Package registry.",{"type":281,"tag":282,"props":3876,"children":3877},{},[3878,3880,3885],{"type":291,"value":3879},"When building our project using ",{"type":281,"tag":286,"props":3881,"children":3883},{"href":3882},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html#building-an-extension",[3884],{"type":291,"value":1591},{"type":291,"value":3886},",\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":281,"tag":530,"props":3888,"children":3890},{"id":3889},"building-manually",[3891],{"type":291,"value":3892},"Building manually",{"type":281,"tag":282,"props":3894,"children":3895},{},[3896],{"type":291,"value":3897},"Building a plugin is as simple as running:",{"type":281,"tag":301,"props":3899,"children":3901},{"className":1597,"code":3900,"language":1596,"meta":8,"style":8},"shopware-cli extension build .\n",[3902],{"type":281,"tag":315,"props":3903,"children":3904},{"__ignoreMap":8},[3905],{"type":281,"tag":319,"props":3906,"children":3907},{"class":321,"line":322},[3908,3912,3916,3921],{"type":281,"tag":319,"props":3909,"children":3910},{"style":1607},[3911],{"type":291,"value":1591},{"type":281,"tag":319,"props":3913,"children":3914},{"style":365},[3915],{"type":291,"value":1614},{"type":281,"tag":319,"props":3917,"children":3918},{"style":365},[3919],{"type":291,"value":3920}," build",{"type":281,"tag":319,"props":3922,"children":3923},{"style":365},[3924],{"type":291,"value":1640},{"type":281,"tag":282,"props":3926,"children":3927},{},[3928],{"type":291,"value":3929},"In the plugin root directory.",{"type":281,"tag":282,"props":3931,"children":3932},{},[3933],{"type":291,"value":3934},"There are some tweaks you can make, like:",{"type":281,"tag":455,"props":3936,"children":3937},{},[3938,3943,3948],{"type":281,"tag":459,"props":3939,"children":3940},{},[3941],{"type":291,"value":3942},"constrain a shopware version",{"type":281,"tag":459,"props":3944,"children":3945},{},[3946],{"type":291,"value":3947},"specify extra bundles",{"type":281,"tag":459,"props":3949,"children":3950},{},[3951],{"type":291,"value":3952},"use esbuild",{"type":281,"tag":282,"props":3954,"children":3955},{},[3956,3958,3964],{"type":291,"value":3957},"Please refer to the ",{"type":281,"tag":286,"props":3959,"children":3961},{"href":3960},"https://developer.shopware.com/docs/products/cli/extension-commands/build.html",[3962],{"type":291,"value":3963},"official documentation",{"type":291,"value":3965}," for detailed configuration.",{"type":281,"tag":282,"props":3967,"children":3968},{},[3969],{"type":291,"value":3970},"The build process will create the following directories containing the compiled files:",{"type":281,"tag":455,"props":3972,"children":3973},{},[3974,3983],{"type":281,"tag":459,"props":3975,"children":3976},{},[3977],{"type":281,"tag":315,"props":3978,"children":3980},{"className":3979},[],[3981],{"type":291,"value":3982},"src/Resources/app/storefront/dist/",{"type":281,"tag":459,"props":3984,"children":3985},{},[3986],{"type":281,"tag":315,"props":3987,"children":3989},{"className":3988},[],[3990],{"type":291,"value":3991},"src/Resources/public/static/",{"type":281,"tag":530,"props":3993,"children":3995},{"id":3994},"build-pipeline",[3996],{"type":291,"value":3997},"Build pipeline",{"type":281,"tag":282,"props":3999,"children":4000},{},[4001,4003,4008,4010,4016],{"type":291,"value":4002},"We use the official ",{"type":281,"tag":315,"props":4004,"children":4006},{"className":4005},[],[4007],{"type":291,"value":1591},{"type":291,"value":4009}," docker image. To speed up the process, we take advantage of the ",{"type":281,"tag":315,"props":4011,"children":4013},{"className":4012},[],[4014],{"type":291,"value":4015},"CI",{"type":291,"value":4017}," caching system.",{"type":281,"tag":301,"props":4019,"children":4022},{"className":312,"code":4020,"filename":1687,"highlights":4021,"language":311,"meta":8,"style":8},"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",[307,1025,1038,1048,1061,1074],[4023],{"type":281,"tag":315,"props":4024,"children":4025},{"__ignoreMap":8},[4026,4037,4049,4056,4068,4079,4095,4114,4129,4140,4155,4172,4183,4194,4206,4226,4238,4250,4263,4274,4293,4308],{"type":281,"tag":319,"props":4027,"children":4028},{"class":321,"line":322},[4029,4033],{"type":281,"tag":319,"props":4030,"children":4031},{"style":326},[4032],{"type":291,"value":1700},{"type":281,"tag":319,"props":4034,"children":4035},{"style":332},[4036],{"type":291,"value":335},{"type":281,"tag":319,"props":4038,"children":4039},{"class":321,"line":338},[4040,4044],{"type":281,"tag":319,"props":4041,"children":4042},{"style":332},[4043],{"type":291,"value":1712},{"type":281,"tag":319,"props":4045,"children":4046},{"style":365},[4047],{"type":291,"value":4048},"build\n",{"type":281,"tag":319,"props":4050,"children":4051},{"class":321,"line":351},[4052],{"type":281,"tag":319,"props":4053,"children":4054},{"emptyLinePlaceholder":1042},[4055],{"type":291,"value":1045},{"type":281,"tag":319,"props":4057,"children":4058},{"class":321,"line":371},[4059,4064],{"type":281,"tag":319,"props":4060,"children":4061},{"style":326},[4062],{"type":291,"value":4063},"build",{"type":281,"tag":319,"props":4065,"children":4066},{"style":332},[4067],{"type":291,"value":335},{"type":281,"tag":319,"props":4069,"children":4070},{"class":321,"line":306},[4071,4075],{"type":281,"tag":319,"props":4072,"children":4073},{"style":326},[4074],{"type":291,"value":2126},{"type":281,"tag":319,"props":4076,"children":4077},{"style":332},[4078],{"type":291,"value":335},{"type":281,"tag":319,"props":4080,"children":4082},{"class":4081,"line":307},[321,385],[4083,4087,4091],{"type":281,"tag":319,"props":4084,"children":4085},{"style":326},[4086],{"type":291,"value":2138},{"type":281,"tag":319,"props":4088,"children":4089},{"style":332},[4090],{"type":291,"value":362},{"type":281,"tag":319,"props":4092,"children":4093},{"style":365},[4094],{"type":291,"value":1765},{"type":281,"tag":319,"props":4096,"children":4097},{"class":321,"line":308},[4098,4102,4106,4110],{"type":281,"tag":319,"props":4099,"children":4100},{"style":326},[4101],{"type":291,"value":2154},{"type":281,"tag":319,"props":4103,"children":4104},{"style":332},[4105],{"type":291,"value":1778},{"type":281,"tag":319,"props":4107,"children":4108},{"style":365},[4109],{"type":291,"value":1783},{"type":281,"tag":319,"props":4111,"children":4112},{"style":332},[4113],{"type":291,"value":1788},{"type":281,"tag":319,"props":4115,"children":4116},{"class":321,"line":309},[4117,4121,4125],{"type":281,"tag":319,"props":4118,"children":4119},{"style":326},[4120],{"type":291,"value":2110},{"type":281,"tag":319,"props":4122,"children":4123},{"style":332},[4124],{"type":291,"value":362},{"type":281,"tag":319,"props":4126,"children":4127},{"style":365},[4128],{"type":291,"value":4048},{"type":281,"tag":319,"props":4130,"children":4131},{"class":321,"line":310},[4132,4136],{"type":281,"tag":319,"props":4133,"children":4134},{"style":326},[4135],{"type":291,"value":2276},{"type":281,"tag":319,"props":4137,"children":4138},{"style":332},[4139],{"type":291,"value":335},{"type":281,"tag":319,"props":4141,"children":4142},{"class":321,"line":973},[4143,4147,4151],{"type":281,"tag":319,"props":4144,"children":4145},{"style":326},[4146],{"type":291,"value":2402},{"type":281,"tag":319,"props":4148,"children":4149},{"style":332},[4150],{"type":291,"value":362},{"type":281,"tag":319,"props":4152,"children":4153},{"style":365},[4154],{"type":291,"value":2411},{"type":281,"tag":319,"props":4156,"children":4157},{"class":321,"line":986},[4158,4163,4167],{"type":281,"tag":319,"props":4159,"children":4160},{"style":326},[4161],{"type":291,"value":4162},"    npm_config_cache",{"type":281,"tag":319,"props":4164,"children":4165},{"style":332},[4166],{"type":291,"value":362},{"type":281,"tag":319,"props":4168,"children":4169},{"style":365},[4170],{"type":291,"value":4171},"${CI_PROJECT_DIR}/.npm\n",{"type":281,"tag":319,"props":4173,"children":4174},{"class":321,"line":999},[4175,4179],{"type":281,"tag":319,"props":4176,"children":4177},{"style":326},[4178],{"type":291,"value":2585},{"type":281,"tag":319,"props":4180,"children":4181},{"style":332},[4182],{"type":291,"value":335},{"type":281,"tag":319,"props":4184,"children":4185},{"class":321,"line":1012},[4186,4190],{"type":281,"tag":319,"props":4187,"children":4188},{"style":332},[4189],{"type":291,"value":2188},{"type":281,"tag":319,"props":4191,"children":4192},{"style":365},[4193],{"type":291,"value":3900},{"type":281,"tag":319,"props":4195,"children":4197},{"class":4196,"line":1025},[321,385],[4198,4202],{"type":281,"tag":319,"props":4199,"children":4200},{"style":326},[4201],{"type":291,"value":2619},{"type":281,"tag":319,"props":4203,"children":4204},{"style":332},[4205],{"type":291,"value":335},{"type":281,"tag":319,"props":4207,"children":4209},{"class":4208,"line":1038},[321,385],[4210,4214,4218,4222],{"type":281,"tag":319,"props":4211,"children":4212},{"style":332},[4213],{"type":291,"value":2188},{"type":281,"tag":319,"props":4215,"children":4216},{"style":326},[4217],{"type":291,"value":2636},{"type":281,"tag":319,"props":4219,"children":4220},{"style":332},[4221],{"type":291,"value":362},{"type":281,"tag":319,"props":4223,"children":4224},{"style":365},[4225],{"type":291,"value":2645},{"type":281,"tag":319,"props":4227,"children":4229},{"class":4228,"line":1048},[321,385],[4230,4234],{"type":281,"tag":319,"props":4231,"children":4232},{"style":326},[4233],{"type":291,"value":2654},{"type":281,"tag":319,"props":4235,"children":4236},{"style":332},[4237],{"type":291,"value":335},{"type":281,"tag":319,"props":4239,"children":4241},{"class":4240,"line":1061},[321,385],[4242,4246],{"type":281,"tag":319,"props":4243,"children":4244},{"style":332},[4245],{"type":291,"value":2667},{"type":281,"tag":319,"props":4247,"children":4248},{"style":365},[4249],{"type":291,"value":2672},{"type":281,"tag":319,"props":4251,"children":4253},{"class":4252,"line":1074},[321,385],[4254,4258],{"type":281,"tag":319,"props":4255,"children":4256},{"style":332},[4257],{"type":291,"value":2667},{"type":281,"tag":319,"props":4259,"children":4260},{"style":365},[4261],{"type":291,"value":4262},"$npm_config_cache\n",{"type":281,"tag":319,"props":4264,"children":4265},{"class":321,"line":1083},[4266,4270],{"type":281,"tag":319,"props":4267,"children":4268},{"style":326},[4269],{"type":291,"value":2774},{"type":281,"tag":319,"props":4271,"children":4272},{"style":332},[4273],{"type":291,"value":335},{"type":281,"tag":319,"props":4275,"children":4276},{"class":321,"line":1096},[4277,4281,4285,4289],{"type":281,"tag":319,"props":4278,"children":4279},{"style":332},[4280],{"type":291,"value":2188},{"type":281,"tag":319,"props":4282,"children":4283},{"style":326},[4284],{"type":291,"value":1895},{"type":281,"tag":319,"props":4286,"children":4287},{"style":332},[4288],{"type":291,"value":362},{"type":281,"tag":319,"props":4290,"children":4291},{"style":365},[4292],{"type":291,"value":1925},{"type":281,"tag":319,"props":4294,"children":4295},{"class":321,"line":1109},[4296,4300,4304],{"type":281,"tag":319,"props":4297,"children":4298},{"style":326},[4299],{"type":291,"value":2827},{"type":281,"tag":319,"props":4301,"children":4302},{"style":332},[4303],{"type":291,"value":362},{"type":281,"tag":319,"props":4305,"children":4306},{"style":365},[4307],{"type":291,"value":1943},{"type":281,"tag":319,"props":4309,"children":4310},{"class":321,"line":1122},[4311,4315,4319,4323],{"type":281,"tag":319,"props":4312,"children":4313},{"style":332},[4314],{"type":291,"value":2188},{"type":281,"tag":319,"props":4316,"children":4317},{"style":326},[4318],{"type":291,"value":1895},{"type":281,"tag":319,"props":4320,"children":4321},{"style":332},[4322],{"type":291,"value":362},{"type":281,"tag":319,"props":4324,"children":4325},{"style":365},[4326],{"type":291,"value":1964},{"type":281,"tag":282,"props":4328,"children":4329},{},[4330,4332,4337],{"type":291,"value":4331},"Let's combine it with our release pipeline from the ",{"type":281,"tag":286,"props":4333,"children":4335},{"href":4334},"/en/blog/shopware-plugin-gitlab-pipeline-release#with-semantic-release",[4336],{"type":291,"value":3872},{"type":291,"value":564},{"type":281,"tag":282,"props":4339,"children":4340},{},[4341],{"type":291,"value":4342},"It's important to pass the built artifacts over to the next job.",{"type":281,"tag":301,"props":4344,"children":4347},{"className":312,"code":4345,"filename":1687,"highlights":4346,"language":311,"meta":8,"style":8},"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",[1096,1109,1122,1130],[4348],{"type":281,"tag":315,"props":4349,"children":4350},{"__ignoreMap":8},[4351,4362,4374,4385,4392,4403,4414,4429,4448,4463,4474,4489,4504,4515,4526,4537,4556,4567,4578,4589,4601,4614,4627,4640,4651,4670,4685,4704,4711,4723,4738,4749,4765,4784,4801,4812,4824,4835,4854,4869],{"type":281,"tag":319,"props":4352,"children":4353},{"class":321,"line":322},[4354,4358],{"type":281,"tag":319,"props":4355,"children":4356},{"style":326},[4357],{"type":291,"value":1700},{"type":281,"tag":319,"props":4359,"children":4360},{"style":332},[4361],{"type":291,"value":335},{"type":281,"tag":319,"props":4363,"children":4364},{"class":321,"line":338},[4365,4369],{"type":281,"tag":319,"props":4366,"children":4367},{"style":332},[4368],{"type":291,"value":1712},{"type":281,"tag":319,"props":4370,"children":4371},{"style":365},[4372],{"type":291,"value":4373},"release\n",{"type":281,"tag":319,"props":4375,"children":4376},{"class":321,"line":351},[4377,4381],{"type":281,"tag":319,"props":4378,"children":4379},{"style":332},[4380],{"type":291,"value":1712},{"type":281,"tag":319,"props":4382,"children":4383},{"style":365},[4384],{"type":291,"value":4048},{"type":281,"tag":319,"props":4386,"children":4387},{"class":321,"line":371},[4388],{"type":281,"tag":319,"props":4389,"children":4390},{"emptyLinePlaceholder":1042},[4391],{"type":291,"value":1045},{"type":281,"tag":319,"props":4393,"children":4394},{"class":321,"line":306},[4395,4399],{"type":281,"tag":319,"props":4396,"children":4397},{"style":326},[4398],{"type":291,"value":4063},{"type":281,"tag":319,"props":4400,"children":4401},{"style":332},[4402],{"type":291,"value":335},{"type":281,"tag":319,"props":4404,"children":4405},{"class":321,"line":307},[4406,4410],{"type":281,"tag":319,"props":4407,"children":4408},{"style":326},[4409],{"type":291,"value":2126},{"type":281,"tag":319,"props":4411,"children":4412},{"style":332},[4413],{"type":291,"value":335},{"type":281,"tag":319,"props":4415,"children":4416},{"class":321,"line":308},[4417,4421,4425],{"type":281,"tag":319,"props":4418,"children":4419},{"style":326},[4420],{"type":291,"value":2138},{"type":281,"tag":319,"props":4422,"children":4423},{"style":332},[4424],{"type":291,"value":362},{"type":281,"tag":319,"props":4426,"children":4427},{"style":365},[4428],{"type":291,"value":1765},{"type":281,"tag":319,"props":4430,"children":4431},{"class":321,"line":309},[4432,4436,4440,4444],{"type":281,"tag":319,"props":4433,"children":4434},{"style":326},[4435],{"type":291,"value":2154},{"type":281,"tag":319,"props":4437,"children":4438},{"style":332},[4439],{"type":291,"value":1778},{"type":281,"tag":319,"props":4441,"children":4442},{"style":365},[4443],{"type":291,"value":1783},{"type":281,"tag":319,"props":4445,"children":4446},{"style":332},[4447],{"type":291,"value":1788},{"type":281,"tag":319,"props":4449,"children":4450},{"class":321,"line":310},[4451,4455,4459],{"type":281,"tag":319,"props":4452,"children":4453},{"style":326},[4454],{"type":291,"value":2110},{"type":281,"tag":319,"props":4456,"children":4457},{"style":332},[4458],{"type":291,"value":362},{"type":281,"tag":319,"props":4460,"children":4461},{"style":365},[4462],{"type":291,"value":4048},{"type":281,"tag":319,"props":4464,"children":4465},{"class":321,"line":973},[4466,4470],{"type":281,"tag":319,"props":4467,"children":4468},{"style":326},[4469],{"type":291,"value":2276},{"type":281,"tag":319,"props":4471,"children":4472},{"style":332},[4473],{"type":291,"value":335},{"type":281,"tag":319,"props":4475,"children":4476},{"class":321,"line":986},[4477,4481,4485],{"type":281,"tag":319,"props":4478,"children":4479},{"style":326},[4480],{"type":291,"value":2402},{"type":281,"tag":319,"props":4482,"children":4483},{"style":332},[4484],{"type":291,"value":362},{"type":281,"tag":319,"props":4486,"children":4487},{"style":365},[4488],{"type":291,"value":2411},{"type":281,"tag":319,"props":4490,"children":4491},{"class":321,"line":999},[4492,4496,4500],{"type":281,"tag":319,"props":4493,"children":4494},{"style":326},[4495],{"type":291,"value":4162},{"type":281,"tag":319,"props":4497,"children":4498},{"style":332},[4499],{"type":291,"value":362},{"type":281,"tag":319,"props":4501,"children":4502},{"style":365},[4503],{"type":291,"value":4171},{"type":281,"tag":319,"props":4505,"children":4506},{"class":321,"line":1012},[4507,4511],{"type":281,"tag":319,"props":4508,"children":4509},{"style":326},[4510],{"type":291,"value":2585},{"type":281,"tag":319,"props":4512,"children":4513},{"style":332},[4514],{"type":291,"value":335},{"type":281,"tag":319,"props":4516,"children":4517},{"class":321,"line":1025},[4518,4522],{"type":281,"tag":319,"props":4519,"children":4520},{"style":332},[4521],{"type":291,"value":2188},{"type":281,"tag":319,"props":4523,"children":4524},{"style":365},[4525],{"type":291,"value":3900},{"type":281,"tag":319,"props":4527,"children":4528},{"class":321,"line":1038},[4529,4533],{"type":281,"tag":319,"props":4530,"children":4531},{"style":326},[4532],{"type":291,"value":2619},{"type":281,"tag":319,"props":4534,"children":4535},{"style":332},[4536],{"type":291,"value":335},{"type":281,"tag":319,"props":4538,"children":4539},{"class":321,"line":1048},[4540,4544,4548,4552],{"type":281,"tag":319,"props":4541,"children":4542},{"style":332},[4543],{"type":291,"value":2188},{"type":281,"tag":319,"props":4545,"children":4546},{"style":326},[4547],{"type":291,"value":2636},{"type":281,"tag":319,"props":4549,"children":4550},{"style":332},[4551],{"type":291,"value":362},{"type":281,"tag":319,"props":4553,"children":4554},{"style":365},[4555],{"type":291,"value":2645},{"type":281,"tag":319,"props":4557,"children":4558},{"class":321,"line":1061},[4559,4563],{"type":281,"tag":319,"props":4560,"children":4561},{"style":326},[4562],{"type":291,"value":2654},{"type":281,"tag":319,"props":4564,"children":4565},{"style":332},[4566],{"type":291,"value":335},{"type":281,"tag":319,"props":4568,"children":4569},{"class":321,"line":1074},[4570,4574],{"type":281,"tag":319,"props":4571,"children":4572},{"style":332},[4573],{"type":291,"value":2667},{"type":281,"tag":319,"props":4575,"children":4576},{"style":365},[4577],{"type":291,"value":2672},{"type":281,"tag":319,"props":4579,"children":4580},{"class":321,"line":1083},[4581,4585],{"type":281,"tag":319,"props":4582,"children":4583},{"style":332},[4584],{"type":291,"value":2667},{"type":281,"tag":319,"props":4586,"children":4587},{"style":365},[4588],{"type":291,"value":4262},{"type":281,"tag":319,"props":4590,"children":4592},{"class":4591,"line":1096},[321,385],[4593,4597],{"type":281,"tag":319,"props":4594,"children":4595},{"style":326},[4596],{"type":291,"value":2699},{"type":281,"tag":319,"props":4598,"children":4599},{"style":332},[4600],{"type":291,"value":335},{"type":281,"tag":319,"props":4602,"children":4604},{"class":4603,"line":1109},[321,385],[4605,4610],{"type":281,"tag":319,"props":4606,"children":4607},{"style":326},[4608],{"type":291,"value":4609},"    paths",{"type":281,"tag":319,"props":4611,"children":4612},{"style":332},[4613],{"type":291,"value":335},{"type":281,"tag":319,"props":4615,"children":4617},{"class":4616,"line":1122},[321,385],[4618,4622],{"type":281,"tag":319,"props":4619,"children":4620},{"style":332},[4621],{"type":291,"value":391},{"type":281,"tag":319,"props":4623,"children":4624},{"style":365},[4625],{"type":291,"value":4626},"src/Resources/public\n",{"type":281,"tag":319,"props":4628,"children":4630},{"class":4629,"line":1130},[321,385],[4631,4635],{"type":281,"tag":319,"props":4632,"children":4633},{"style":332},[4634],{"type":291,"value":391},{"type":281,"tag":319,"props":4636,"children":4637},{"style":365},[4638],{"type":291,"value":4639},"src/Storefront/Resources/public\n",{"type":281,"tag":319,"props":4641,"children":4642},{"class":321,"line":1143},[4643,4647],{"type":281,"tag":319,"props":4644,"children":4645},{"style":326},[4646],{"type":291,"value":2774},{"type":281,"tag":319,"props":4648,"children":4649},{"style":332},[4650],{"type":291,"value":335},{"type":281,"tag":319,"props":4652,"children":4653},{"class":321,"line":1156},[4654,4658,4662,4666],{"type":281,"tag":319,"props":4655,"children":4656},{"style":332},[4657],{"type":291,"value":2188},{"type":281,"tag":319,"props":4659,"children":4660},{"style":326},[4661],{"type":291,"value":1895},{"type":281,"tag":319,"props":4663,"children":4664},{"style":332},[4665],{"type":291,"value":362},{"type":281,"tag":319,"props":4667,"children":4668},{"style":365},[4669],{"type":291,"value":1925},{"type":281,"tag":319,"props":4671,"children":4672},{"class":321,"line":1169},[4673,4677,4681],{"type":281,"tag":319,"props":4674,"children":4675},{"style":326},[4676],{"type":291,"value":2827},{"type":281,"tag":319,"props":4678,"children":4679},{"style":332},[4680],{"type":291,"value":362},{"type":281,"tag":319,"props":4682,"children":4683},{"style":365},[4684],{"type":291,"value":1943},{"type":281,"tag":319,"props":4686,"children":4687},{"class":321,"line":1182},[4688,4692,4696,4700],{"type":281,"tag":319,"props":4689,"children":4690},{"style":332},[4691],{"type":291,"value":2188},{"type":281,"tag":319,"props":4693,"children":4694},{"style":326},[4695],{"type":291,"value":1895},{"type":281,"tag":319,"props":4697,"children":4698},{"style":332},[4699],{"type":291,"value":362},{"type":281,"tag":319,"props":4701,"children":4702},{"style":365},[4703],{"type":291,"value":1964},{"type":281,"tag":319,"props":4705,"children":4706},{"class":321,"line":1195},[4707],{"type":281,"tag":319,"props":4708,"children":4709},{"emptyLinePlaceholder":1042},[4710],{"type":291,"value":1045},{"type":281,"tag":319,"props":4712,"children":4713},{"class":321,"line":2048},[4714,4719],{"type":281,"tag":319,"props":4715,"children":4716},{"style":326},[4717],{"type":291,"value":4718},"release",{"type":281,"tag":319,"props":4720,"children":4721},{"style":332},[4722],{"type":291,"value":335},{"type":281,"tag":319,"props":4724,"children":4725},{"class":321,"line":2049},[4726,4730,4734],{"type":281,"tag":319,"props":4727,"children":4728},{"style":326},[4729],{"type":291,"value":2110},{"type":281,"tag":319,"props":4731,"children":4732},{"style":332},[4733],{"type":291,"value":362},{"type":281,"tag":319,"props":4735,"children":4736},{"style":365},[4737],{"type":291,"value":4373},{"type":281,"tag":319,"props":4739,"children":4740},{"class":321,"line":2050},[4741,4745],{"type":281,"tag":319,"props":4742,"children":4743},{"style":326},[4744],{"type":291,"value":2126},{"type":281,"tag":319,"props":4746,"children":4747},{"style":332},[4748],{"type":291,"value":335},{"type":281,"tag":319,"props":4750,"children":4751},{"class":321,"line":2051},[4752,4756,4760],{"type":281,"tag":319,"props":4753,"children":4754},{"style":326},[4755],{"type":291,"value":2138},{"type":281,"tag":319,"props":4757,"children":4758},{"style":332},[4759],{"type":291,"value":362},{"type":281,"tag":319,"props":4761,"children":4762},{"style":365},[4763],{"type":291,"value":4764},"ghcr.io/voxpupuli/semantic-release:latest\n",{"type":281,"tag":319,"props":4766,"children":4767},{"class":321,"line":2052},[4768,4772,4776,4780],{"type":281,"tag":319,"props":4769,"children":4770},{"style":326},[4771],{"type":291,"value":2154},{"type":281,"tag":319,"props":4773,"children":4774},{"style":332},[4775],{"type":291,"value":1778},{"type":281,"tag":319,"props":4777,"children":4778},{"style":365},[4779],{"type":291,"value":1783},{"type":281,"tag":319,"props":4781,"children":4782},{"style":332},[4783],{"type":291,"value":1788},{"type":281,"tag":319,"props":4785,"children":4786},{"class":321,"line":2053},[4787,4792,4796],{"type":281,"tag":319,"props":4788,"children":4789},{"style":326},[4790],{"type":291,"value":4791},"  interruptible",{"type":281,"tag":319,"props":4793,"children":4794},{"style":332},[4795],{"type":291,"value":362},{"type":281,"tag":319,"props":4797,"children":4798},{"style":1622},[4799],{"type":291,"value":4800},"true\n",{"type":281,"tag":319,"props":4802,"children":4803},{"class":321,"line":2054},[4804,4808],{"type":281,"tag":319,"props":4805,"children":4806},{"style":326},[4807],{"type":291,"value":2585},{"type":281,"tag":319,"props":4809,"children":4810},{"style":332},[4811],{"type":291,"value":335},{"type":281,"tag":319,"props":4813,"children":4814},{"class":321,"line":2055},[4815,4819],{"type":281,"tag":319,"props":4816,"children":4817},{"style":332},[4818],{"type":291,"value":2188},{"type":281,"tag":319,"props":4820,"children":4821},{"style":365},[4822],{"type":291,"value":4823},"/docker-entrypoint.sh\n",{"type":281,"tag":319,"props":4825,"children":4826},{"class":321,"line":2579},[4827,4831],{"type":281,"tag":319,"props":4828,"children":4829},{"style":326},[4830],{"type":291,"value":2774},{"type":281,"tag":319,"props":4832,"children":4833},{"style":332},[4834],{"type":291,"value":335},{"type":281,"tag":319,"props":4836,"children":4837},{"class":321,"line":2056},[4838,4842,4846,4850],{"type":281,"tag":319,"props":4839,"children":4840},{"style":332},[4841],{"type":291,"value":2188},{"type":281,"tag":319,"props":4843,"children":4844},{"style":326},[4845],{"type":291,"value":1895},{"type":281,"tag":319,"props":4847,"children":4848},{"style":332},[4849],{"type":291,"value":362},{"type":281,"tag":319,"props":4851,"children":4852},{"style":365},[4853],{"type":291,"value":1925},{"type":281,"tag":319,"props":4855,"children":4856},{"class":321,"line":2605},[4857,4861,4865],{"type":281,"tag":319,"props":4858,"children":4859},{"style":326},[4860],{"type":291,"value":2827},{"type":281,"tag":319,"props":4862,"children":4863},{"style":332},[4864],{"type":291,"value":362},{"type":281,"tag":319,"props":4866,"children":4867},{"style":365},[4868],{"type":291,"value":1943},{"type":281,"tag":319,"props":4870,"children":4871},{"class":321,"line":2613},[4872,4876,4880,4884],{"type":281,"tag":319,"props":4873,"children":4874},{"style":332},[4875],{"type":291,"value":2188},{"type":281,"tag":319,"props":4877,"children":4878},{"style":326},[4879],{"type":291,"value":1895},{"type":281,"tag":319,"props":4881,"children":4882},{"style":332},[4883],{"type":291,"value":362},{"type":281,"tag":319,"props":4885,"children":4886},{"style":365},[4887],{"type":291,"value":1964},{"type":281,"tag":282,"props":4889,"children":4890},{},[4891],{"type":281,"tag":319,"props":4892,"children":4895},{"className":4893},[4894],"text-h2",[4896],{"type":291,"value":4897},"That's it!",{"type":281,"tag":282,"props":4899,"children":4900},{},[4901],{"type":291,"value":4902},"This will:",{"type":281,"tag":608,"props":4904,"children":4905},{},[4906,4911,4916],{"type":281,"tag":459,"props":4907,"children":4908},{},[4909],{"type":291,"value":4910},"Build all the assets",{"type":281,"tag":459,"props":4912,"children":4913},{},[4914],{"type":291,"value":4915},"Pass them to the second job",{"type":281,"tag":459,"props":4917,"children":4918},{},[4919],{"type":291,"value":4920},"Run the release process as described previously",{"type":281,"tag":1477,"props":4922,"children":4923},{},[4924],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":4926},[4927,4928],{"id":3889,"depth":338,"text":3892},{"id":3994,"depth":338,"text":3997},{"_path":51,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":52,"description":53,"author":11,"image":12,"releaseDate":30,"blogCategories":4930,"articleTags":4931,"tags":4932,"body":4933,"_type":20,"_id":57,"_source":22,"_file":58,"_stem":59,"_extension":25},[15,16],[16,33,34],[36,19],{"type":278,"children":4934,"toc":9244},[4935,4939,4944,4955,4960,4965,5000,5005,5011,5016,5022,5034,6042,6047,6071,6081,6084,6097,6120,6255,6267,6272,6278,6290,6310,6712,6753,6758,6779,6921,6933,6939,6950,6955,6967,7002,7007,7934,7939,8038,8043,8102,8113,8118,8139,8274,8283,8289,8309,8312,8315,8321,8327,8332,8348,8398,8546,8552,8557,8568,8581,8791,9196,9200,9240],{"type":281,"tag":1499,"props":4936,"children":4938},{"alt":8,"aspect-ratio":1501,"height":1502,"object-fit":1503,"src":4937},"/blog/shopware-plugin-release.png",[],{"type":281,"tag":282,"props":4940,"children":4941},{},[4942],{"type":291,"value":4943},"There are many ways to install Shopware 6 plugins. You can download them directly in the admin panel or install them with composer.",{"type":281,"tag":282,"props":4945,"children":4946},{},[4947,4949,4954],{"type":291,"value":4948},"There is a detailed comparison in the ",{"type":281,"tag":286,"props":4950,"children":4952},{"href":4951},"https://developer.shopware.com/docs/guides/plugins/plugins/",[4953],{"type":291,"value":3963},{"type":291,"value":564},{"type":281,"tag":282,"props":4956,"children":4957},{},[4958],{"type":291,"value":4959},"As a developer and maintainer of themes, customizations, third part API's, etc., I'm focused on Static Plugins.",{"type":281,"tag":282,"props":4961,"children":4962},{},[4963],{"type":291,"value":4964},"The workflow is simple:",{"type":281,"tag":608,"props":4966,"children":4967},{},[4968,4979,4990],{"type":281,"tag":459,"props":4969,"children":4970},{},[4971,4973],{"type":291,"value":4972},"Create a plugin with ",{"type":281,"tag":315,"props":4974,"children":4976},{"className":4975},[],[4977],{"type":291,"value":4978},"bin/console plugin:create --static",{"type":281,"tag":459,"props":4980,"children":4981},{},[4982,4984],{"type":291,"value":4983},"Require it with ",{"type":281,"tag":286,"props":4985,"children":4987},{"href":4986},"https://developer.shopware.com/docs/guides/plugins/plugins/#static-plugins",[4988],{"type":291,"value":4989},"composer",{"type":281,"tag":459,"props":4991,"children":4992},{},[4993,4995],{"type":291,"value":4994},"Build the project with ",{"type":281,"tag":286,"props":4996,"children":4998},{"href":4997},"https://developer.shopware.com/docs/products/cli/project-commands/build.html#example-docker-image",[4999],{"type":291,"value":1591},{"type":281,"tag":282,"props":5001,"children":5002},{},[5003],{"type":291,"value":5004},"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":281,"tag":530,"props":5006,"children":5008},{"id":5007},"extracting-the-plugin",[5009],{"type":291,"value":5010},"Extracting the plugin",{"type":281,"tag":282,"props":5012,"children":5013},{},[5014],{"type":291,"value":5015},"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":281,"tag":1248,"props":5017,"children":5019},{"id":5018},"download-with-git",[5020],{"type":291,"value":5021},"Download with git",{"type":281,"tag":282,"props":5023,"children":5024},{},[5025,5027,5032],{"type":291,"value":5026},"We just need to tell ",{"type":281,"tag":315,"props":5028,"children":5030},{"className":5029},[],[5031],{"type":291,"value":4989},{"type":291,"value":5033}," where to find our plugin",{"type":281,"tag":301,"props":5035,"children":5041},{"className":5036,"code":5037,"filename":5038,"highlights":5039,"language":5040,"meta":8,"style":8},"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",[2055,2579,2056,2605],"json",[5042],{"type":281,"tag":315,"props":5043,"children":5044},{"__ignoreMap":8},[5045,5053,5077,5098,5119,5132,5153,5174,5195,5216,5236,5256,5273,5281,5294,5302,5323,5344,5356,5372,5380,5388,5395,5414,5434,5445,5460,5467,5474,5481,5500,5520,5531,5546,5553,5560,5568,5589,5606,5615,5623,5635,5647,5675,5682,5689,5710,5722,5734,5754,5770,5777,5797,5813,5820,5832,5844,5861,5868,5880,5888,5896,5908,5915,5923,5930,5942,5954,5974,5986,5998,6007,6016,6024,6033],{"type":281,"tag":319,"props":5046,"children":5047},{"class":321,"line":322},[5048],{"type":281,"tag":319,"props":5049,"children":5050},{"style":332},[5051],{"type":291,"value":5052},"{\n",{"type":281,"tag":319,"props":5054,"children":5055},{"class":321,"line":338},[5056,5062,5066,5072],{"type":281,"tag":319,"props":5057,"children":5059},{"style":5058},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic",[5060],{"type":291,"value":5061},"  \"name\"",{"type":281,"tag":319,"props":5063,"children":5064},{"style":332},[5065],{"type":291,"value":362},{"type":281,"tag":319,"props":5067,"children":5069},{"style":5068},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-sepia:#CFCFC2",[5070],{"type":291,"value":5071},"\"shopware/production\"",{"type":281,"tag":319,"props":5073,"children":5074},{"style":332},[5075],{"type":291,"value":5076},",\n",{"type":281,"tag":319,"props":5078,"children":5079},{"class":321,"line":351},[5080,5085,5089,5094],{"type":281,"tag":319,"props":5081,"children":5082},{"style":5058},[5083],{"type":291,"value":5084},"  \"license\"",{"type":281,"tag":319,"props":5086,"children":5087},{"style":332},[5088],{"type":291,"value":362},{"type":281,"tag":319,"props":5090,"children":5091},{"style":5068},[5092],{"type":291,"value":5093},"\"MIT\"",{"type":281,"tag":319,"props":5095,"children":5096},{"style":332},[5097],{"type":291,"value":5076},{"type":281,"tag":319,"props":5099,"children":5100},{"class":321,"line":371},[5101,5106,5110,5115],{"type":281,"tag":319,"props":5102,"children":5103},{"style":5058},[5104],{"type":291,"value":5105},"  \"type\"",{"type":281,"tag":319,"props":5107,"children":5108},{"style":332},[5109],{"type":291,"value":362},{"type":281,"tag":319,"props":5111,"children":5112},{"style":5068},[5113],{"type":291,"value":5114},"\"project\"",{"type":281,"tag":319,"props":5116,"children":5117},{"style":332},[5118],{"type":291,"value":5076},{"type":281,"tag":319,"props":5120,"children":5121},{"class":321,"line":306},[5122,5127],{"type":281,"tag":319,"props":5123,"children":5124},{"style":5058},[5125],{"type":291,"value":5126},"  \"require\"",{"type":281,"tag":319,"props":5128,"children":5129},{"style":332},[5130],{"type":291,"value":5131},": {\n",{"type":281,"tag":319,"props":5133,"children":5134},{"class":321,"line":307},[5135,5140,5144,5149],{"type":281,"tag":319,"props":5136,"children":5137},{"style":5058},[5138],{"type":291,"value":5139},"    \"composer-runtime-api\"",{"type":281,"tag":319,"props":5141,"children":5142},{"style":332},[5143],{"type":291,"value":362},{"type":281,"tag":319,"props":5145,"children":5146},{"style":5068},[5147],{"type":291,"value":5148},"\"^2.0\"",{"type":281,"tag":319,"props":5150,"children":5151},{"style":332},[5152],{"type":291,"value":5076},{"type":281,"tag":319,"props":5154,"children":5155},{"class":321,"line":308},[5156,5161,5165,5170],{"type":281,"tag":319,"props":5157,"children":5158},{"style":5058},[5159],{"type":291,"value":5160},"    \"acme/sample-plugin\"",{"type":281,"tag":319,"props":5162,"children":5163},{"style":332},[5164],{"type":291,"value":362},{"type":281,"tag":319,"props":5166,"children":5167},{"style":5068},[5168],{"type":291,"value":5169},"\"^1.0\"",{"type":281,"tag":319,"props":5171,"children":5172},{"style":332},[5173],{"type":291,"value":5076},{"type":281,"tag":319,"props":5175,"children":5176},{"class":321,"line":309},[5177,5182,5186,5191],{"type":281,"tag":319,"props":5178,"children":5179},{"style":5058},[5180],{"type":291,"value":5181},"    \"shopware/administration\"",{"type":281,"tag":319,"props":5183,"children":5184},{"style":332},[5185],{"type":291,"value":362},{"type":281,"tag":319,"props":5187,"children":5188},{"style":5068},[5189],{"type":291,"value":5190},"\"*\"",{"type":281,"tag":319,"props":5192,"children":5193},{"style":332},[5194],{"type":291,"value":5076},{"type":281,"tag":319,"props":5196,"children":5197},{"class":321,"line":310},[5198,5203,5207,5212],{"type":281,"tag":319,"props":5199,"children":5200},{"style":5058},[5201],{"type":291,"value":5202},"    \"shopware/core\"",{"type":281,"tag":319,"props":5204,"children":5205},{"style":332},[5206],{"type":291,"value":362},{"type":281,"tag":319,"props":5208,"children":5209},{"style":5068},[5210],{"type":291,"value":5211},"\"6.6.10.2\"",{"type":281,"tag":319,"props":5213,"children":5214},{"style":332},[5215],{"type":291,"value":5076},{"type":281,"tag":319,"props":5217,"children":5218},{"class":321,"line":973},[5219,5224,5228,5232],{"type":281,"tag":319,"props":5220,"children":5221},{"style":5058},[5222],{"type":291,"value":5223},"    \"shopware/elasticsearch\"",{"type":281,"tag":319,"props":5225,"children":5226},{"style":332},[5227],{"type":291,"value":362},{"type":281,"tag":319,"props":5229,"children":5230},{"style":5068},[5231],{"type":291,"value":5190},{"type":281,"tag":319,"props":5233,"children":5234},{"style":332},[5235],{"type":291,"value":5076},{"type":281,"tag":319,"props":5237,"children":5238},{"class":321,"line":986},[5239,5244,5248,5252],{"type":281,"tag":319,"props":5240,"children":5241},{"style":5058},[5242],{"type":291,"value":5243},"    \"shopware/storefront\"",{"type":281,"tag":319,"props":5245,"children":5246},{"style":332},[5247],{"type":291,"value":362},{"type":281,"tag":319,"props":5249,"children":5250},{"style":5068},[5251],{"type":291,"value":5190},{"type":281,"tag":319,"props":5253,"children":5254},{"style":332},[5255],{"type":291,"value":5076},{"type":281,"tag":319,"props":5257,"children":5258},{"class":321,"line":999},[5259,5264,5268],{"type":281,"tag":319,"props":5260,"children":5261},{"style":5058},[5262],{"type":291,"value":5263},"    \"symfony/flex\"",{"type":281,"tag":319,"props":5265,"children":5266},{"style":332},[5267],{"type":291,"value":362},{"type":281,"tag":319,"props":5269,"children":5270},{"style":5068},[5271],{"type":291,"value":5272},"\"~2\"\n",{"type":281,"tag":319,"props":5274,"children":5275},{"class":321,"line":1012},[5276],{"type":281,"tag":319,"props":5277,"children":5278},{"style":332},[5279],{"type":291,"value":5280},"  },\n",{"type":281,"tag":319,"props":5282,"children":5283},{"class":321,"line":1025},[5284,5289],{"type":281,"tag":319,"props":5285,"children":5286},{"style":5058},[5287],{"type":291,"value":5288},"  \"repositories\"",{"type":281,"tag":319,"props":5290,"children":5291},{"style":332},[5292],{"type":291,"value":5293},": [\n",{"type":281,"tag":319,"props":5295,"children":5296},{"class":321,"line":1038},[5297],{"type":281,"tag":319,"props":5298,"children":5299},{"style":332},[5300],{"type":291,"value":5301},"    {\n",{"type":281,"tag":319,"props":5303,"children":5304},{"class":321,"line":1048},[5305,5310,5314,5319],{"type":281,"tag":319,"props":5306,"children":5307},{"style":5058},[5308],{"type":291,"value":5309},"      \"type\"",{"type":281,"tag":319,"props":5311,"children":5312},{"style":332},[5313],{"type":291,"value":362},{"type":281,"tag":319,"props":5315,"children":5316},{"style":5068},[5317],{"type":291,"value":5318},"\"path\"",{"type":281,"tag":319,"props":5320,"children":5321},{"style":332},[5322],{"type":291,"value":5076},{"type":281,"tag":319,"props":5324,"children":5325},{"class":321,"line":1061},[5326,5331,5335,5340],{"type":281,"tag":319,"props":5327,"children":5328},{"style":5058},[5329],{"type":291,"value":5330},"      \"url\"",{"type":281,"tag":319,"props":5332,"children":5333},{"style":332},[5334],{"type":291,"value":362},{"type":281,"tag":319,"props":5336,"children":5337},{"style":5068},[5338],{"type":291,"value":5339},"\"custom/plugins/*\"",{"type":281,"tag":319,"props":5341,"children":5342},{"style":332},[5343],{"type":291,"value":5076},{"type":281,"tag":319,"props":5345,"children":5346},{"class":321,"line":1074},[5347,5352],{"type":281,"tag":319,"props":5348,"children":5349},{"style":5058},[5350],{"type":291,"value":5351},"      \"options\"",{"type":281,"tag":319,"props":5353,"children":5354},{"style":332},[5355],{"type":291,"value":5131},{"type":281,"tag":319,"props":5357,"children":5358},{"class":321,"line":1083},[5359,5364,5368],{"type":281,"tag":319,"props":5360,"children":5361},{"style":5058},[5362],{"type":291,"value":5363},"        \"symlink\"",{"type":281,"tag":319,"props":5365,"children":5366},{"style":332},[5367],{"type":291,"value":362},{"type":281,"tag":319,"props":5369,"children":5370},{"style":1622},[5371],{"type":291,"value":4800},{"type":281,"tag":319,"props":5373,"children":5374},{"class":321,"line":1096},[5375],{"type":281,"tag":319,"props":5376,"children":5377},{"style":332},[5378],{"type":291,"value":5379},"      }\n",{"type":281,"tag":319,"props":5381,"children":5382},{"class":321,"line":1109},[5383],{"type":281,"tag":319,"props":5384,"children":5385},{"style":332},[5386],{"type":291,"value":5387},"    },\n",{"type":281,"tag":319,"props":5389,"children":5390},{"class":321,"line":1122},[5391],{"type":281,"tag":319,"props":5392,"children":5393},{"style":332},[5394],{"type":291,"value":5301},{"type":281,"tag":319,"props":5396,"children":5397},{"class":321,"line":1130},[5398,5402,5406,5410],{"type":281,"tag":319,"props":5399,"children":5400},{"style":5058},[5401],{"type":291,"value":5309},{"type":281,"tag":319,"props":5403,"children":5404},{"style":332},[5405],{"type":291,"value":362},{"type":281,"tag":319,"props":5407,"children":5408},{"style":5068},[5409],{"type":291,"value":5318},{"type":281,"tag":319,"props":5411,"children":5412},{"style":332},[5413],{"type":291,"value":5076},{"type":281,"tag":319,"props":5415,"children":5416},{"class":321,"line":1143},[5417,5421,5425,5430],{"type":281,"tag":319,"props":5418,"children":5419},{"style":5058},[5420],{"type":291,"value":5330},{"type":281,"tag":319,"props":5422,"children":5423},{"style":332},[5424],{"type":291,"value":362},{"type":281,"tag":319,"props":5426,"children":5427},{"style":5068},[5428],{"type":291,"value":5429},"\"custom/plugins/*/packages/*\"",{"type":281,"tag":319,"props":5431,"children":5432},{"style":332},[5433],{"type":291,"value":5076},{"type":281,"tag":319,"props":5435,"children":5436},{"class":321,"line":1156},[5437,5441],{"type":281,"tag":319,"props":5438,"children":5439},{"style":5058},[5440],{"type":291,"value":5351},{"type":281,"tag":319,"props":5442,"children":5443},{"style":332},[5444],{"type":291,"value":5131},{"type":281,"tag":319,"props":5446,"children":5447},{"class":321,"line":1169},[5448,5452,5456],{"type":281,"tag":319,"props":5449,"children":5450},{"style":5058},[5451],{"type":291,"value":5363},{"type":281,"tag":319,"props":5453,"children":5454},{"style":332},[5455],{"type":291,"value":362},{"type":281,"tag":319,"props":5457,"children":5458},{"style":1622},[5459],{"type":291,"value":4800},{"type":281,"tag":319,"props":5461,"children":5462},{"class":321,"line":1182},[5463],{"type":281,"tag":319,"props":5464,"children":5465},{"style":332},[5466],{"type":291,"value":5379},{"type":281,"tag":319,"props":5468,"children":5469},{"class":321,"line":1195},[5470],{"type":281,"tag":319,"props":5471,"children":5472},{"style":332},[5473],{"type":291,"value":5387},{"type":281,"tag":319,"props":5475,"children":5476},{"class":321,"line":2048},[5477],{"type":281,"tag":319,"props":5478,"children":5479},{"style":332},[5480],{"type":291,"value":5301},{"type":281,"tag":319,"props":5482,"children":5483},{"class":321,"line":2049},[5484,5488,5492,5496],{"type":281,"tag":319,"props":5485,"children":5486},{"style":5058},[5487],{"type":291,"value":5309},{"type":281,"tag":319,"props":5489,"children":5490},{"style":332},[5491],{"type":291,"value":362},{"type":281,"tag":319,"props":5493,"children":5494},{"style":5068},[5495],{"type":291,"value":5318},{"type":281,"tag":319,"props":5497,"children":5498},{"style":332},[5499],{"type":291,"value":5076},{"type":281,"tag":319,"props":5501,"children":5502},{"class":321,"line":2050},[5503,5507,5511,5516],{"type":281,"tag":319,"props":5504,"children":5505},{"style":5058},[5506],{"type":291,"value":5330},{"type":281,"tag":319,"props":5508,"children":5509},{"style":332},[5510],{"type":291,"value":362},{"type":281,"tag":319,"props":5512,"children":5513},{"style":5068},[5514],{"type":291,"value":5515},"\"custom/static-plugins/*\"",{"type":281,"tag":319,"props":5517,"children":5518},{"style":332},[5519],{"type":291,"value":5076},{"type":281,"tag":319,"props":5521,"children":5522},{"class":321,"line":2051},[5523,5527],{"type":281,"tag":319,"props":5524,"children":5525},{"style":5058},[5526],{"type":291,"value":5351},{"type":281,"tag":319,"props":5528,"children":5529},{"style":332},[5530],{"type":291,"value":5131},{"type":281,"tag":319,"props":5532,"children":5533},{"class":321,"line":2052},[5534,5538,5542],{"type":281,"tag":319,"props":5535,"children":5536},{"style":5058},[5537],{"type":291,"value":5363},{"type":281,"tag":319,"props":5539,"children":5540},{"style":332},[5541],{"type":291,"value":362},{"type":281,"tag":319,"props":5543,"children":5544},{"style":1622},[5545],{"type":291,"value":4800},{"type":281,"tag":319,"props":5547,"children":5548},{"class":321,"line":2053},[5549],{"type":281,"tag":319,"props":5550,"children":5551},{"style":332},[5552],{"type":291,"value":5379},{"type":281,"tag":319,"props":5554,"children":5555},{"class":321,"line":2054},[5556],{"type":281,"tag":319,"props":5557,"children":5558},{"style":332},[5559],{"type":291,"value":5387},{"type":281,"tag":319,"props":5561,"children":5563},{"class":5562,"line":2055},[321,385],[5564],{"type":281,"tag":319,"props":5565,"children":5566},{"style":332},[5567],{"type":291,"value":5301},{"type":281,"tag":319,"props":5569,"children":5571},{"class":5570,"line":2579},[321,385],[5572,5576,5580,5585],{"type":281,"tag":319,"props":5573,"children":5574},{"style":5058},[5575],{"type":291,"value":5309},{"type":281,"tag":319,"props":5577,"children":5578},{"style":332},[5579],{"type":291,"value":362},{"type":281,"tag":319,"props":5581,"children":5582},{"style":5068},[5583],{"type":291,"value":5584},"\"git\"",{"type":281,"tag":319,"props":5586,"children":5587},{"style":332},[5588],{"type":291,"value":5076},{"type":281,"tag":319,"props":5590,"children":5592},{"class":5591,"line":2056},[321,385],[5593,5597,5601],{"type":281,"tag":319,"props":5594,"children":5595},{"style":5058},[5596],{"type":291,"value":5330},{"type":281,"tag":319,"props":5598,"children":5599},{"style":332},[5600],{"type":291,"value":362},{"type":281,"tag":319,"props":5602,"children":5603},{"style":5068},[5604],{"type":291,"value":5605},"\"https://\u003CDOMAIN-NAME>/\u003Cgroup>/\u003Crepo>.git\"\n",{"type":281,"tag":319,"props":5607,"children":5609},{"class":5608,"line":2605},[321,385],[5610],{"type":281,"tag":319,"props":5611,"children":5612},{"style":332},[5613],{"type":291,"value":5614},"    }\n",{"type":281,"tag":319,"props":5616,"children":5617},{"class":321,"line":2613},[5618],{"type":281,"tag":319,"props":5619,"children":5620},{"style":332},[5621],{"type":291,"value":5622},"  ],\n",{"type":281,"tag":319,"props":5624,"children":5625},{"class":321,"line":2626},[5626,5631],{"type":281,"tag":319,"props":5627,"children":5628},{"style":5058},[5629],{"type":291,"value":5630},"  \"autoload\"",{"type":281,"tag":319,"props":5632,"children":5633},{"style":332},[5634],{"type":291,"value":5131},{"type":281,"tag":319,"props":5636,"children":5637},{"class":321,"line":2648},[5638,5643],{"type":281,"tag":319,"props":5639,"children":5640},{"style":5058},[5641],{"type":291,"value":5642},"    \"psr-4\"",{"type":281,"tag":319,"props":5644,"children":5645},{"style":332},[5646],{"type":291,"value":5131},{"type":281,"tag":319,"props":5648,"children":5649},{"class":321,"line":2661},[5650,5655,5661,5666,5670],{"type":281,"tag":319,"props":5651,"children":5652},{"style":5058},[5653],{"type":291,"value":5654},"      \"App",{"type":281,"tag":319,"props":5656,"children":5658},{"style":5657},"--shiki-default:#79B8FF;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#AE81FF;--shiki-sepia-font-style:italic",[5659],{"type":291,"value":5660},"\\\\",{"type":281,"tag":319,"props":5662,"children":5663},{"style":5058},[5664],{"type":291,"value":5665},"\"",{"type":281,"tag":319,"props":5667,"children":5668},{"style":332},[5669],{"type":291,"value":362},{"type":281,"tag":319,"props":5671,"children":5672},{"style":5068},[5673],{"type":291,"value":5674},"\"src/\"\n",{"type":281,"tag":319,"props":5676,"children":5677},{"class":321,"line":2675},[5678],{"type":281,"tag":319,"props":5679,"children":5680},{"style":332},[5681],{"type":291,"value":5614},{"type":281,"tag":319,"props":5683,"children":5684},{"class":321,"line":2693},[5685],{"type":281,"tag":319,"props":5686,"children":5687},{"style":332},[5688],{"type":291,"value":5280},{"type":281,"tag":319,"props":5690,"children":5691},{"class":321,"line":2706},[5692,5697,5701,5706],{"type":281,"tag":319,"props":5693,"children":5694},{"style":5058},[5695],{"type":291,"value":5696},"  \"prefer-stable\"",{"type":281,"tag":319,"props":5698,"children":5699},{"style":332},[5700],{"type":291,"value":362},{"type":281,"tag":319,"props":5702,"children":5703},{"style":1622},[5704],{"type":291,"value":5705},"true",{"type":281,"tag":319,"props":5707,"children":5708},{"style":332},[5709],{"type":291,"value":5076},{"type":281,"tag":319,"props":5711,"children":5712},{"class":321,"line":2719},[5713,5718],{"type":281,"tag":319,"props":5714,"children":5715},{"style":5058},[5716],{"type":291,"value":5717},"  \"config\"",{"type":281,"tag":319,"props":5719,"children":5720},{"style":332},[5721],{"type":291,"value":5131},{"type":281,"tag":319,"props":5723,"children":5724},{"class":321,"line":2732},[5725,5730],{"type":281,"tag":319,"props":5726,"children":5727},{"style":5058},[5728],{"type":291,"value":5729},"    \"allow-plugins\"",{"type":281,"tag":319,"props":5731,"children":5732},{"style":332},[5733],{"type":291,"value":5131},{"type":281,"tag":319,"props":5735,"children":5736},{"class":321,"line":2750},[5737,5742,5746,5750],{"type":281,"tag":319,"props":5738,"children":5739},{"style":5058},[5740],{"type":291,"value":5741},"      \"symfony/flex\"",{"type":281,"tag":319,"props":5743,"children":5744},{"style":332},[5745],{"type":291,"value":362},{"type":281,"tag":319,"props":5747,"children":5748},{"style":1622},[5749],{"type":291,"value":5705},{"type":281,"tag":319,"props":5751,"children":5752},{"style":332},[5753],{"type":291,"value":5076},{"type":281,"tag":319,"props":5755,"children":5756},{"class":321,"line":2768},[5757,5762,5766],{"type":281,"tag":319,"props":5758,"children":5759},{"style":5058},[5760],{"type":291,"value":5761},"      \"symfony/runtime\"",{"type":281,"tag":319,"props":5763,"children":5764},{"style":332},[5765],{"type":291,"value":362},{"type":281,"tag":319,"props":5767,"children":5768},{"style":1622},[5769],{"type":291,"value":4800},{"type":281,"tag":319,"props":5771,"children":5772},{"class":321,"line":2781},[5773],{"type":281,"tag":319,"props":5774,"children":5775},{"style":332},[5776],{"type":291,"value":5387},{"type":281,"tag":319,"props":5778,"children":5779},{"class":321,"line":2801},[5780,5785,5789,5793],{"type":281,"tag":319,"props":5781,"children":5782},{"style":5058},[5783],{"type":291,"value":5784},"    \"optimize-autoloader\"",{"type":281,"tag":319,"props":5786,"children":5787},{"style":332},[5788],{"type":291,"value":362},{"type":281,"tag":319,"props":5790,"children":5791},{"style":1622},[5792],{"type":291,"value":5705},{"type":281,"tag":319,"props":5794,"children":5795},{"style":332},[5796],{"type":291,"value":5076},{"type":281,"tag":319,"props":5798,"children":5799},{"class":321,"line":2821},[5800,5805,5809],{"type":281,"tag":319,"props":5801,"children":5802},{"style":5058},[5803],{"type":291,"value":5804},"    \"sort-packages\"",{"type":281,"tag":319,"props":5806,"children":5807},{"style":332},[5808],{"type":291,"value":362},{"type":281,"tag":319,"props":5810,"children":5811},{"style":1622},[5812],{"type":291,"value":4800},{"type":281,"tag":319,"props":5814,"children":5815},{"class":321,"line":2838},[5816],{"type":281,"tag":319,"props":5817,"children":5818},{"style":332},[5819],{"type":291,"value":5280},{"type":281,"tag":319,"props":5821,"children":5822},{"class":321,"line":3607},[5823,5828],{"type":281,"tag":319,"props":5824,"children":5825},{"style":5058},[5826],{"type":291,"value":5827},"  \"scripts\"",{"type":281,"tag":319,"props":5829,"children":5830},{"style":332},[5831],{"type":291,"value":5131},{"type":281,"tag":319,"props":5833,"children":5834},{"class":321,"line":3615},[5835,5840],{"type":281,"tag":319,"props":5836,"children":5837},{"style":5058},[5838],{"type":291,"value":5839},"    \"auto-scripts\"",{"type":281,"tag":319,"props":5841,"children":5842},{"style":332},[5843],{"type":291,"value":5131},{"type":281,"tag":319,"props":5845,"children":5846},{"class":321,"line":3627},[5847,5852,5856],{"type":281,"tag":319,"props":5848,"children":5849},{"style":5058},[5850],{"type":291,"value":5851},"      \"assets:install\"",{"type":281,"tag":319,"props":5853,"children":5854},{"style":332},[5855],{"type":291,"value":362},{"type":281,"tag":319,"props":5857,"children":5858},{"style":5068},[5859],{"type":291,"value":5860},"\"symfony-cmd\"\n",{"type":281,"tag":319,"props":5862,"children":5863},{"class":321,"line":3639},[5864],{"type":281,"tag":319,"props":5865,"children":5866},{"style":332},[5867],{"type":291,"value":5387},{"type":281,"tag":319,"props":5869,"children":5870},{"class":321,"line":3655},[5871,5876],{"type":281,"tag":319,"props":5872,"children":5873},{"style":5058},[5874],{"type":291,"value":5875},"    \"post-install-cmd\"",{"type":281,"tag":319,"props":5877,"children":5878},{"style":332},[5879],{"type":291,"value":5293},{"type":281,"tag":319,"props":5881,"children":5882},{"class":321,"line":3675},[5883],{"type":281,"tag":319,"props":5884,"children":5885},{"style":5068},[5886],{"type":291,"value":5887},"      \"@auto-scripts\"\n",{"type":281,"tag":319,"props":5889,"children":5890},{"class":321,"line":3691},[5891],{"type":281,"tag":319,"props":5892,"children":5893},{"style":332},[5894],{"type":291,"value":5895},"    ],\n",{"type":281,"tag":319,"props":5897,"children":5898},{"class":321,"line":3703},[5899,5904],{"type":281,"tag":319,"props":5900,"children":5901},{"style":5058},[5902],{"type":291,"value":5903},"    \"post-update-cmd\"",{"type":281,"tag":319,"props":5905,"children":5906},{"style":332},[5907],{"type":291,"value":5293},{"type":281,"tag":319,"props":5909,"children":5910},{"class":321,"line":3715},[5911],{"type":281,"tag":319,"props":5912,"children":5913},{"style":5068},[5914],{"type":291,"value":5887},{"type":281,"tag":319,"props":5916,"children":5917},{"class":321,"line":3727},[5918],{"type":281,"tag":319,"props":5919,"children":5920},{"style":332},[5921],{"type":291,"value":5922},"    ]\n",{"type":281,"tag":319,"props":5924,"children":5925},{"class":321,"line":3739},[5926],{"type":281,"tag":319,"props":5927,"children":5928},{"style":332},[5929],{"type":291,"value":5280},{"type":281,"tag":319,"props":5931,"children":5932},{"class":321,"line":3755},[5933,5938],{"type":281,"tag":319,"props":5934,"children":5935},{"style":5058},[5936],{"type":291,"value":5937},"  \"extra\"",{"type":281,"tag":319,"props":5939,"children":5940},{"style":332},[5941],{"type":291,"value":5131},{"type":281,"tag":319,"props":5943,"children":5944},{"class":321,"line":3767},[5945,5950],{"type":281,"tag":319,"props":5946,"children":5947},{"style":5058},[5948],{"type":291,"value":5949},"    \"symfony\"",{"type":281,"tag":319,"props":5951,"children":5952},{"style":332},[5953],{"type":291,"value":5131},{"type":281,"tag":319,"props":5955,"children":5956},{"class":321,"line":3787},[5957,5962,5966,5970],{"type":281,"tag":319,"props":5958,"children":5959},{"style":5058},[5960],{"type":291,"value":5961},"      \"allow-contrib\"",{"type":281,"tag":319,"props":5963,"children":5964},{"style":332},[5965],{"type":291,"value":362},{"type":281,"tag":319,"props":5967,"children":5968},{"style":1622},[5969],{"type":291,"value":5705},{"type":281,"tag":319,"props":5971,"children":5972},{"style":332},[5973],{"type":291,"value":5076},{"type":281,"tag":319,"props":5975,"children":5976},{"class":321,"line":3807},[5977,5982],{"type":281,"tag":319,"props":5978,"children":5979},{"style":5058},[5980],{"type":291,"value":5981},"      \"endpoint\"",{"type":281,"tag":319,"props":5983,"children":5984},{"style":332},[5985],{"type":291,"value":5293},{"type":281,"tag":319,"props":5987,"children":5988},{"class":321,"line":3823},[5989,5994],{"type":281,"tag":319,"props":5990,"children":5991},{"style":5068},[5992],{"type":291,"value":5993},"        \"https://raw.githubusercontent.com/shopware/recipes/flex/main/index.json\"",{"type":281,"tag":319,"props":5995,"children":5996},{"style":332},[5997],{"type":291,"value":5076},{"type":281,"tag":319,"props":5999,"children":6001},{"class":321,"line":6000},71,[6002],{"type":281,"tag":319,"props":6003,"children":6004},{"style":5068},[6005],{"type":291,"value":6006},"        \"flex://defaults\"\n",{"type":281,"tag":319,"props":6008,"children":6010},{"class":321,"line":6009},72,[6011],{"type":281,"tag":319,"props":6012,"children":6013},{"style":332},[6014],{"type":291,"value":6015},"      ]\n",{"type":281,"tag":319,"props":6017,"children":6019},{"class":321,"line":6018},73,[6020],{"type":281,"tag":319,"props":6021,"children":6022},{"style":332},[6023],{"type":291,"value":5614},{"type":281,"tag":319,"props":6025,"children":6027},{"class":321,"line":6026},74,[6028],{"type":281,"tag":319,"props":6029,"children":6030},{"style":332},[6031],{"type":291,"value":6032},"  }\n",{"type":281,"tag":319,"props":6034,"children":6036},{"class":321,"line":6035},75,[6037],{"type":281,"tag":319,"props":6038,"children":6039},{"style":332},[6040],{"type":291,"value":6041},"}\n",{"type":281,"tag":282,"props":6043,"children":6044},{},[6045],{"type":291,"value":6046},"and require it with",{"type":281,"tag":301,"props":6048,"children":6050},{"className":1597,"code":6049,"language":1596,"meta":8,"style":8},"composer req acme/sample-plugin\n",[6051],{"type":281,"tag":315,"props":6052,"children":6053},{"__ignoreMap":8},[6054],{"type":281,"tag":319,"props":6055,"children":6056},{"class":321,"line":322},[6057,6061,6066],{"type":281,"tag":319,"props":6058,"children":6059},{"style":1607},[6060],{"type":291,"value":4989},{"type":281,"tag":319,"props":6062,"children":6063},{"style":365},[6064],{"type":291,"value":6065}," req",{"type":281,"tag":319,"props":6067,"children":6068},{"style":365},[6069],{"type":291,"value":6070}," acme/sample-plugin\n",{"type":281,"tag":6072,"props":6073,"children":6075},"v-alert",{"type":6074},"error",[6076],{"type":281,"tag":282,"props":6077,"children":6078},{},[6079],{"type":291,"value":6080},"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":281,"tag":1314,"props":6082,"children":6083},{},[],{"type":281,"tag":282,"props":6085,"children":6086},{},[6087,6089,6095],{"type":291,"value":6088},"Yes... this is the downside. We need to use ",{"type":281,"tag":315,"props":6090,"children":6092},{"className":6091},[],[6093],{"type":291,"value":6094},"dev-master",{"type":291,"value":6096}," as a version",{"type":281,"tag":301,"props":6098,"children":6100},{"className":1597,"code":6099,"language":1596,"meta":8,"style":8},"composer req acme/sample-plugin:dev-master\n",[6101],{"type":281,"tag":315,"props":6102,"children":6103},{"__ignoreMap":8},[6104],{"type":281,"tag":319,"props":6105,"children":6106},{"class":321,"line":322},[6107,6111,6115],{"type":281,"tag":319,"props":6108,"children":6109},{"style":1607},[6110],{"type":291,"value":4989},{"type":281,"tag":319,"props":6112,"children":6113},{"style":365},[6114],{"type":291,"value":6065},{"type":281,"tag":319,"props":6116,"children":6117},{"style":365},[6118],{"type":291,"value":6119}," acme/sample-plugin:dev-master\n",{"type":281,"tag":301,"props":6121,"children":6125},{"className":6122,"code":6123,"language":6124,"meta":8,"style":8},"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",[6126],{"type":281,"tag":315,"props":6127,"children":6128},{"__ignoreMap":8},[6129,6137,6145,6153,6161,6169,6177,6185,6193,6201,6209,6217,6225,6232,6240,6247],{"type":281,"tag":319,"props":6130,"children":6131},{"class":321,"line":322},[6132],{"type":281,"tag":319,"props":6133,"children":6134},{},[6135],{"type":291,"value":6136},"./composer.json has been updated\n",{"type":281,"tag":319,"props":6138,"children":6139},{"class":321,"line":338},[6140],{"type":281,"tag":319,"props":6141,"children":6142},{},[6143],{"type":291,"value":6144},"Running composer update acme/sample-plugin\n",{"type":281,"tag":319,"props":6146,"children":6147},{"class":321,"line":351},[6148],{"type":281,"tag":319,"props":6149,"children":6150},{},[6151],{"type":291,"value":6152},"Loading composer repositories with package information                                                                \n",{"type":281,"tag":319,"props":6154,"children":6155},{"class":321,"line":371},[6156],{"type":281,"tag":319,"props":6157,"children":6158},{},[6159],{"type":291,"value":6160},"Updating dependencies                                 \n",{"type":281,"tag":319,"props":6162,"children":6163},{"class":321,"line":306},[6164],{"type":281,"tag":319,"props":6165,"children":6166},{},[6167],{"type":291,"value":6168},"Lock file operations: 1 install, 0 updates, 0 removals\n",{"type":281,"tag":319,"props":6170,"children":6171},{"class":321,"line":307},[6172],{"type":281,"tag":319,"props":6173,"children":6174},{},[6175],{"type":291,"value":6176},"  - Locking acme/sample-plugin (dev-master 294414d)\n",{"type":281,"tag":319,"props":6178,"children":6179},{"class":321,"line":308},[6180],{"type":281,"tag":319,"props":6181,"children":6182},{},[6183],{"type":291,"value":6184},"Writing lock file\n",{"type":281,"tag":319,"props":6186,"children":6187},{"class":321,"line":309},[6188],{"type":281,"tag":319,"props":6189,"children":6190},{},[6191],{"type":291,"value":6192},"Installing dependencies from lock file (including require-dev)\n",{"type":281,"tag":319,"props":6194,"children":6195},{"class":321,"line":310},[6196],{"type":281,"tag":319,"props":6197,"children":6198},{},[6199],{"type":291,"value":6200},"Package operations: 1 install, 0 updates, 0 removals\n",{"type":281,"tag":319,"props":6202,"children":6203},{"class":321,"line":973},[6204],{"type":281,"tag":319,"props":6205,"children":6206},{},[6207],{"type":291,"value":6208},"  - Syncing acme/sample-plugin (dev-master 294414d) into cache\n",{"type":281,"tag":319,"props":6210,"children":6211},{"class":321,"line":986},[6212],{"type":281,"tag":319,"props":6213,"children":6214},{},[6215],{"type":291,"value":6216},"  - Installing acme/sample-plugin (dev-master 294414d): Cloning 294414deb2 from cache\n",{"type":281,"tag":319,"props":6218,"children":6219},{"class":321,"line":999},[6220],{"type":281,"tag":319,"props":6221,"children":6222},{},[6223],{"type":291,"value":6224},"Generating optimized autoload files\n",{"type":281,"tag":319,"props":6226,"children":6227},{"class":321,"line":1012},[6228],{"type":281,"tag":319,"props":6229,"children":6230},{"emptyLinePlaceholder":1042},[6231],{"type":291,"value":1045},{"type":281,"tag":319,"props":6233,"children":6234},{"class":321,"line":1025},[6235],{"type":281,"tag":319,"props":6236,"children":6237},{},[6238],{"type":291,"value":6239},"Run composer recipes at any time to see the status of your Symfony recipes.\n",{"type":281,"tag":319,"props":6241,"children":6242},{"class":321,"line":1038},[6243],{"type":281,"tag":319,"props":6244,"children":6245},{"emptyLinePlaceholder":1042},[6246],{"type":291,"value":1045},{"type":281,"tag":319,"props":6248,"children":6249},{"class":321,"line":1048},[6250],{"type":281,"tag":319,"props":6251,"children":6252},{},[6253],{"type":291,"value":6254},"Executing script assets:install [OK]\n",{"type":281,"tag":282,"props":6256,"children":6257},{},[6258,6260,6265],{"type":291,"value":6259},"Composer will use ",{"type":281,"tag":315,"props":6261,"children":6263},{"className":6262},[],[6264],{"type":291,"value":554},{"type":291,"value":6266}," to clone our repo and use the default branch and the commit hash to track the release.",{"type":281,"tag":282,"props":6268,"children":6269},{},[6270],{"type":291,"value":6271},"This works, but we can do better.",{"type":281,"tag":1248,"props":6273,"children":6275},{"id":6274},"git-tags",[6276],{"type":291,"value":6277},"Git tags",{"type":281,"tag":282,"props":6279,"children":6280},{},[6281,6283,6289],{"type":291,"value":6282},"Let's tag our plugin with ",{"type":281,"tag":315,"props":6284,"children":6286},{"className":6285},[],[6287],{"type":291,"value":6288},"v1.0.0",{"type":291,"value":564},{"type":281,"tag":282,"props":6291,"children":6292},{},[6293,6295,6301,6303,6309],{"type":291,"value":6294},"Make sure to set the ",{"type":281,"tag":315,"props":6296,"children":6298},{"className":6297},[],[6299],{"type":291,"value":6300},"version",{"type":291,"value":6302}," in ",{"type":281,"tag":315,"props":6304,"children":6306},{"className":6305},[],[6307],{"type":291,"value":6308},"composer.json",{"type":291,"value":564},{"type":281,"tag":301,"props":6311,"children":6315},{"className":5036,"code":6312,"filename":6313,"highlights":6314,"language":5040,"meta":8,"style":8},"{\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",[306],[6316],{"type":281,"tag":315,"props":6317,"children":6318},{"__ignoreMap":8},[6319,6326,6347,6367,6388,6410,6430,6442,6459,6466,6478,6508,6520,6541,6558,6566,6573,6585,6597,6621,6628,6635,6647,6658,6691,6698,6705],{"type":281,"tag":319,"props":6320,"children":6321},{"class":321,"line":322},[6322],{"type":281,"tag":319,"props":6323,"children":6324},{"style":332},[6325],{"type":291,"value":5052},{"type":281,"tag":319,"props":6327,"children":6328},{"class":321,"line":338},[6329,6334,6338,6343],{"type":281,"tag":319,"props":6330,"children":6331},{"style":5058},[6332],{"type":291,"value":6333},"    \"name\"",{"type":281,"tag":319,"props":6335,"children":6336},{"style":332},[6337],{"type":291,"value":362},{"type":281,"tag":319,"props":6339,"children":6340},{"style":5068},[6341],{"type":291,"value":6342},"\"acme/sample-plugin\"",{"type":281,"tag":319,"props":6344,"children":6345},{"style":332},[6346],{"type":291,"value":5076},{"type":281,"tag":319,"props":6348,"children":6349},{"class":321,"line":351},[6350,6355,6359,6363],{"type":281,"tag":319,"props":6351,"children":6352},{"style":5058},[6353],{"type":291,"value":6354},"    \"description\"",{"type":281,"tag":319,"props":6356,"children":6357},{"style":332},[6358],{"type":291,"value":362},{"type":281,"tag":319,"props":6360,"children":6361},{"style":5068},[6362],{"type":291,"value":6342},{"type":281,"tag":319,"props":6364,"children":6365},{"style":332},[6366],{"type":291,"value":5076},{"type":281,"tag":319,"props":6368,"children":6369},{"class":321,"line":371},[6370,6375,6379,6384],{"type":281,"tag":319,"props":6371,"children":6372},{"style":5058},[6373],{"type":291,"value":6374},"    \"type\"",{"type":281,"tag":319,"props":6376,"children":6377},{"style":332},[6378],{"type":291,"value":362},{"type":281,"tag":319,"props":6380,"children":6381},{"style":5068},[6382],{"type":291,"value":6383},"\"shopware-platform-plugin\"",{"type":281,"tag":319,"props":6385,"children":6386},{"style":332},[6387],{"type":291,"value":5076},{"type":281,"tag":319,"props":6389,"children":6391},{"class":6390,"line":306},[321,385],[6392,6397,6401,6406],{"type":281,"tag":319,"props":6393,"children":6394},{"style":5058},[6395],{"type":291,"value":6396},"    \"version\"",{"type":281,"tag":319,"props":6398,"children":6399},{"style":332},[6400],{"type":291,"value":362},{"type":281,"tag":319,"props":6402,"children":6403},{"style":5068},[6404],{"type":291,"value":6405},"\"1.0.0\"",{"type":281,"tag":319,"props":6407,"children":6408},{"style":332},[6409],{"type":291,"value":5076},{"type":281,"tag":319,"props":6411,"children":6412},{"class":321,"line":307},[6413,6418,6422,6426],{"type":281,"tag":319,"props":6414,"children":6415},{"style":5058},[6416],{"type":291,"value":6417},"    \"license\"",{"type":281,"tag":319,"props":6419,"children":6420},{"style":332},[6421],{"type":291,"value":362},{"type":281,"tag":319,"props":6423,"children":6424},{"style":5068},[6425],{"type":291,"value":5093},{"type":281,"tag":319,"props":6427,"children":6428},{"style":332},[6429],{"type":291,"value":5076},{"type":281,"tag":319,"props":6431,"children":6432},{"class":321,"line":308},[6433,6438],{"type":281,"tag":319,"props":6434,"children":6435},{"style":5058},[6436],{"type":291,"value":6437},"    \"require\"",{"type":281,"tag":319,"props":6439,"children":6440},{"style":332},[6441],{"type":291,"value":5131},{"type":281,"tag":319,"props":6443,"children":6444},{"class":321,"line":309},[6445,6450,6454],{"type":281,"tag":319,"props":6446,"children":6447},{"style":5058},[6448],{"type":291,"value":6449},"        \"shopware/core\"",{"type":281,"tag":319,"props":6451,"children":6452},{"style":332},[6453],{"type":291,"value":362},{"type":281,"tag":319,"props":6455,"children":6456},{"style":5068},[6457],{"type":291,"value":6458},"\"~6.6.0\"\n",{"type":281,"tag":319,"props":6460,"children":6461},{"class":321,"line":310},[6462],{"type":281,"tag":319,"props":6463,"children":6464},{"style":332},[6465],{"type":291,"value":5387},{"type":281,"tag":319,"props":6467,"children":6468},{"class":321,"line":973},[6469,6474],{"type":281,"tag":319,"props":6470,"children":6471},{"style":5058},[6472],{"type":291,"value":6473},"    \"extra\"",{"type":281,"tag":319,"props":6475,"children":6476},{"style":332},[6477],{"type":291,"value":5131},{"type":281,"tag":319,"props":6479,"children":6480},{"class":321,"line":986},[6481,6486,6490,6495,6499,6504],{"type":281,"tag":319,"props":6482,"children":6483},{"style":5058},[6484],{"type":291,"value":6485},"        \"shopware-plugin-class\"",{"type":281,"tag":319,"props":6487,"children":6488},{"style":332},[6489],{"type":291,"value":362},{"type":281,"tag":319,"props":6491,"children":6492},{"style":5068},[6493],{"type":291,"value":6494},"\"Acme",{"type":281,"tag":319,"props":6496,"children":6497},{"style":1622},[6498],{"type":291,"value":5660},{"type":281,"tag":319,"props":6500,"children":6501},{"style":5068},[6502],{"type":291,"value":6503},"SamplePlugin\"",{"type":281,"tag":319,"props":6505,"children":6506},{"style":332},[6507],{"type":291,"value":5076},{"type":281,"tag":319,"props":6509,"children":6510},{"class":321,"line":999},[6511,6516],{"type":281,"tag":319,"props":6512,"children":6513},{"style":5058},[6514],{"type":291,"value":6515},"        \"label\"",{"type":281,"tag":319,"props":6517,"children":6518},{"style":332},[6519],{"type":291,"value":5131},{"type":281,"tag":319,"props":6521,"children":6522},{"class":321,"line":1012},[6523,6528,6532,6537],{"type":281,"tag":319,"props":6524,"children":6525},{"style":5058},[6526],{"type":291,"value":6527},"            \"de-DE\"",{"type":281,"tag":319,"props":6529,"children":6530},{"style":332},[6531],{"type":291,"value":362},{"type":281,"tag":319,"props":6533,"children":6534},{"style":5068},[6535],{"type":291,"value":6536},"\"Skeleton plugin\"",{"type":281,"tag":319,"props":6538,"children":6539},{"style":332},[6540],{"type":291,"value":5076},{"type":281,"tag":319,"props":6542,"children":6543},{"class":321,"line":1025},[6544,6549,6553],{"type":281,"tag":319,"props":6545,"children":6546},{"style":5058},[6547],{"type":291,"value":6548},"            \"en-GB\"",{"type":281,"tag":319,"props":6550,"children":6551},{"style":332},[6552],{"type":291,"value":362},{"type":281,"tag":319,"props":6554,"children":6555},{"style":5068},[6556],{"type":291,"value":6557},"\"Skeleton plugin\"\n",{"type":281,"tag":319,"props":6559,"children":6560},{"class":321,"line":1038},[6561],{"type":281,"tag":319,"props":6562,"children":6563},{"style":332},[6564],{"type":291,"value":6565},"        }\n",{"type":281,"tag":319,"props":6567,"children":6568},{"class":321,"line":1048},[6569],{"type":281,"tag":319,"props":6570,"children":6571},{"style":332},[6572],{"type":291,"value":5387},{"type":281,"tag":319,"props":6574,"children":6575},{"class":321,"line":1061},[6576,6581],{"type":281,"tag":319,"props":6577,"children":6578},{"style":5058},[6579],{"type":291,"value":6580},"    \"autoload\"",{"type":281,"tag":319,"props":6582,"children":6583},{"style":332},[6584],{"type":291,"value":5131},{"type":281,"tag":319,"props":6586,"children":6587},{"class":321,"line":1074},[6588,6593],{"type":281,"tag":319,"props":6589,"children":6590},{"style":5058},[6591],{"type":291,"value":6592},"        \"psr-4\"",{"type":281,"tag":319,"props":6594,"children":6595},{"style":332},[6596],{"type":291,"value":5131},{"type":281,"tag":319,"props":6598,"children":6599},{"class":321,"line":1083},[6600,6605,6609,6613,6617],{"type":281,"tag":319,"props":6601,"children":6602},{"style":5058},[6603],{"type":291,"value":6604},"            \"Acme",{"type":281,"tag":319,"props":6606,"children":6607},{"style":5657},[6608],{"type":291,"value":5660},{"type":281,"tag":319,"props":6610,"children":6611},{"style":5058},[6612],{"type":291,"value":5665},{"type":281,"tag":319,"props":6614,"children":6615},{"style":332},[6616],{"type":291,"value":362},{"type":281,"tag":319,"props":6618,"children":6619},{"style":5068},[6620],{"type":291,"value":5674},{"type":281,"tag":319,"props":6622,"children":6623},{"class":321,"line":1096},[6624],{"type":281,"tag":319,"props":6625,"children":6626},{"style":332},[6627],{"type":291,"value":6565},{"type":281,"tag":319,"props":6629,"children":6630},{"class":321,"line":1109},[6631],{"type":281,"tag":319,"props":6632,"children":6633},{"style":332},[6634],{"type":291,"value":5387},{"type":281,"tag":319,"props":6636,"children":6637},{"class":321,"line":1122},[6638,6643],{"type":281,"tag":319,"props":6639,"children":6640},{"style":5058},[6641],{"type":291,"value":6642},"    \"autoload-dev\"",{"type":281,"tag":319,"props":6644,"children":6645},{"style":332},[6646],{"type":291,"value":5131},{"type":281,"tag":319,"props":6648,"children":6649},{"class":321,"line":1130},[6650,6654],{"type":281,"tag":319,"props":6651,"children":6652},{"style":5058},[6653],{"type":291,"value":6592},{"type":281,"tag":319,"props":6655,"children":6656},{"style":332},[6657],{"type":291,"value":5131},{"type":281,"tag":319,"props":6659,"children":6660},{"class":321,"line":1143},[6661,6665,6669,6674,6678,6682,6686],{"type":281,"tag":319,"props":6662,"children":6663},{"style":5058},[6664],{"type":291,"value":6604},{"type":281,"tag":319,"props":6666,"children":6667},{"style":5657},[6668],{"type":291,"value":5660},{"type":281,"tag":319,"props":6670,"children":6671},{"style":5058},[6672],{"type":291,"value":6673},"Tests",{"type":281,"tag":319,"props":6675,"children":6676},{"style":5657},[6677],{"type":291,"value":5660},{"type":281,"tag":319,"props":6679,"children":6680},{"style":5058},[6681],{"type":291,"value":5665},{"type":281,"tag":319,"props":6683,"children":6684},{"style":332},[6685],{"type":291,"value":362},{"type":281,"tag":319,"props":6687,"children":6688},{"style":5068},[6689],{"type":291,"value":6690},"\"tests/\"\n",{"type":281,"tag":319,"props":6692,"children":6693},{"class":321,"line":1156},[6694],{"type":281,"tag":319,"props":6695,"children":6696},{"style":332},[6697],{"type":291,"value":6565},{"type":281,"tag":319,"props":6699,"children":6700},{"class":321,"line":1169},[6701],{"type":281,"tag":319,"props":6702,"children":6703},{"style":332},[6704],{"type":291,"value":5614},{"type":281,"tag":319,"props":6706,"children":6707},{"class":321,"line":1182},[6708],{"type":281,"tag":319,"props":6709,"children":6710},{"style":332},[6711],{"type":291,"value":6041},{"type":281,"tag":301,"props":6713,"children":6715},{"className":1597,"code":6714,"language":1596,"meta":8,"style":8},"git tag v1.0.0\ngit push --tags\n",[6716],{"type":281,"tag":315,"props":6717,"children":6718},{"__ignoreMap":8},[6719,6736],{"type":281,"tag":319,"props":6720,"children":6721},{"class":321,"line":322},[6722,6726,6731],{"type":281,"tag":319,"props":6723,"children":6724},{"style":1607},[6725],{"type":291,"value":554},{"type":281,"tag":319,"props":6727,"children":6728},{"style":365},[6729],{"type":291,"value":6730}," tag",{"type":281,"tag":319,"props":6732,"children":6733},{"style":365},[6734],{"type":291,"value":6735}," v1.0.0\n",{"type":281,"tag":319,"props":6737,"children":6738},{"class":321,"line":338},[6739,6743,6748],{"type":281,"tag":319,"props":6740,"children":6741},{"style":1607},[6742],{"type":291,"value":554},{"type":281,"tag":319,"props":6744,"children":6745},{"style":365},[6746],{"type":291,"value":6747}," push",{"type":281,"tag":319,"props":6749,"children":6750},{"style":1622},[6751],{"type":291,"value":6752}," --tags\n",{"type":281,"tag":282,"props":6754,"children":6755},{},[6756],{"type":291,"value":6757},"Now this will work:",{"type":281,"tag":301,"props":6759,"children":6760},{"className":1597,"code":6049,"language":1596,"meta":8,"style":8},[6761],{"type":281,"tag":315,"props":6762,"children":6763},{"__ignoreMap":8},[6764],{"type":281,"tag":319,"props":6765,"children":6766},{"class":321,"line":322},[6767,6771,6775],{"type":281,"tag":319,"props":6768,"children":6769},{"style":1607},[6770],{"type":291,"value":4989},{"type":281,"tag":319,"props":6772,"children":6773},{"style":365},[6774],{"type":291,"value":6065},{"type":281,"tag":319,"props":6776,"children":6777},{"style":365},[6778],{"type":291,"value":6070},{"type":281,"tag":301,"props":6780,"children":6784},{"className":6781,"code":6782,"language":6783,"meta":8,"style":8},"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",[6785],{"type":281,"tag":315,"props":6786,"children":6787},{"__ignoreMap":8},[6788,6796,6803,6811,6819,6826,6834,6841,6848,6855,6863,6871,6878,6885,6892,6899,6906,6913],{"type":281,"tag":319,"props":6789,"children":6790},{"class":321,"line":322},[6791],{"type":281,"tag":319,"props":6792,"children":6793},{},[6794],{"type":291,"value":6795},"./composer.json has been updated                                                                                                            \n",{"type":281,"tag":319,"props":6797,"children":6798},{"class":321,"line":338},[6799],{"type":281,"tag":319,"props":6800,"children":6801},{},[6802],{"type":291,"value":6144},{"type":281,"tag":319,"props":6804,"children":6805},{"class":321,"line":351},[6806],{"type":281,"tag":319,"props":6807,"children":6808},{},[6809],{"type":291,"value":6810},"Loading composer repositories with package information\n",{"type":281,"tag":319,"props":6812,"children":6813},{"class":321,"line":371},[6814],{"type":281,"tag":319,"props":6815,"children":6816},{},[6817],{"type":291,"value":6818},"Updating dependencies\n",{"type":281,"tag":319,"props":6820,"children":6821},{"class":321,"line":306},[6822],{"type":281,"tag":319,"props":6823,"children":6824},{},[6825],{"type":291,"value":6168},{"type":281,"tag":319,"props":6827,"children":6828},{"class":321,"line":307},[6829],{"type":281,"tag":319,"props":6830,"children":6831},{},[6832],{"type":291,"value":6833},"  - Locking acme/sample-plugin (1.0.0)\n",{"type":281,"tag":319,"props":6835,"children":6836},{"class":321,"line":308},[6837],{"type":281,"tag":319,"props":6838,"children":6839},{},[6840],{"type":291,"value":6184},{"type":281,"tag":319,"props":6842,"children":6843},{"class":321,"line":309},[6844],{"type":281,"tag":319,"props":6845,"children":6846},{},[6847],{"type":291,"value":6192},{"type":281,"tag":319,"props":6849,"children":6850},{"class":321,"line":310},[6851],{"type":281,"tag":319,"props":6852,"children":6853},{},[6854],{"type":291,"value":6200},{"type":281,"tag":319,"props":6856,"children":6857},{"class":321,"line":973},[6858],{"type":281,"tag":319,"props":6859,"children":6860},{},[6861],{"type":291,"value":6862},"  - Syncing acme/sample-plugin (1.0.0) into cache\n",{"type":281,"tag":319,"props":6864,"children":6865},{"class":321,"line":986},[6866],{"type":281,"tag":319,"props":6867,"children":6868},{},[6869],{"type":291,"value":6870},"  - Installing acme/sample-plugin (1.0.0): Cloning 294414deb2 from cache\n",{"type":281,"tag":319,"props":6872,"children":6873},{"class":321,"line":999},[6874],{"type":281,"tag":319,"props":6875,"children":6876},{},[6877],{"type":291,"value":6224},{"type":281,"tag":319,"props":6879,"children":6880},{"class":321,"line":1012},[6881],{"type":281,"tag":319,"props":6882,"children":6883},{"emptyLinePlaceholder":1042},[6884],{"type":291,"value":1045},{"type":281,"tag":319,"props":6886,"children":6887},{"class":321,"line":1025},[6888],{"type":281,"tag":319,"props":6889,"children":6890},{},[6891],{"type":291,"value":6239},{"type":281,"tag":319,"props":6893,"children":6894},{"class":321,"line":1038},[6895],{"type":281,"tag":319,"props":6896,"children":6897},{"emptyLinePlaceholder":1042},[6898],{"type":291,"value":1045},{"type":281,"tag":319,"props":6900,"children":6901},{"class":321,"line":1048},[6902],{"type":281,"tag":319,"props":6903,"children":6904},{},[6905],{"type":291,"value":6254},{"type":281,"tag":319,"props":6907,"children":6908},{"class":321,"line":1061},[6909],{"type":281,"tag":319,"props":6910,"children":6911},{"emptyLinePlaceholder":1042},[6912],{"type":291,"value":1045},{"type":281,"tag":319,"props":6914,"children":6915},{"class":321,"line":1074},[6916],{"type":281,"tag":319,"props":6917,"children":6918},{},[6919],{"type":291,"value":6920},"Using version ^1.0 for acme/sample-plugin\n",{"type":281,"tag":282,"props":6922,"children":6923},{},[6924,6926,6931],{"type":291,"value":6925},"This is better, but we are still using ",{"type":281,"tag":315,"props":6927,"children":6929},{"className":6928},[],[6930],{"type":291,"value":554},{"type":291,"value":6932}," to fetch the plugin. We can do better.",{"type":281,"tag":1248,"props":6934,"children":6936},{"id":6935},"gitlab-package-registry",[6937],{"type":291,"value":6938},"GitLab Package registry",{"type":281,"tag":282,"props":6940,"children":6941},{},[6942,6944,6949],{"type":291,"value":6943},"Here is where the GitLab part starts. For more details refer to the ",{"type":281,"tag":286,"props":6945,"children":6947},{"href":6946},"https://docs.gitlab.com/18.3/user/packages/composer_repository/",[6948],{"type":291,"value":3963},{"type":291,"value":564},{"type":281,"tag":282,"props":6951,"children":6952},{},[6953],{"type":291,"value":6954},"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":281,"tag":282,"props":6956,"children":6957},{},[6958,6960,6965],{"type":291,"value":6959},"Let's release our ",{"type":281,"tag":315,"props":6961,"children":6963},{"className":6962},[],[6964],{"type":291,"value":6288},{"type":291,"value":6966}," tag as a composer package.",{"type":281,"tag":301,"props":6968,"children":6970},{"className":1597,"code":6969,"language":1596,"meta":8,"style":8},"curl --fail-with-body --data tag=v1.0.0 \"https://__token__:\u003Cpersonal-access-token>@\u003CDOMAIN-NAME>/api/v4/projects/\u003Cproject_id>/packages/composer\"\n",[6971],{"type":281,"tag":315,"props":6972,"children":6973},{"__ignoreMap":8},[6974],{"type":281,"tag":319,"props":6975,"children":6976},{"class":321,"line":322},[6977,6982,6987,6992,6997],{"type":281,"tag":319,"props":6978,"children":6979},{"style":1607},[6980],{"type":291,"value":6981},"curl",{"type":281,"tag":319,"props":6983,"children":6984},{"style":1622},[6985],{"type":291,"value":6986}," --fail-with-body",{"type":281,"tag":319,"props":6988,"children":6989},{"style":1622},[6990],{"type":291,"value":6991}," --data",{"type":281,"tag":319,"props":6993,"children":6994},{"style":365},[6995],{"type":291,"value":6996}," tag=v1.0.0",{"type":281,"tag":319,"props":6998,"children":6999},{"style":365},[7000],{"type":291,"value":7001}," \"https://__token__:\u003Cpersonal-access-token>@\u003CDOMAIN-NAME>/api/v4/projects/\u003Cproject_id>/packages/composer\"\n",{"type":281,"tag":282,"props":7003,"children":7004},{},[7005],{"type":291,"value":7006},"Now we need to update the repository information:",{"type":281,"tag":301,"props":7008,"children":7011},{"className":5036,"code":7009,"filename":5038,"highlights":7010,"language":5040,"meta":8,"style":8},"{\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",[2055,2579,2056,2605],[7012],{"type":281,"tag":315,"props":7013,"children":7014},{"__ignoreMap":8},[7015,7022,7041,7060,7079,7090,7109,7128,7147,7166,7185,7204,7219,7226,7237,7244,7263,7282,7293,7308,7315,7322,7329,7348,7367,7378,7393,7400,7407,7414,7433,7452,7463,7478,7485,7492,7500,7521,7538,7546,7553,7564,7575,7598,7605,7612,7631,7642,7653,7672,7687,7694,7713,7728,7735,7746,7757,7772,7779,7790,7797,7804,7815,7822,7829,7836,7847,7858,7877,7888,7899,7906,7913,7920,7927],{"type":281,"tag":319,"props":7016,"children":7017},{"class":321,"line":322},[7018],{"type":281,"tag":319,"props":7019,"children":7020},{"style":332},[7021],{"type":291,"value":5052},{"type":281,"tag":319,"props":7023,"children":7024},{"class":321,"line":338},[7025,7029,7033,7037],{"type":281,"tag":319,"props":7026,"children":7027},{"style":5058},[7028],{"type":291,"value":5061},{"type":281,"tag":319,"props":7030,"children":7031},{"style":332},[7032],{"type":291,"value":362},{"type":281,"tag":319,"props":7034,"children":7035},{"style":5068},[7036],{"type":291,"value":5071},{"type":281,"tag":319,"props":7038,"children":7039},{"style":332},[7040],{"type":291,"value":5076},{"type":281,"tag":319,"props":7042,"children":7043},{"class":321,"line":351},[7044,7048,7052,7056],{"type":281,"tag":319,"props":7045,"children":7046},{"style":5058},[7047],{"type":291,"value":5084},{"type":281,"tag":319,"props":7049,"children":7050},{"style":332},[7051],{"type":291,"value":362},{"type":281,"tag":319,"props":7053,"children":7054},{"style":5068},[7055],{"type":291,"value":5093},{"type":281,"tag":319,"props":7057,"children":7058},{"style":332},[7059],{"type":291,"value":5076},{"type":281,"tag":319,"props":7061,"children":7062},{"class":321,"line":371},[7063,7067,7071,7075],{"type":281,"tag":319,"props":7064,"children":7065},{"style":5058},[7066],{"type":291,"value":5105},{"type":281,"tag":319,"props":7068,"children":7069},{"style":332},[7070],{"type":291,"value":362},{"type":281,"tag":319,"props":7072,"children":7073},{"style":5068},[7074],{"type":291,"value":5114},{"type":281,"tag":319,"props":7076,"children":7077},{"style":332},[7078],{"type":291,"value":5076},{"type":281,"tag":319,"props":7080,"children":7081},{"class":321,"line":306},[7082,7086],{"type":281,"tag":319,"props":7083,"children":7084},{"style":5058},[7085],{"type":291,"value":5126},{"type":281,"tag":319,"props":7087,"children":7088},{"style":332},[7089],{"type":291,"value":5131},{"type":281,"tag":319,"props":7091,"children":7092},{"class":321,"line":307},[7093,7097,7101,7105],{"type":281,"tag":319,"props":7094,"children":7095},{"style":5058},[7096],{"type":291,"value":5139},{"type":281,"tag":319,"props":7098,"children":7099},{"style":332},[7100],{"type":291,"value":362},{"type":281,"tag":319,"props":7102,"children":7103},{"style":5068},[7104],{"type":291,"value":5148},{"type":281,"tag":319,"props":7106,"children":7107},{"style":332},[7108],{"type":291,"value":5076},{"type":281,"tag":319,"props":7110,"children":7111},{"class":321,"line":308},[7112,7116,7120,7124],{"type":281,"tag":319,"props":7113,"children":7114},{"style":5058},[7115],{"type":291,"value":5160},{"type":281,"tag":319,"props":7117,"children":7118},{"style":332},[7119],{"type":291,"value":362},{"type":281,"tag":319,"props":7121,"children":7122},{"style":5068},[7123],{"type":291,"value":5169},{"type":281,"tag":319,"props":7125,"children":7126},{"style":332},[7127],{"type":291,"value":5076},{"type":281,"tag":319,"props":7129,"children":7130},{"class":321,"line":309},[7131,7135,7139,7143],{"type":281,"tag":319,"props":7132,"children":7133},{"style":5058},[7134],{"type":291,"value":5181},{"type":281,"tag":319,"props":7136,"children":7137},{"style":332},[7138],{"type":291,"value":362},{"type":281,"tag":319,"props":7140,"children":7141},{"style":5068},[7142],{"type":291,"value":5190},{"type":281,"tag":319,"props":7144,"children":7145},{"style":332},[7146],{"type":291,"value":5076},{"type":281,"tag":319,"props":7148,"children":7149},{"class":321,"line":310},[7150,7154,7158,7162],{"type":281,"tag":319,"props":7151,"children":7152},{"style":5058},[7153],{"type":291,"value":5202},{"type":281,"tag":319,"props":7155,"children":7156},{"style":332},[7157],{"type":291,"value":362},{"type":281,"tag":319,"props":7159,"children":7160},{"style":5068},[7161],{"type":291,"value":5211},{"type":281,"tag":319,"props":7163,"children":7164},{"style":332},[7165],{"type":291,"value":5076},{"type":281,"tag":319,"props":7167,"children":7168},{"class":321,"line":973},[7169,7173,7177,7181],{"type":281,"tag":319,"props":7170,"children":7171},{"style":5058},[7172],{"type":291,"value":5223},{"type":281,"tag":319,"props":7174,"children":7175},{"style":332},[7176],{"type":291,"value":362},{"type":281,"tag":319,"props":7178,"children":7179},{"style":5068},[7180],{"type":291,"value":5190},{"type":281,"tag":319,"props":7182,"children":7183},{"style":332},[7184],{"type":291,"value":5076},{"type":281,"tag":319,"props":7186,"children":7187},{"class":321,"line":986},[7188,7192,7196,7200],{"type":281,"tag":319,"props":7189,"children":7190},{"style":5058},[7191],{"type":291,"value":5243},{"type":281,"tag":319,"props":7193,"children":7194},{"style":332},[7195],{"type":291,"value":362},{"type":281,"tag":319,"props":7197,"children":7198},{"style":5068},[7199],{"type":291,"value":5190},{"type":281,"tag":319,"props":7201,"children":7202},{"style":332},[7203],{"type":291,"value":5076},{"type":281,"tag":319,"props":7205,"children":7206},{"class":321,"line":999},[7207,7211,7215],{"type":281,"tag":319,"props":7208,"children":7209},{"style":5058},[7210],{"type":291,"value":5263},{"type":281,"tag":319,"props":7212,"children":7213},{"style":332},[7214],{"type":291,"value":362},{"type":281,"tag":319,"props":7216,"children":7217},{"style":5068},[7218],{"type":291,"value":5272},{"type":281,"tag":319,"props":7220,"children":7221},{"class":321,"line":1012},[7222],{"type":281,"tag":319,"props":7223,"children":7224},{"style":332},[7225],{"type":291,"value":5280},{"type":281,"tag":319,"props":7227,"children":7228},{"class":321,"line":1025},[7229,7233],{"type":281,"tag":319,"props":7230,"children":7231},{"style":5058},[7232],{"type":291,"value":5288},{"type":281,"tag":319,"props":7234,"children":7235},{"style":332},[7236],{"type":291,"value":5293},{"type":281,"tag":319,"props":7238,"children":7239},{"class":321,"line":1038},[7240],{"type":281,"tag":319,"props":7241,"children":7242},{"style":332},[7243],{"type":291,"value":5301},{"type":281,"tag":319,"props":7245,"children":7246},{"class":321,"line":1048},[7247,7251,7255,7259],{"type":281,"tag":319,"props":7248,"children":7249},{"style":5058},[7250],{"type":291,"value":5309},{"type":281,"tag":319,"props":7252,"children":7253},{"style":332},[7254],{"type":291,"value":362},{"type":281,"tag":319,"props":7256,"children":7257},{"style":5068},[7258],{"type":291,"value":5318},{"type":281,"tag":319,"props":7260,"children":7261},{"style":332},[7262],{"type":291,"value":5076},{"type":281,"tag":319,"props":7264,"children":7265},{"class":321,"line":1061},[7266,7270,7274,7278],{"type":281,"tag":319,"props":7267,"children":7268},{"style":5058},[7269],{"type":291,"value":5330},{"type":281,"tag":319,"props":7271,"children":7272},{"style":332},[7273],{"type":291,"value":362},{"type":281,"tag":319,"props":7275,"children":7276},{"style":5068},[7277],{"type":291,"value":5339},{"type":281,"tag":319,"props":7279,"children":7280},{"style":332},[7281],{"type":291,"value":5076},{"type":281,"tag":319,"props":7283,"children":7284},{"class":321,"line":1074},[7285,7289],{"type":281,"tag":319,"props":7286,"children":7287},{"style":5058},[7288],{"type":291,"value":5351},{"type":281,"tag":319,"props":7290,"children":7291},{"style":332},[7292],{"type":291,"value":5131},{"type":281,"tag":319,"props":7294,"children":7295},{"class":321,"line":1083},[7296,7300,7304],{"type":281,"tag":319,"props":7297,"children":7298},{"style":5058},[7299],{"type":291,"value":5363},{"type":281,"tag":319,"props":7301,"children":7302},{"style":332},[7303],{"type":291,"value":362},{"type":281,"tag":319,"props":7305,"children":7306},{"style":1622},[7307],{"type":291,"value":4800},{"type":281,"tag":319,"props":7309,"children":7310},{"class":321,"line":1096},[7311],{"type":281,"tag":319,"props":7312,"children":7313},{"style":332},[7314],{"type":291,"value":5379},{"type":281,"tag":319,"props":7316,"children":7317},{"class":321,"line":1109},[7318],{"type":281,"tag":319,"props":7319,"children":7320},{"style":332},[7321],{"type":291,"value":5387},{"type":281,"tag":319,"props":7323,"children":7324},{"class":321,"line":1122},[7325],{"type":281,"tag":319,"props":7326,"children":7327},{"style":332},[7328],{"type":291,"value":5301},{"type":281,"tag":319,"props":7330,"children":7331},{"class":321,"line":1130},[7332,7336,7340,7344],{"type":281,"tag":319,"props":7333,"children":7334},{"style":5058},[7335],{"type":291,"value":5309},{"type":281,"tag":319,"props":7337,"children":7338},{"style":332},[7339],{"type":291,"value":362},{"type":281,"tag":319,"props":7341,"children":7342},{"style":5068},[7343],{"type":291,"value":5318},{"type":281,"tag":319,"props":7345,"children":7346},{"style":332},[7347],{"type":291,"value":5076},{"type":281,"tag":319,"props":7349,"children":7350},{"class":321,"line":1143},[7351,7355,7359,7363],{"type":281,"tag":319,"props":7352,"children":7353},{"style":5058},[7354],{"type":291,"value":5330},{"type":281,"tag":319,"props":7356,"children":7357},{"style":332},[7358],{"type":291,"value":362},{"type":281,"tag":319,"props":7360,"children":7361},{"style":5068},[7362],{"type":291,"value":5429},{"type":281,"tag":319,"props":7364,"children":7365},{"style":332},[7366],{"type":291,"value":5076},{"type":281,"tag":319,"props":7368,"children":7369},{"class":321,"line":1156},[7370,7374],{"type":281,"tag":319,"props":7371,"children":7372},{"style":5058},[7373],{"type":291,"value":5351},{"type":281,"tag":319,"props":7375,"children":7376},{"style":332},[7377],{"type":291,"value":5131},{"type":281,"tag":319,"props":7379,"children":7380},{"class":321,"line":1169},[7381,7385,7389],{"type":281,"tag":319,"props":7382,"children":7383},{"style":5058},[7384],{"type":291,"value":5363},{"type":281,"tag":319,"props":7386,"children":7387},{"style":332},[7388],{"type":291,"value":362},{"type":281,"tag":319,"props":7390,"children":7391},{"style":1622},[7392],{"type":291,"value":4800},{"type":281,"tag":319,"props":7394,"children":7395},{"class":321,"line":1182},[7396],{"type":281,"tag":319,"props":7397,"children":7398},{"style":332},[7399],{"type":291,"value":5379},{"type":281,"tag":319,"props":7401,"children":7402},{"class":321,"line":1195},[7403],{"type":281,"tag":319,"props":7404,"children":7405},{"style":332},[7406],{"type":291,"value":5387},{"type":281,"tag":319,"props":7408,"children":7409},{"class":321,"line":2048},[7410],{"type":281,"tag":319,"props":7411,"children":7412},{"style":332},[7413],{"type":291,"value":5301},{"type":281,"tag":319,"props":7415,"children":7416},{"class":321,"line":2049},[7417,7421,7425,7429],{"type":281,"tag":319,"props":7418,"children":7419},{"style":5058},[7420],{"type":291,"value":5309},{"type":281,"tag":319,"props":7422,"children":7423},{"style":332},[7424],{"type":291,"value":362},{"type":281,"tag":319,"props":7426,"children":7427},{"style":5068},[7428],{"type":291,"value":5318},{"type":281,"tag":319,"props":7430,"children":7431},{"style":332},[7432],{"type":291,"value":5076},{"type":281,"tag":319,"props":7434,"children":7435},{"class":321,"line":2050},[7436,7440,7444,7448],{"type":281,"tag":319,"props":7437,"children":7438},{"style":5058},[7439],{"type":291,"value":5330},{"type":281,"tag":319,"props":7441,"children":7442},{"style":332},[7443],{"type":291,"value":362},{"type":281,"tag":319,"props":7445,"children":7446},{"style":5068},[7447],{"type":291,"value":5515},{"type":281,"tag":319,"props":7449,"children":7450},{"style":332},[7451],{"type":291,"value":5076},{"type":281,"tag":319,"props":7453,"children":7454},{"class":321,"line":2051},[7455,7459],{"type":281,"tag":319,"props":7456,"children":7457},{"style":5058},[7458],{"type":291,"value":5351},{"type":281,"tag":319,"props":7460,"children":7461},{"style":332},[7462],{"type":291,"value":5131},{"type":281,"tag":319,"props":7464,"children":7465},{"class":321,"line":2052},[7466,7470,7474],{"type":281,"tag":319,"props":7467,"children":7468},{"style":5058},[7469],{"type":291,"value":5363},{"type":281,"tag":319,"props":7471,"children":7472},{"style":332},[7473],{"type":291,"value":362},{"type":281,"tag":319,"props":7475,"children":7476},{"style":1622},[7477],{"type":291,"value":4800},{"type":281,"tag":319,"props":7479,"children":7480},{"class":321,"line":2053},[7481],{"type":281,"tag":319,"props":7482,"children":7483},{"style":332},[7484],{"type":291,"value":5379},{"type":281,"tag":319,"props":7486,"children":7487},{"class":321,"line":2054},[7488],{"type":281,"tag":319,"props":7489,"children":7490},{"style":332},[7491],{"type":291,"value":5387},{"type":281,"tag":319,"props":7493,"children":7495},{"class":7494,"line":2055},[321,385],[7496],{"type":281,"tag":319,"props":7497,"children":7498},{"style":332},[7499],{"type":291,"value":5301},{"type":281,"tag":319,"props":7501,"children":7503},{"class":7502,"line":2579},[321,385],[7504,7508,7512,7517],{"type":281,"tag":319,"props":7505,"children":7506},{"style":5058},[7507],{"type":291,"value":5309},{"type":281,"tag":319,"props":7509,"children":7510},{"style":332},[7511],{"type":291,"value":362},{"type":281,"tag":319,"props":7513,"children":7514},{"style":5068},[7515],{"type":291,"value":7516},"\"composer\"",{"type":281,"tag":319,"props":7518,"children":7519},{"style":332},[7520],{"type":291,"value":5076},{"type":281,"tag":319,"props":7522,"children":7524},{"class":7523,"line":2056},[321,385],[7525,7529,7533],{"type":281,"tag":319,"props":7526,"children":7527},{"style":5058},[7528],{"type":291,"value":5330},{"type":281,"tag":319,"props":7530,"children":7531},{"style":332},[7532],{"type":291,"value":362},{"type":281,"tag":319,"props":7534,"children":7535},{"style":5068},[7536],{"type":291,"value":7537},"\"https://\u003CDOMAIN-NAME>/api/v4/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\"\n",{"type":281,"tag":319,"props":7539,"children":7541},{"class":7540,"line":2605},[321,385],[7542],{"type":281,"tag":319,"props":7543,"children":7544},{"style":332},[7545],{"type":291,"value":5614},{"type":281,"tag":319,"props":7547,"children":7548},{"class":321,"line":2613},[7549],{"type":281,"tag":319,"props":7550,"children":7551},{"style":332},[7552],{"type":291,"value":5622},{"type":281,"tag":319,"props":7554,"children":7555},{"class":321,"line":2626},[7556,7560],{"type":281,"tag":319,"props":7557,"children":7558},{"style":5058},[7559],{"type":291,"value":5630},{"type":281,"tag":319,"props":7561,"children":7562},{"style":332},[7563],{"type":291,"value":5131},{"type":281,"tag":319,"props":7565,"children":7566},{"class":321,"line":2648},[7567,7571],{"type":281,"tag":319,"props":7568,"children":7569},{"style":5058},[7570],{"type":291,"value":5642},{"type":281,"tag":319,"props":7572,"children":7573},{"style":332},[7574],{"type":291,"value":5131},{"type":281,"tag":319,"props":7576,"children":7577},{"class":321,"line":2661},[7578,7582,7586,7590,7594],{"type":281,"tag":319,"props":7579,"children":7580},{"style":5058},[7581],{"type":291,"value":5654},{"type":281,"tag":319,"props":7583,"children":7584},{"style":5657},[7585],{"type":291,"value":5660},{"type":281,"tag":319,"props":7587,"children":7588},{"style":5058},[7589],{"type":291,"value":5665},{"type":281,"tag":319,"props":7591,"children":7592},{"style":332},[7593],{"type":291,"value":362},{"type":281,"tag":319,"props":7595,"children":7596},{"style":5068},[7597],{"type":291,"value":5674},{"type":281,"tag":319,"props":7599,"children":7600},{"class":321,"line":2675},[7601],{"type":281,"tag":319,"props":7602,"children":7603},{"style":332},[7604],{"type":291,"value":5614},{"type":281,"tag":319,"props":7606,"children":7607},{"class":321,"line":2693},[7608],{"type":281,"tag":319,"props":7609,"children":7610},{"style":332},[7611],{"type":291,"value":5280},{"type":281,"tag":319,"props":7613,"children":7614},{"class":321,"line":2706},[7615,7619,7623,7627],{"type":281,"tag":319,"props":7616,"children":7617},{"style":5058},[7618],{"type":291,"value":5696},{"type":281,"tag":319,"props":7620,"children":7621},{"style":332},[7622],{"type":291,"value":362},{"type":281,"tag":319,"props":7624,"children":7625},{"style":1622},[7626],{"type":291,"value":5705},{"type":281,"tag":319,"props":7628,"children":7629},{"style":332},[7630],{"type":291,"value":5076},{"type":281,"tag":319,"props":7632,"children":7633},{"class":321,"line":2719},[7634,7638],{"type":281,"tag":319,"props":7635,"children":7636},{"style":5058},[7637],{"type":291,"value":5717},{"type":281,"tag":319,"props":7639,"children":7640},{"style":332},[7641],{"type":291,"value":5131},{"type":281,"tag":319,"props":7643,"children":7644},{"class":321,"line":2732},[7645,7649],{"type":281,"tag":319,"props":7646,"children":7647},{"style":5058},[7648],{"type":291,"value":5729},{"type":281,"tag":319,"props":7650,"children":7651},{"style":332},[7652],{"type":291,"value":5131},{"type":281,"tag":319,"props":7654,"children":7655},{"class":321,"line":2750},[7656,7660,7664,7668],{"type":281,"tag":319,"props":7657,"children":7658},{"style":5058},[7659],{"type":291,"value":5741},{"type":281,"tag":319,"props":7661,"children":7662},{"style":332},[7663],{"type":291,"value":362},{"type":281,"tag":319,"props":7665,"children":7666},{"style":1622},[7667],{"type":291,"value":5705},{"type":281,"tag":319,"props":7669,"children":7670},{"style":332},[7671],{"type":291,"value":5076},{"type":281,"tag":319,"props":7673,"children":7674},{"class":321,"line":2768},[7675,7679,7683],{"type":281,"tag":319,"props":7676,"children":7677},{"style":5058},[7678],{"type":291,"value":5761},{"type":281,"tag":319,"props":7680,"children":7681},{"style":332},[7682],{"type":291,"value":362},{"type":281,"tag":319,"props":7684,"children":7685},{"style":1622},[7686],{"type":291,"value":4800},{"type":281,"tag":319,"props":7688,"children":7689},{"class":321,"line":2781},[7690],{"type":281,"tag":319,"props":7691,"children":7692},{"style":332},[7693],{"type":291,"value":5387},{"type":281,"tag":319,"props":7695,"children":7696},{"class":321,"line":2801},[7697,7701,7705,7709],{"type":281,"tag":319,"props":7698,"children":7699},{"style":5058},[7700],{"type":291,"value":5784},{"type":281,"tag":319,"props":7702,"children":7703},{"style":332},[7704],{"type":291,"value":362},{"type":281,"tag":319,"props":7706,"children":7707},{"style":1622},[7708],{"type":291,"value":5705},{"type":281,"tag":319,"props":7710,"children":7711},{"style":332},[7712],{"type":291,"value":5076},{"type":281,"tag":319,"props":7714,"children":7715},{"class":321,"line":2821},[7716,7720,7724],{"type":281,"tag":319,"props":7717,"children":7718},{"style":5058},[7719],{"type":291,"value":5804},{"type":281,"tag":319,"props":7721,"children":7722},{"style":332},[7723],{"type":291,"value":362},{"type":281,"tag":319,"props":7725,"children":7726},{"style":1622},[7727],{"type":291,"value":4800},{"type":281,"tag":319,"props":7729,"children":7730},{"class":321,"line":2838},[7731],{"type":281,"tag":319,"props":7732,"children":7733},{"style":332},[7734],{"type":291,"value":5280},{"type":281,"tag":319,"props":7736,"children":7737},{"class":321,"line":3607},[7738,7742],{"type":281,"tag":319,"props":7739,"children":7740},{"style":5058},[7741],{"type":291,"value":5827},{"type":281,"tag":319,"props":7743,"children":7744},{"style":332},[7745],{"type":291,"value":5131},{"type":281,"tag":319,"props":7747,"children":7748},{"class":321,"line":3615},[7749,7753],{"type":281,"tag":319,"props":7750,"children":7751},{"style":5058},[7752],{"type":291,"value":5839},{"type":281,"tag":319,"props":7754,"children":7755},{"style":332},[7756],{"type":291,"value":5131},{"type":281,"tag":319,"props":7758,"children":7759},{"class":321,"line":3627},[7760,7764,7768],{"type":281,"tag":319,"props":7761,"children":7762},{"style":5058},[7763],{"type":291,"value":5851},{"type":281,"tag":319,"props":7765,"children":7766},{"style":332},[7767],{"type":291,"value":362},{"type":281,"tag":319,"props":7769,"children":7770},{"style":5068},[7771],{"type":291,"value":5860},{"type":281,"tag":319,"props":7773,"children":7774},{"class":321,"line":3639},[7775],{"type":281,"tag":319,"props":7776,"children":7777},{"style":332},[7778],{"type":291,"value":5387},{"type":281,"tag":319,"props":7780,"children":7781},{"class":321,"line":3655},[7782,7786],{"type":281,"tag":319,"props":7783,"children":7784},{"style":5058},[7785],{"type":291,"value":5875},{"type":281,"tag":319,"props":7787,"children":7788},{"style":332},[7789],{"type":291,"value":5293},{"type":281,"tag":319,"props":7791,"children":7792},{"class":321,"line":3675},[7793],{"type":281,"tag":319,"props":7794,"children":7795},{"style":5068},[7796],{"type":291,"value":5887},{"type":281,"tag":319,"props":7798,"children":7799},{"class":321,"line":3691},[7800],{"type":281,"tag":319,"props":7801,"children":7802},{"style":332},[7803],{"type":291,"value":5895},{"type":281,"tag":319,"props":7805,"children":7806},{"class":321,"line":3703},[7807,7811],{"type":281,"tag":319,"props":7808,"children":7809},{"style":5058},[7810],{"type":291,"value":5903},{"type":281,"tag":319,"props":7812,"children":7813},{"style":332},[7814],{"type":291,"value":5293},{"type":281,"tag":319,"props":7816,"children":7817},{"class":321,"line":3715},[7818],{"type":281,"tag":319,"props":7819,"children":7820},{"style":5068},[7821],{"type":291,"value":5887},{"type":281,"tag":319,"props":7823,"children":7824},{"class":321,"line":3727},[7825],{"type":281,"tag":319,"props":7826,"children":7827},{"style":332},[7828],{"type":291,"value":5922},{"type":281,"tag":319,"props":7830,"children":7831},{"class":321,"line":3739},[7832],{"type":281,"tag":319,"props":7833,"children":7834},{"style":332},[7835],{"type":291,"value":5280},{"type":281,"tag":319,"props":7837,"children":7838},{"class":321,"line":3755},[7839,7843],{"type":281,"tag":319,"props":7840,"children":7841},{"style":5058},[7842],{"type":291,"value":5937},{"type":281,"tag":319,"props":7844,"children":7845},{"style":332},[7846],{"type":291,"value":5131},{"type":281,"tag":319,"props":7848,"children":7849},{"class":321,"line":3767},[7850,7854],{"type":281,"tag":319,"props":7851,"children":7852},{"style":5058},[7853],{"type":291,"value":5949},{"type":281,"tag":319,"props":7855,"children":7856},{"style":332},[7857],{"type":291,"value":5131},{"type":281,"tag":319,"props":7859,"children":7860},{"class":321,"line":3787},[7861,7865,7869,7873],{"type":281,"tag":319,"props":7862,"children":7863},{"style":5058},[7864],{"type":291,"value":5961},{"type":281,"tag":319,"props":7866,"children":7867},{"style":332},[7868],{"type":291,"value":362},{"type":281,"tag":319,"props":7870,"children":7871},{"style":1622},[7872],{"type":291,"value":5705},{"type":281,"tag":319,"props":7874,"children":7875},{"style":332},[7876],{"type":291,"value":5076},{"type":281,"tag":319,"props":7878,"children":7879},{"class":321,"line":3807},[7880,7884],{"type":281,"tag":319,"props":7881,"children":7882},{"style":5058},[7883],{"type":291,"value":5981},{"type":281,"tag":319,"props":7885,"children":7886},{"style":332},[7887],{"type":291,"value":5293},{"type":281,"tag":319,"props":7889,"children":7890},{"class":321,"line":3823},[7891,7895],{"type":281,"tag":319,"props":7892,"children":7893},{"style":5068},[7894],{"type":291,"value":5993},{"type":281,"tag":319,"props":7896,"children":7897},{"style":332},[7898],{"type":291,"value":5076},{"type":281,"tag":319,"props":7900,"children":7901},{"class":321,"line":6000},[7902],{"type":281,"tag":319,"props":7903,"children":7904},{"style":5068},[7905],{"type":291,"value":6006},{"type":281,"tag":319,"props":7907,"children":7908},{"class":321,"line":6009},[7909],{"type":281,"tag":319,"props":7910,"children":7911},{"style":332},[7912],{"type":291,"value":6015},{"type":281,"tag":319,"props":7914,"children":7915},{"class":321,"line":6018},[7916],{"type":281,"tag":319,"props":7917,"children":7918},{"style":332},[7919],{"type":291,"value":5614},{"type":281,"tag":319,"props":7921,"children":7922},{"class":321,"line":6026},[7923],{"type":281,"tag":319,"props":7924,"children":7925},{"style":332},[7926],{"type":291,"value":6032},{"type":281,"tag":319,"props":7928,"children":7929},{"class":321,"line":6035},[7930],{"type":281,"tag":319,"props":7931,"children":7932},{"style":332},[7933],{"type":291,"value":6041},{"type":281,"tag":282,"props":7935,"children":7936},{},[7937],{"type":291,"value":7938},"or by using the CLI:",{"type":281,"tag":301,"props":7940,"children":7942},{"className":1597,"code":7941,"language":1596,"meta":8,"style":8},"composer config repositories.\u003Cgroup_id> composer https://\u003CDOMAIN-NAME>/api/v4/group/\u003Cgroup_id>/-/packages/composer/packages.json\n",[7943],{"type":281,"tag":315,"props":7944,"children":7945},{"__ignoreMap":8},[7946],{"type":281,"tag":319,"props":7947,"children":7948},{"class":321,"line":322},[7949,7953,7958,7963,7969,7974,7979,7984,7989,7994,7998,8003,8008,8012,8017,8021,8025,8029,8033],{"type":281,"tag":319,"props":7950,"children":7951},{"style":1607},[7952],{"type":291,"value":4989},{"type":281,"tag":319,"props":7954,"children":7955},{"style":365},[7956],{"type":291,"value":7957}," config",{"type":281,"tag":319,"props":7959,"children":7960},{"style":365},[7961],{"type":291,"value":7962}," repositories.",{"type":281,"tag":319,"props":7964,"children":7966},{"style":7965},"--shiki-default:#F97583;--shiki-dark:#F97583;--shiki-sepia:#F92672",[7967],{"type":291,"value":7968},"\u003C",{"type":281,"tag":319,"props":7970,"children":7971},{"style":365},[7972],{"type":291,"value":7973},"group_i",{"type":281,"tag":319,"props":7975,"children":7976},{"style":332},[7977],{"type":291,"value":7978},"d",{"type":281,"tag":319,"props":7980,"children":7981},{"style":7965},[7982],{"type":291,"value":7983},">",{"type":281,"tag":319,"props":7985,"children":7986},{"style":365},[7987],{"type":291,"value":7988}," composer",{"type":281,"tag":319,"props":7990,"children":7991},{"style":365},[7992],{"type":291,"value":7993}," https://",{"type":281,"tag":319,"props":7995,"children":7996},{"style":7965},[7997],{"type":291,"value":7968},{"type":281,"tag":319,"props":7999,"children":8000},{"style":365},[8001],{"type":291,"value":8002},"DOMAIN-NAM",{"type":281,"tag":319,"props":8004,"children":8005},{"style":332},[8006],{"type":291,"value":8007},"E",{"type":281,"tag":319,"props":8009,"children":8010},{"style":7965},[8011],{"type":291,"value":7983},{"type":281,"tag":319,"props":8013,"children":8014},{"style":365},[8015],{"type":291,"value":8016},"/api/v4/group/",{"type":281,"tag":319,"props":8018,"children":8019},{"style":7965},[8020],{"type":291,"value":7968},{"type":281,"tag":319,"props":8022,"children":8023},{"style":365},[8024],{"type":291,"value":7973},{"type":281,"tag":319,"props":8026,"children":8027},{"style":332},[8028],{"type":291,"value":7978},{"type":281,"tag":319,"props":8030,"children":8031},{"style":7965},[8032],{"type":291,"value":7983},{"type":281,"tag":319,"props":8034,"children":8035},{"style":365},[8036],{"type":291,"value":8037},"/-/packages/composer/packages.json\n",{"type":281,"tag":282,"props":8039,"children":8040},{},[8041],{"type":291,"value":8042},"And setup GitLab credentials:",{"type":281,"tag":301,"props":8044,"children":8046},{"className":1597,"code":8045,"language":1596,"meta":8,"style":8},"composer config gitlab-token.\u003CDOMAIN-NAME> \u003Cpersonal_access_token>\n",[8047],{"type":281,"tag":315,"props":8048,"children":8049},{"__ignoreMap":8},[8050],{"type":281,"tag":319,"props":8051,"children":8052},{"class":321,"line":322},[8053,8057,8061,8066,8070,8074,8078,8082,8087,8092,8097],{"type":281,"tag":319,"props":8054,"children":8055},{"style":1607},[8056],{"type":291,"value":4989},{"type":281,"tag":319,"props":8058,"children":8059},{"style":365},[8060],{"type":291,"value":7957},{"type":281,"tag":319,"props":8062,"children":8063},{"style":365},[8064],{"type":291,"value":8065}," gitlab-token.",{"type":281,"tag":319,"props":8067,"children":8068},{"style":7965},[8069],{"type":291,"value":7968},{"type":281,"tag":319,"props":8071,"children":8072},{"style":365},[8073],{"type":291,"value":8002},{"type":281,"tag":319,"props":8075,"children":8076},{"style":332},[8077],{"type":291,"value":8007},{"type":281,"tag":319,"props":8079,"children":8080},{"style":7965},[8081],{"type":291,"value":7983},{"type":281,"tag":319,"props":8083,"children":8084},{"style":7965},[8085],{"type":291,"value":8086}," \u003C",{"type":281,"tag":319,"props":8088,"children":8089},{"style":365},[8090],{"type":291,"value":8091},"personal_access_toke",{"type":281,"tag":319,"props":8093,"children":8094},{"style":332},[8095],{"type":291,"value":8096},"n",{"type":281,"tag":319,"props":8098,"children":8099},{"style":7965},[8100],{"type":291,"value":8101},">\n",{"type":281,"tag":282,"props":8103,"children":8104},{},[8105,8107,8112],{"type":291,"value":8106},"You can read more about this process in the ",{"type":281,"tag":286,"props":8108,"children":8110},{"href":8109},"https://docs.gitlab.com/user/packages/composer_repository/#install-a-composer-package",[8111],{"type":291,"value":3963},{"type":291,"value":564},{"type":281,"tag":282,"props":8114,"children":8115},{},[8116],{"type":291,"value":8117},"Now we require our package us usual:",{"type":281,"tag":301,"props":8119,"children":8120},{"className":1597,"code":6049,"language":1596,"meta":8,"style":8},[8121],{"type":281,"tag":315,"props":8122,"children":8123},{"__ignoreMap":8},[8124],{"type":281,"tag":319,"props":8125,"children":8126},{"class":321,"line":322},[8127,8131,8135],{"type":281,"tag":319,"props":8128,"children":8129},{"style":1607},[8130],{"type":291,"value":4989},{"type":281,"tag":319,"props":8132,"children":8133},{"style":365},[8134],{"type":291,"value":6065},{"type":281,"tag":319,"props":8136,"children":8137},{"style":365},[8138],{"type":291,"value":6070},{"type":281,"tag":301,"props":8140,"children":8142},{"className":6781,"code":8141,"language":6783,"meta":8,"style":8},"./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",[8143],{"type":281,"tag":315,"props":8144,"children":8145},{"__ignoreMap":8},[8146,8153,8160,8167,8174,8181,8188,8195,8202,8209,8217,8225,8232,8239,8246,8253,8260,8267],{"type":281,"tag":319,"props":8147,"children":8148},{"class":321,"line":322},[8149],{"type":281,"tag":319,"props":8150,"children":8151},{},[8152],{"type":291,"value":6136},{"type":281,"tag":319,"props":8154,"children":8155},{"class":321,"line":338},[8156],{"type":281,"tag":319,"props":8157,"children":8158},{},[8159],{"type":291,"value":6144},{"type":281,"tag":319,"props":8161,"children":8162},{"class":321,"line":351},[8163],{"type":281,"tag":319,"props":8164,"children":8165},{},[8166],{"type":291,"value":6810},{"type":281,"tag":319,"props":8168,"children":8169},{"class":321,"line":371},[8170],{"type":281,"tag":319,"props":8171,"children":8172},{},[8173],{"type":291,"value":6818},{"type":281,"tag":319,"props":8175,"children":8176},{"class":321,"line":306},[8177],{"type":281,"tag":319,"props":8178,"children":8179},{},[8180],{"type":291,"value":6168},{"type":281,"tag":319,"props":8182,"children":8183},{"class":321,"line":307},[8184],{"type":281,"tag":319,"props":8185,"children":8186},{},[8187],{"type":291,"value":6833},{"type":281,"tag":319,"props":8189,"children":8190},{"class":321,"line":308},[8191],{"type":281,"tag":319,"props":8192,"children":8193},{},[8194],{"type":291,"value":6184},{"type":281,"tag":319,"props":8196,"children":8197},{"class":321,"line":309},[8198],{"type":281,"tag":319,"props":8199,"children":8200},{},[8201],{"type":291,"value":6192},{"type":281,"tag":319,"props":8203,"children":8204},{"class":321,"line":310},[8205],{"type":281,"tag":319,"props":8206,"children":8207},{},[8208],{"type":291,"value":6200},{"type":281,"tag":319,"props":8210,"children":8211},{"class":321,"line":973},[8212],{"type":281,"tag":319,"props":8213,"children":8214},{},[8215],{"type":291,"value":8216},"  - Downloading acme/sample-plugin (1.0.0)\n",{"type":281,"tag":319,"props":8218,"children":8219},{"class":321,"line":986},[8220],{"type":281,"tag":319,"props":8221,"children":8222},{},[8223],{"type":291,"value":8224},"  - Installing acme/sample-plugin (1.0.0): Extracting archive\n",{"type":281,"tag":319,"props":8226,"children":8227},{"class":321,"line":999},[8228],{"type":281,"tag":319,"props":8229,"children":8230},{},[8231],{"type":291,"value":6224},{"type":281,"tag":319,"props":8233,"children":8234},{"class":321,"line":1012},[8235],{"type":281,"tag":319,"props":8236,"children":8237},{"emptyLinePlaceholder":1042},[8238],{"type":291,"value":1045},{"type":281,"tag":319,"props":8240,"children":8241},{"class":321,"line":1025},[8242],{"type":281,"tag":319,"props":8243,"children":8244},{},[8245],{"type":291,"value":6239},{"type":281,"tag":319,"props":8247,"children":8248},{"class":321,"line":1038},[8249],{"type":281,"tag":319,"props":8250,"children":8251},{"emptyLinePlaceholder":1042},[8252],{"type":291,"value":1045},{"type":281,"tag":319,"props":8254,"children":8255},{"class":321,"line":1048},[8256],{"type":281,"tag":319,"props":8257,"children":8258},{},[8259],{"type":291,"value":6254},{"type":281,"tag":319,"props":8261,"children":8262},{"class":321,"line":1061},[8263],{"type":281,"tag":319,"props":8264,"children":8265},{"emptyLinePlaceholder":1042},[8266],{"type":291,"value":1045},{"type":281,"tag":319,"props":8268,"children":8269},{"class":321,"line":1074},[8270],{"type":281,"tag":319,"props":8271,"children":8272},{},[8273],{"type":291,"value":6920},{"type":281,"tag":282,"props":8275,"children":8276},{},[8277],{"type":281,"tag":319,"props":8278,"children":8280},{"className":8279},[4894],[8281],{"type":291,"value":8282},"Awesome. Direct package download!",{"type":281,"tag":1248,"props":8284,"children":8286},{"id":8285},"why-bother",[8287],{"type":291,"value":8288},"Why bother?",{"type":281,"tag":282,"props":8290,"children":8291},{},[8292,8294,8299,8301,8307],{"type":291,"value":8293},"This is an excellent question. The main reason is package caching. When running in a ",{"type":281,"tag":315,"props":8295,"children":8297},{"className":8296},[],[8298],{"type":291,"value":1578},{"type":291,"value":8300}," environment or ",{"type":281,"tag":315,"props":8302,"children":8304},{"className":8303},[],[8305],{"type":291,"value":8306},"docker build",{"type":291,"value":8308},",\ncaching packages can give you a massive performance boost.",{"type":281,"tag":1314,"props":8310,"children":8311},{},[],{"type":281,"tag":832,"props":8313,"children":8314},{},[],{"type":281,"tag":530,"props":8316,"children":8318},{"id":8317},"release-pipeline",[8319],{"type":291,"value":8320},"Release pipeline",{"type":281,"tag":1248,"props":8322,"children":8324},{"id":8323},"with-manual-tagging",[8325],{"type":291,"value":8326},"With manual tagging",{"type":281,"tag":282,"props":8328,"children":8329},{},[8330],{"type":291,"value":8331},"This is a simple pipeline when you need to manually create and push a git tag.",{"type":281,"tag":282,"props":8333,"children":8334},{},[8335,8337,8342,8343],{"type":291,"value":8336},"Make sure to always update the ",{"type":281,"tag":315,"props":8338,"children":8340},{"className":8339},[],[8341],{"type":291,"value":6300},{"type":291,"value":6302},{"type":281,"tag":315,"props":8344,"children":8346},{"className":8345},[],[8347],{"type":291,"value":6308},{"type":281,"tag":301,"props":8349,"children":8351},{"className":1597,"code":8350,"language":1596,"meta":8,"style":8},"git tag \u003Cversion>\ngit push --tags\n",[8352],{"type":281,"tag":315,"props":8353,"children":8354},{"__ignoreMap":8},[8355,8383],{"type":281,"tag":319,"props":8356,"children":8357},{"class":321,"line":322},[8358,8362,8366,8370,8375,8379],{"type":281,"tag":319,"props":8359,"children":8360},{"style":1607},[8361],{"type":291,"value":554},{"type":281,"tag":319,"props":8363,"children":8364},{"style":365},[8365],{"type":291,"value":6730},{"type":281,"tag":319,"props":8367,"children":8368},{"style":7965},[8369],{"type":291,"value":8086},{"type":281,"tag":319,"props":8371,"children":8372},{"style":365},[8373],{"type":291,"value":8374},"versio",{"type":281,"tag":319,"props":8376,"children":8377},{"style":332},[8378],{"type":291,"value":8096},{"type":281,"tag":319,"props":8380,"children":8381},{"style":7965},[8382],{"type":291,"value":8101},{"type":281,"tag":319,"props":8384,"children":8385},{"class":321,"line":338},[8386,8390,8394],{"type":281,"tag":319,"props":8387,"children":8388},{"style":1607},[8389],{"type":291,"value":554},{"type":281,"tag":319,"props":8391,"children":8392},{"style":365},[8393],{"type":291,"value":6747},{"type":281,"tag":319,"props":8395,"children":8396},{"style":1622},[8397],{"type":291,"value":6752},{"type":281,"tag":301,"props":8399,"children":8402},{"className":312,"code":8400,"filename":8401,"language":311,"meta":8,"style":8},"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",[8403],{"type":281,"tag":315,"props":8404,"children":8405},{"__ignoreMap":8},[8406,8417,8428,8435,8447,8463,8478,8489,8501,8518,8529],{"type":281,"tag":319,"props":8407,"children":8408},{"class":321,"line":322},[8409,8413],{"type":281,"tag":319,"props":8410,"children":8411},{"style":326},[8412],{"type":291,"value":1700},{"type":281,"tag":319,"props":8414,"children":8415},{"style":332},[8416],{"type":291,"value":335},{"type":281,"tag":319,"props":8418,"children":8419},{"class":321,"line":338},[8420,8424],{"type":281,"tag":319,"props":8421,"children":8422},{"style":332},[8423],{"type":291,"value":1712},{"type":281,"tag":319,"props":8425,"children":8426},{"style":365},[8427],{"type":291,"value":4373},{"type":281,"tag":319,"props":8429,"children":8430},{"class":321,"line":351},[8431],{"type":281,"tag":319,"props":8432,"children":8433},{"emptyLinePlaceholder":1042},[8434],{"type":291,"value":1045},{"type":281,"tag":319,"props":8436,"children":8437},{"class":321,"line":371},[8438,8443],{"type":281,"tag":319,"props":8439,"children":8440},{"style":326},[8441],{"type":291,"value":8442},"deploy",{"type":281,"tag":319,"props":8444,"children":8445},{"style":332},[8446],{"type":291,"value":335},{"type":281,"tag":319,"props":8448,"children":8449},{"class":321,"line":306},[8450,8454,8458],{"type":281,"tag":319,"props":8451,"children":8452},{"style":326},[8453],{"type":291,"value":2126},{"type":281,"tag":319,"props":8455,"children":8456},{"style":332},[8457],{"type":291,"value":362},{"type":281,"tag":319,"props":8459,"children":8460},{"style":365},[8461],{"type":291,"value":8462},"alpine/curl\n",{"type":281,"tag":319,"props":8464,"children":8465},{"class":321,"line":307},[8466,8470,8474],{"type":281,"tag":319,"props":8467,"children":8468},{"style":326},[8469],{"type":291,"value":2110},{"type":281,"tag":319,"props":8471,"children":8472},{"style":332},[8473],{"type":291,"value":362},{"type":281,"tag":319,"props":8475,"children":8476},{"style":365},[8477],{"type":291,"value":4373},{"type":281,"tag":319,"props":8479,"children":8480},{"class":321,"line":308},[8481,8485],{"type":281,"tag":319,"props":8482,"children":8483},{"style":326},[8484],{"type":291,"value":2585},{"type":281,"tag":319,"props":8486,"children":8487},{"style":332},[8488],{"type":291,"value":335},{"type":281,"tag":319,"props":8490,"children":8491},{"class":321,"line":309},[8492,8496],{"type":281,"tag":319,"props":8493,"children":8494},{"style":332},[8495],{"type":291,"value":2188},{"type":281,"tag":319,"props":8497,"children":8498},{"style":365},[8499],{"type":291,"value":8500},"'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":281,"tag":319,"props":8502,"children":8503},{"class":321,"line":310},[8504,8509,8513],{"type":281,"tag":319,"props":8505,"children":8506},{"style":326},[8507],{"type":291,"value":8508},"  environment",{"type":281,"tag":319,"props":8510,"children":8511},{"style":332},[8512],{"type":291,"value":362},{"type":281,"tag":319,"props":8514,"children":8515},{"style":365},[8516],{"type":291,"value":8517},"production\n",{"type":281,"tag":319,"props":8519,"children":8520},{"class":321,"line":973},[8521,8525],{"type":281,"tag":319,"props":8522,"children":8523},{"style":326},[8524],{"type":291,"value":2774},{"type":281,"tag":319,"props":8526,"children":8527},{"style":332},[8528],{"type":291,"value":335},{"type":281,"tag":319,"props":8530,"children":8531},{"class":321,"line":986},[8532,8537,8541],{"type":281,"tag":319,"props":8533,"children":8534},{"style":326},[8535],{"type":291,"value":8536},"    if",{"type":281,"tag":319,"props":8538,"children":8539},{"style":332},[8540],{"type":291,"value":362},{"type":281,"tag":319,"props":8542,"children":8543},{"style":365},[8544],{"type":291,"value":8545},"$CI_COMMIT_TAG\n",{"type":281,"tag":1248,"props":8547,"children":8549},{"id":8548},"with-semantic-release",[8550],{"type":291,"value":8551},"With semantic-release",{"type":281,"tag":282,"props":8553,"children":8554},{},[8555],{"type":291,"value":8556},"It would be a lot easier if we could just push our changes and don't care about versioning and tagging.",{"type":281,"tag":282,"props":8558,"children":8559},{},[8560,8566],{"type":281,"tag":286,"props":8561,"children":8563},{"href":8562},"https://github.com/semantic-release/semantic-release",[8564],{"type":291,"value":8565},"semantic-release",{"type":291,"value":8567}," automates the whole package release workflow.",{"type":281,"tag":282,"props":8569,"children":8570},{},[8571,8573,8579],{"type":291,"value":8572},"Please follow the ",{"type":281,"tag":286,"props":8574,"children":8576},{"href":8575},"https://github.com/semantic-release/gitlab?tab=readme-ov-file#gitlab-authentication",[8577],{"type":291,"value":8578},"GitLab authentication instruction",{"type":291,"value":8580}," before you continue to read.",{"type":281,"tag":301,"props":8582,"children":8584},{"className":312,"code":8583,"filename":1687,"language":311,"meta":8,"style":8},"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",[8585],{"type":281,"tag":315,"props":8586,"children":8587},{"__ignoreMap":8},[8588,8599,8610,8617,8628,8643,8654,8670,8689,8704,8715,8727,8738,8757,8772],{"type":281,"tag":319,"props":8589,"children":8590},{"class":321,"line":322},[8591,8595],{"type":281,"tag":319,"props":8592,"children":8593},{"style":326},[8594],{"type":291,"value":1700},{"type":281,"tag":319,"props":8596,"children":8597},{"style":332},[8598],{"type":291,"value":335},{"type":281,"tag":319,"props":8600,"children":8601},{"class":321,"line":338},[8602,8606],{"type":281,"tag":319,"props":8603,"children":8604},{"style":332},[8605],{"type":291,"value":1712},{"type":281,"tag":319,"props":8607,"children":8608},{"style":365},[8609],{"type":291,"value":4373},{"type":281,"tag":319,"props":8611,"children":8612},{"class":321,"line":351},[8613],{"type":281,"tag":319,"props":8614,"children":8615},{"emptyLinePlaceholder":1042},[8616],{"type":291,"value":1045},{"type":281,"tag":319,"props":8618,"children":8619},{"class":321,"line":371},[8620,8624],{"type":281,"tag":319,"props":8621,"children":8622},{"style":326},[8623],{"type":291,"value":4718},{"type":281,"tag":319,"props":8625,"children":8626},{"style":332},[8627],{"type":291,"value":335},{"type":281,"tag":319,"props":8629,"children":8630},{"class":321,"line":306},[8631,8635,8639],{"type":281,"tag":319,"props":8632,"children":8633},{"style":326},[8634],{"type":291,"value":2110},{"type":281,"tag":319,"props":8636,"children":8637},{"style":332},[8638],{"type":291,"value":362},{"type":281,"tag":319,"props":8640,"children":8641},{"style":365},[8642],{"type":291,"value":4373},{"type":281,"tag":319,"props":8644,"children":8645},{"class":321,"line":307},[8646,8650],{"type":281,"tag":319,"props":8647,"children":8648},{"style":326},[8649],{"type":291,"value":2126},{"type":281,"tag":319,"props":8651,"children":8652},{"style":332},[8653],{"type":291,"value":335},{"type":281,"tag":319,"props":8655,"children":8656},{"class":321,"line":308},[8657,8661,8665],{"type":281,"tag":319,"props":8658,"children":8659},{"style":326},[8660],{"type":291,"value":2138},{"type":281,"tag":319,"props":8662,"children":8663},{"style":332},[8664],{"type":291,"value":362},{"type":281,"tag":319,"props":8666,"children":8667},{"style":365},[8668],{"type":291,"value":8669},"ghcr.io/voxpupuli/semantic-release:25.0.0-latest\n",{"type":281,"tag":319,"props":8671,"children":8672},{"class":321,"line":309},[8673,8677,8681,8685],{"type":281,"tag":319,"props":8674,"children":8675},{"style":326},[8676],{"type":291,"value":2154},{"type":281,"tag":319,"props":8678,"children":8679},{"style":332},[8680],{"type":291,"value":1778},{"type":281,"tag":319,"props":8682,"children":8683},{"style":365},[8684],{"type":291,"value":1783},{"type":281,"tag":319,"props":8686,"children":8687},{"style":332},[8688],{"type":291,"value":1788},{"type":281,"tag":319,"props":8690,"children":8691},{"class":321,"line":310},[8692,8696,8700],{"type":281,"tag":319,"props":8693,"children":8694},{"style":326},[8695],{"type":291,"value":4791},{"type":281,"tag":319,"props":8697,"children":8698},{"style":332},[8699],{"type":291,"value":362},{"type":281,"tag":319,"props":8701,"children":8702},{"style":1622},[8703],{"type":291,"value":4800},{"type":281,"tag":319,"props":8705,"children":8706},{"class":321,"line":973},[8707,8711],{"type":281,"tag":319,"props":8708,"children":8709},{"style":326},[8710],{"type":291,"value":2585},{"type":281,"tag":319,"props":8712,"children":8713},{"style":332},[8714],{"type":291,"value":335},{"type":281,"tag":319,"props":8716,"children":8717},{"class":321,"line":986},[8718,8722],{"type":281,"tag":319,"props":8719,"children":8720},{"style":332},[8721],{"type":291,"value":2188},{"type":281,"tag":319,"props":8723,"children":8724},{"style":365},[8725],{"type":291,"value":8726},"/container-entrypoint.sh\n",{"type":281,"tag":319,"props":8728,"children":8729},{"class":321,"line":999},[8730,8734],{"type":281,"tag":319,"props":8731,"children":8732},{"style":326},[8733],{"type":291,"value":2774},{"type":281,"tag":319,"props":8735,"children":8736},{"style":332},[8737],{"type":291,"value":335},{"type":281,"tag":319,"props":8739,"children":8740},{"class":321,"line":1012},[8741,8745,8749,8753],{"type":281,"tag":319,"props":8742,"children":8743},{"style":332},[8744],{"type":291,"value":2188},{"type":281,"tag":319,"props":8746,"children":8747},{"style":326},[8748],{"type":291,"value":1895},{"type":281,"tag":319,"props":8750,"children":8751},{"style":332},[8752],{"type":291,"value":362},{"type":281,"tag":319,"props":8754,"children":8755},{"style":365},[8756],{"type":291,"value":1925},{"type":281,"tag":319,"props":8758,"children":8759},{"class":321,"line":1025},[8760,8764,8768],{"type":281,"tag":319,"props":8761,"children":8762},{"style":326},[8763],{"type":291,"value":2827},{"type":281,"tag":319,"props":8765,"children":8766},{"style":332},[8767],{"type":291,"value":362},{"type":281,"tag":319,"props":8769,"children":8770},{"style":365},[8771],{"type":291,"value":1943},{"type":281,"tag":319,"props":8773,"children":8774},{"class":321,"line":1038},[8775,8779,8783,8787],{"type":281,"tag":319,"props":8776,"children":8777},{"style":332},[8778],{"type":291,"value":2188},{"type":281,"tag":319,"props":8780,"children":8781},{"style":326},[8782],{"type":291,"value":1895},{"type":281,"tag":319,"props":8784,"children":8785},{"style":332},[8786],{"type":291,"value":362},{"type":281,"tag":319,"props":8788,"children":8789},{"style":365},[8790],{"type":291,"value":1964},{"type":281,"tag":301,"props":8792,"children":8795},{"className":5036,"code":8793,"filename":8794,"language":5040,"meta":8,"style":8},"{\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",[8796],{"type":281,"tag":315,"props":8797,"children":8798},{"__ignoreMap":8},[8799,8806,8818,8830,8838,8850,8858,8870,8878,8900,8947,8989,8997,9005,9012,9019,9026,9038,9045,9065,9092,9099,9106,9113,9125,9132,9167,9174,9181,9189],{"type":281,"tag":319,"props":8800,"children":8801},{"class":321,"line":322},[8802],{"type":281,"tag":319,"props":8803,"children":8804},{"style":332},[8805],{"type":291,"value":5052},{"type":281,"tag":319,"props":8807,"children":8808},{"class":321,"line":338},[8809,8814],{"type":281,"tag":319,"props":8810,"children":8811},{"style":5058},[8812],{"type":291,"value":8813},"  \"plugins\"",{"type":281,"tag":319,"props":8815,"children":8816},{"style":332},[8817],{"type":291,"value":5293},{"type":281,"tag":319,"props":8819,"children":8820},{"class":321,"line":351},[8821,8826],{"type":281,"tag":319,"props":8822,"children":8823},{"style":5068},[8824],{"type":291,"value":8825},"    \"@semantic-release/commit-analyzer\"",{"type":281,"tag":319,"props":8827,"children":8828},{"style":332},[8829],{"type":291,"value":5076},{"type":281,"tag":319,"props":8831,"children":8832},{"class":321,"line":371},[8833],{"type":281,"tag":319,"props":8834,"children":8835},{"style":332},[8836],{"type":291,"value":8837},"    [\n",{"type":281,"tag":319,"props":8839,"children":8840},{"class":321,"line":306},[8841,8846],{"type":281,"tag":319,"props":8842,"children":8843},{"style":5068},[8844],{"type":291,"value":8845},"      \"semantic-release-replace-plugin\"",{"type":281,"tag":319,"props":8847,"children":8848},{"style":332},[8849],{"type":291,"value":5076},{"type":281,"tag":319,"props":8851,"children":8852},{"class":321,"line":307},[8853],{"type":281,"tag":319,"props":8854,"children":8855},{"style":332},[8856],{"type":291,"value":8857},"      {\n",{"type":281,"tag":319,"props":8859,"children":8860},{"class":321,"line":308},[8861,8866],{"type":281,"tag":319,"props":8862,"children":8863},{"style":5058},[8864],{"type":291,"value":8865},"        \"replacements\"",{"type":281,"tag":319,"props":8867,"children":8868},{"style":332},[8869],{"type":291,"value":5293},{"type":281,"tag":319,"props":8871,"children":8872},{"class":321,"line":309},[8873],{"type":281,"tag":319,"props":8874,"children":8875},{"style":332},[8876],{"type":291,"value":8877},"          {\n",{"type":281,"tag":319,"props":8879,"children":8880},{"class":321,"line":310},[8881,8886,8890,8895],{"type":281,"tag":319,"props":8882,"children":8883},{"style":5058},[8884],{"type":291,"value":8885},"            \"files\"",{"type":281,"tag":319,"props":8887,"children":8888},{"style":332},[8889],{"type":291,"value":1778},{"type":281,"tag":319,"props":8891,"children":8892},{"style":5068},[8893],{"type":291,"value":8894},"\"composer.json\"",{"type":281,"tag":319,"props":8896,"children":8897},{"style":332},[8898],{"type":291,"value":8899},"],\n",{"type":281,"tag":319,"props":8901,"children":8902},{"class":321,"line":973},[8903,8908,8912,8917,8922,8926,8930,8935,8939,8943],{"type":281,"tag":319,"props":8904,"children":8905},{"style":5058},[8906],{"type":291,"value":8907},"            \"from\"",{"type":281,"tag":319,"props":8909,"children":8910},{"style":332},[8911],{"type":291,"value":362},{"type":281,"tag":319,"props":8913,"children":8914},{"style":5068},[8915],{"type":291,"value":8916},"\"version",{"type":281,"tag":319,"props":8918,"children":8919},{"style":1622},[8920],{"type":291,"value":8921},"\\\"",{"type":281,"tag":319,"props":8923,"children":8924},{"style":5068},[8925],{"type":291,"value":362},{"type":281,"tag":319,"props":8927,"children":8928},{"style":1622},[8929],{"type":291,"value":8921},{"type":281,"tag":319,"props":8931,"children":8932},{"style":5068},[8933],{"type":291,"value":8934},".*",{"type":281,"tag":319,"props":8936,"children":8937},{"style":1622},[8938],{"type":291,"value":8921},{"type":281,"tag":319,"props":8940,"children":8941},{"style":5068},[8942],{"type":291,"value":5665},{"type":281,"tag":319,"props":8944,"children":8945},{"style":332},[8946],{"type":291,"value":5076},{"type":281,"tag":319,"props":8948,"children":8949},{"class":321,"line":986},[8950,8955,8959,8963,8967,8971,8975,8980,8984],{"type":281,"tag":319,"props":8951,"children":8952},{"style":5058},[8953],{"type":291,"value":8954},"            \"to\"",{"type":281,"tag":319,"props":8956,"children":8957},{"style":332},[8958],{"type":291,"value":362},{"type":281,"tag":319,"props":8960,"children":8961},{"style":5068},[8962],{"type":291,"value":8916},{"type":281,"tag":319,"props":8964,"children":8965},{"style":1622},[8966],{"type":291,"value":8921},{"type":281,"tag":319,"props":8968,"children":8969},{"style":5068},[8970],{"type":291,"value":362},{"type":281,"tag":319,"props":8972,"children":8973},{"style":1622},[8974],{"type":291,"value":8921},{"type":281,"tag":319,"props":8976,"children":8977},{"style":5068},[8978],{"type":291,"value":8979},"${nextRelease.version}",{"type":281,"tag":319,"props":8981,"children":8982},{"style":1622},[8983],{"type":291,"value":8921},{"type":281,"tag":319,"props":8985,"children":8986},{"style":5068},[8987],{"type":291,"value":8988},"\"\n",{"type":281,"tag":319,"props":8990,"children":8991},{"class":321,"line":999},[8992],{"type":281,"tag":319,"props":8993,"children":8994},{"style":332},[8995],{"type":291,"value":8996},"          }\n",{"type":281,"tag":319,"props":8998,"children":8999},{"class":321,"line":1012},[9000],{"type":281,"tag":319,"props":9001,"children":9002},{"style":332},[9003],{"type":291,"value":9004},"        ]\n",{"type":281,"tag":319,"props":9006,"children":9007},{"class":321,"line":1025},[9008],{"type":281,"tag":319,"props":9009,"children":9010},{"style":332},[9011],{"type":291,"value":5379},{"type":281,"tag":319,"props":9013,"children":9014},{"class":321,"line":1038},[9015],{"type":281,"tag":319,"props":9016,"children":9017},{"style":332},[9018],{"type":291,"value":5895},{"type":281,"tag":319,"props":9020,"children":9021},{"class":321,"line":1048},[9022],{"type":281,"tag":319,"props":9023,"children":9024},{"style":332},[9025],{"type":291,"value":8837},{"type":281,"tag":319,"props":9027,"children":9028},{"class":321,"line":1061},[9029,9034],{"type":281,"tag":319,"props":9030,"children":9031},{"style":5068},[9032],{"type":291,"value":9033},"      \"@semantic-release/git\"",{"type":281,"tag":319,"props":9035,"children":9036},{"style":332},[9037],{"type":291,"value":5076},{"type":281,"tag":319,"props":9039,"children":9040},{"class":321,"line":1074},[9041],{"type":281,"tag":319,"props":9042,"children":9043},{"style":332},[9044],{"type":291,"value":8857},{"type":281,"tag":319,"props":9046,"children":9047},{"class":321,"line":1083},[9048,9053,9057,9061],{"type":281,"tag":319,"props":9049,"children":9050},{"style":5058},[9051],{"type":291,"value":9052},"        \"assets\"",{"type":281,"tag":319,"props":9054,"children":9055},{"style":332},[9056],{"type":291,"value":1778},{"type":281,"tag":319,"props":9058,"children":9059},{"style":5068},[9060],{"type":291,"value":8894},{"type":281,"tag":319,"props":9062,"children":9063},{"style":332},[9064],{"type":291,"value":8899},{"type":281,"tag":319,"props":9066,"children":9067},{"class":321,"line":1096},[9068,9073,9077,9082,9087],{"type":281,"tag":319,"props":9069,"children":9070},{"style":5058},[9071],{"type":291,"value":9072},"        \"message\"",{"type":281,"tag":319,"props":9074,"children":9075},{"style":332},[9076],{"type":291,"value":362},{"type":281,"tag":319,"props":9078,"children":9079},{"style":5068},[9080],{"type":291,"value":9081},"\"chore(release): ${nextRelease.version} [skip ci]",{"type":281,"tag":319,"props":9083,"children":9084},{"style":1622},[9085],{"type":291,"value":9086},"\\n\\n",{"type":281,"tag":319,"props":9088,"children":9089},{"style":5068},[9090],{"type":291,"value":9091},"${nextRelease.notes}\"\n",{"type":281,"tag":319,"props":9093,"children":9094},{"class":321,"line":1109},[9095],{"type":281,"tag":319,"props":9096,"children":9097},{"style":332},[9098],{"type":291,"value":5379},{"type":281,"tag":319,"props":9100,"children":9101},{"class":321,"line":1122},[9102],{"type":281,"tag":319,"props":9103,"children":9104},{"style":332},[9105],{"type":291,"value":5895},{"type":281,"tag":319,"props":9107,"children":9108},{"class":321,"line":1130},[9109],{"type":281,"tag":319,"props":9110,"children":9111},{"style":332},[9112],{"type":291,"value":8837},{"type":281,"tag":319,"props":9114,"children":9115},{"class":321,"line":1143},[9116,9121],{"type":281,"tag":319,"props":9117,"children":9118},{"style":5068},[9119],{"type":291,"value":9120},"      \"@semantic-release/exec\"",{"type":281,"tag":319,"props":9122,"children":9123},{"style":332},[9124],{"type":291,"value":5076},{"type":281,"tag":319,"props":9126,"children":9127},{"class":321,"line":1156},[9128],{"type":281,"tag":319,"props":9129,"children":9130},{"style":332},[9131],{"type":291,"value":8857},{"type":281,"tag":319,"props":9133,"children":9134},{"class":321,"line":1169},[9135,9140,9144,9149,9153,9158,9162],{"type":281,"tag":319,"props":9136,"children":9137},{"style":5058},[9138],{"type":291,"value":9139},"        \"publishCmd\"",{"type":281,"tag":319,"props":9141,"children":9142},{"style":332},[9143],{"type":291,"value":362},{"type":281,"tag":319,"props":9145,"children":9146},{"style":5068},[9147],{"type":291,"value":9148},"\"curl --fail-with-body --header ",{"type":281,"tag":319,"props":9150,"children":9151},{"style":1622},[9152],{"type":291,"value":8921},{"type":281,"tag":319,"props":9154,"children":9155},{"style":5068},[9156],{"type":291,"value":9157},"Job-Token: ${process.env.CI_JOB_TOKEN}",{"type":281,"tag":319,"props":9159,"children":9160},{"style":1622},[9161],{"type":291,"value":8921},{"type":281,"tag":319,"props":9163,"children":9164},{"style":5068},[9165],{"type":291,"value":9166}," --data tag=${nextRelease.gitTag} ${process.env.CI_API_V4_URL}/projects/${process.env.CI_PROJECT_ID}/packages/composer\"\n",{"type":281,"tag":319,"props":9168,"children":9169},{"class":321,"line":1182},[9170],{"type":281,"tag":319,"props":9171,"children":9172},{"style":332},[9173],{"type":291,"value":5379},{"type":281,"tag":319,"props":9175,"children":9176},{"class":321,"line":1195},[9177],{"type":281,"tag":319,"props":9178,"children":9179},{"style":332},[9180],{"type":291,"value":5922},{"type":281,"tag":319,"props":9182,"children":9183},{"class":321,"line":2048},[9184],{"type":281,"tag":319,"props":9185,"children":9186},{"style":332},[9187],{"type":291,"value":9188},"  ]\n",{"type":281,"tag":319,"props":9190,"children":9191},{"class":321,"line":2049},[9192],{"type":281,"tag":319,"props":9193,"children":9194},{"style":332},[9195],{"type":291,"value":6041},{"type":281,"tag":282,"props":9197,"children":9198},{},[9199],{"type":291,"value":4902},{"type":281,"tag":608,"props":9201,"children":9202},{},[9203,9208,9218,9230,9235],{"type":281,"tag":459,"props":9204,"children":9205},{},[9206],{"type":291,"value":9207},"Analise the commits from the last release to decide if a new version should be released",{"type":281,"tag":459,"props":9209,"children":9210},{},[9211,9213],{"type":291,"value":9212},"Update the version in ",{"type":281,"tag":315,"props":9214,"children":9216},{"className":9215},[],[9217],{"type":291,"value":6308},{"type":281,"tag":459,"props":9219,"children":9220},{},[9221,9223,9228],{"type":291,"value":9222},"Commit the ",{"type":281,"tag":315,"props":9224,"children":9226},{"className":9225},[],[9227],{"type":291,"value":6308},{"type":291,"value":9229}," back into the repo",{"type":281,"tag":459,"props":9231,"children":9232},{},[9233],{"type":291,"value":9234},"Create a tag",{"type":281,"tag":459,"props":9236,"children":9237},{},[9238],{"type":291,"value":9239},"Release a composer package from this tag",{"type":281,"tag":1477,"props":9241,"children":9242},{},[9243],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":9245},[9246,9252],{"id":5007,"depth":338,"text":5010,"children":9247},[9248,9249,9250,9251],{"id":5018,"depth":351,"text":5021},{"id":6274,"depth":351,"text":6277},{"id":6935,"depth":351,"text":6938},{"id":8285,"depth":351,"text":8288},{"id":8317,"depth":338,"text":8320,"children":9253},[9254,9255],{"id":8323,"depth":351,"text":8326},{"id":8548,"depth":351,"text":8551},{"_path":61,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":62,"description":63,"author":11,"image":12,"releaseDate":64,"blogCategories":9257,"articleTags":9258,"tags":9259,"body":9260,"_type":20,"_id":68,"_source":22,"_file":69,"_stem":70,"_extension":25},[15,16],[16,33],[19],{"type":278,"children":9261,"toc":10720},[9262,9267,9272,9277,9282,9287,9305,9310,9353,9359,9372,9385,9390,9396,9409,9422,9431,9437,9442,9555,10073,10108,10119,10122,10127,10288,10301,10307,10312,10382,10387,10393,10398,10409,10422,10456,10483,10495,10516,10529,10532,10537,10550,10568,10573,10578,10698,10716],{"type":281,"tag":282,"props":9263,"children":9264},{},[9265],{"type":291,"value":9266},"Managing a multiservice server can be tricky. Not every software is compatible with another, for example different requirements for database or PHP-versions.",{"type":281,"tag":282,"props":9268,"children":9269},{},[9270],{"type":291,"value":9271},"Additionally, all the software should be in the latest version, to mitigate possible security risks.",{"type":281,"tag":282,"props":9273,"children":9274},{},[9275],{"type":291,"value":9276},"There are many ways to handle this: Ansible, Chef etc.",{"type":281,"tag":282,"props":9278,"children":9279},{},[9280],{"type":291,"value":9281},"Out goal was to have an easy to use, automated and free solution.",{"type":281,"tag":282,"props":9283,"children":9284},{},[9285],{"type":291,"value":9286},"Here are the goals:",{"type":281,"tag":455,"props":9288,"children":9289},{},[9290,9295,9300],{"type":281,"tag":459,"props":9291,"children":9292},{},[9293],{"type":291,"value":9294},"use the GitOps approach to store and version control the deployment",{"type":281,"tag":459,"props":9296,"children":9297},{},[9298],{"type":291,"value":9299},"use containers to run the software",{"type":281,"tag":459,"props":9301,"children":9302},{},[9303],{"type":291,"value":9304},"get automated security updates and opt in for minor/major version updates",{"type":281,"tag":282,"props":9306,"children":9307},{},[9308],{"type":291,"value":9309},"This is the stack we ended with:",{"type":281,"tag":455,"props":9311,"children":9312},{},[9313,9331,9342],{"type":281,"tag":459,"props":9314,"children":9315},{},[9316,9322,9324,9329],{"type":281,"tag":286,"props":9317,"children":9319},{"href":9318},"https://www.docker.com/",[9320],{"type":291,"value":9321},"Docker",{"type":291,"value":9323}," and ",{"type":281,"tag":286,"props":9325,"children":9326},{"href":559},[9327],{"type":291,"value":9328},"Docker Compose",{"type":291,"value":9330}," do manage the software",{"type":281,"tag":459,"props":9332,"children":9333},{},[9334,9340],{"type":281,"tag":286,"props":9335,"children":9337},{"href":9336},"https://about.gitlab.com/",[9338],{"type":291,"value":9339},"GitLab",{"type":291,"value":9341}," to store all the compose files",{"type":281,"tag":459,"props":9343,"children":9344},{},[9345,9351],{"type":281,"tag":286,"props":9346,"children":9348},{"href":9347},"https://docs.renovatebot.com",[9349],{"type":291,"value":9350},"Renovate Bot",{"type":291,"value":9352}," to keep the software up to date",{"type":281,"tag":530,"props":9354,"children":9356},{"id":9355},"about-the-stack",[9357],{"type":291,"value":9358},"About the stack",{"type":281,"tag":282,"props":9360,"children":9361},{},[9362,9364,9370],{"type":291,"value":9363},"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":281,"tag":315,"props":9365,"children":9367},{"className":9366},[],[9368],{"type":291,"value":9369},"scp",{"type":291,"value":9371}," it from a pipeline.",{"type":281,"tag":282,"props":9373,"children":9374},{},[9375,9377,9383],{"type":291,"value":9376},"GitLab is out primary tool for version control. Additionally, a ",{"type":281,"tag":286,"props":9378,"children":9380},{"href":9379},"https://docs.gitlab.com/runner/",[9381],{"type":291,"value":9382},"GitLab Runner",{"type":291,"value":9384}," takes care of running pipelines.",{"type":281,"tag":282,"props":9386,"children":9387},{},[9388],{"type":291,"value":9389},"Renovate automates dependency updates. PHP, Go, Python, Docker - to name a couple. We already use it for various projects.",{"type":281,"tag":530,"props":9391,"children":9393},{"id":9392},"container-with-docker-and-docker-compose",[9394],{"type":291,"value":9395},"Container with Docker and Docker Compose",{"type":281,"tag":282,"props":9397,"children":9398},{},[9399,9401,9407],{"type":291,"value":9400},"The main reason why we chose Docker is the ability to access a remote Docker host and execute Docker commands.\nRefer to ",{"type":281,"tag":286,"props":9402,"children":9404},{"href":9403},"https://docs.docker.com/reference/cli/docker/#host",[9405],{"type":291,"value":9406},"the official documentation",{"type":291,"value":9408}," for more information.",{"type":281,"tag":282,"props":9410,"children":9411},{},[9412,9414,9420],{"type":291,"value":9413},"We are using ",{"type":281,"tag":315,"props":9415,"children":9417},{"className":9416},[],[9418],{"type":291,"value":9419},"ssh",{"type":291,"value":9421}," to access our target server.",{"type":281,"tag":282,"props":9423,"children":9424},{},[9425],{"type":281,"tag":315,"props":9426,"children":9428},{"className":9427},[],[9429],{"type":291,"value":9430},"DOCKER_HOST=ssh://[username@]\u003CIP or host>[:port] docker compose up --wait",{"type":281,"tag":530,"props":9432,"children":9434},{"id":9433},"gitops-with-gitlab",[9435],{"type":291,"value":9436},"GitOps with GitLab",{"type":281,"tag":282,"props":9438,"children":9439},{},[9440],{"type":291,"value":9441},"The idea behind GitOps is to use a git repository to store the configuration. Here is an example:",{"type":281,"tag":301,"props":9443,"children":9445},{"className":1597,"code":9444,"language":1596,"meta":8,"style":8},".\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",[9446],{"type":281,"tag":315,"props":9447,"children":9448},{"__ignoreMap":8},[9449,9458,9472,9490,9502,9525,9538],{"type":281,"tag":319,"props":9450,"children":9451},{"class":321,"line":322},[9452],{"type":281,"tag":319,"props":9453,"children":9455},{"style":9454},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#66D9EF",[9456],{"type":291,"value":9457},".\n",{"type":281,"tag":319,"props":9459,"children":9460},{"class":321,"line":338},[9461,9466],{"type":281,"tag":319,"props":9462,"children":9463},{"style":1607},[9464],{"type":291,"value":9465},"├──.gitlab-ci.yml",{"type":281,"tag":319,"props":9467,"children":9469},{"style":9468},"--shiki-default:#6A737D;--shiki-dark:#6A737D;--shiki-sepia:#88846F",[9470],{"type":291,"value":9471},"             # pipeline definition\n",{"type":281,"tag":319,"props":9473,"children":9474},{"class":321,"line":351},[9475,9480,9485],{"type":281,"tag":319,"props":9476,"children":9477},{"style":1607},[9478],{"type":291,"value":9479},"├──",{"type":281,"tag":319,"props":9481,"children":9482},{"style":365},[9483],{"type":291,"value":9484}," renovate.json",{"type":281,"tag":319,"props":9486,"children":9487},{"style":9468},[9488],{"type":291,"value":9489},"             # Renovate configuration\n",{"type":281,"tag":319,"props":9491,"children":9492},{"class":321,"line":371},[9493,9497],{"type":281,"tag":319,"props":9494,"children":9495},{"style":1607},[9496],{"type":291,"value":9479},{"type":281,"tag":319,"props":9498,"children":9499},{"style":365},[9500],{"type":291,"value":9501}," nextcloud\n",{"type":281,"tag":319,"props":9503,"children":9504},{"class":321,"line":306},[9505,9510,9515,9520],{"type":281,"tag":319,"props":9506,"children":9507},{"style":1607},[9508],{"type":291,"value":9509},"│",{"type":281,"tag":319,"props":9511,"children":9512},{"style":365},[9513],{"type":291,"value":9514},"   ├──",{"type":281,"tag":319,"props":9516,"children":9517},{"style":365},[9518],{"type":291,"value":9519}," docker-compose.yml",{"type":281,"tag":319,"props":9521,"children":9522},{"style":9468},[9523],{"type":291,"value":9524},"   # Nextcloud file hosting and collaboration\n",{"type":281,"tag":319,"props":9526,"children":9527},{"class":321,"line":307},[9528,9533],{"type":281,"tag":319,"props":9529,"children":9530},{"style":1607},[9531],{"type":291,"value":9532},"└──",{"type":281,"tag":319,"props":9534,"children":9535},{"style":365},[9536],{"type":291,"value":9537}," traefik\n",{"type":281,"tag":319,"props":9539,"children":9540},{"class":321,"line":308},[9541,9546,9550],{"type":281,"tag":319,"props":9542,"children":9543},{"style":1607},[9544],{"type":291,"value":9545},"    └──",{"type":281,"tag":319,"props":9547,"children":9548},{"style":365},[9549],{"type":291,"value":9519},{"type":281,"tag":319,"props":9551,"children":9552},{"style":9468},[9553],{"type":291,"value":9554},"   # Traefik reverse proxy configuration\n",{"type":281,"tag":301,"props":9556,"children":9559},{"className":312,"code":9557,"filename":9558,"language":311,"meta":8,"style":8},"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",[9560],{"type":281,"tag":315,"props":9561,"children":9562},{"__ignoreMap":8},[9563,9574,9586,9598,9605,9616,9627,9643,9659,9670,9682,9694,9706,9718,9730,9742,9753,9765,9777,9789,9801,9850,9867,9884,9901,9908,9919,9935,9950,9962,9974,9991,10002,10014,10025,10037,10049,10061],{"type":281,"tag":319,"props":9564,"children":9565},{"class":321,"line":322},[9566,9570],{"type":281,"tag":319,"props":9567,"children":9568},{"style":326},[9569],{"type":291,"value":856},{"type":281,"tag":319,"props":9571,"children":9572},{"style":332},[9573],{"type":291,"value":335},{"type":281,"tag":319,"props":9575,"children":9576},{"class":321,"line":338},[9577,9582],{"type":281,"tag":319,"props":9578,"children":9579},{"style":326},[9580],{"type":291,"value":9581},"  nextcloud",{"type":281,"tag":319,"props":9583,"children":9584},{"style":332},[9585],{"type":291,"value":335},{"type":281,"tag":319,"props":9587,"children":9588},{"class":321,"line":351},[9589,9594],{"type":281,"tag":319,"props":9590,"children":9591},{"style":326},[9592],{"type":291,"value":9593},"  db",{"type":281,"tag":319,"props":9595,"children":9596},{"style":332},[9597],{"type":291,"value":335},{"type":281,"tag":319,"props":9599,"children":9600},{"class":321,"line":371},[9601],{"type":281,"tag":319,"props":9602,"children":9603},{"emptyLinePlaceholder":1042},[9604],{"type":291,"value":1045},{"type":281,"tag":319,"props":9606,"children":9607},{"class":321,"line":306},[9608,9612],{"type":281,"tag":319,"props":9609,"children":9610},{"style":326},[9611],{"type":291,"value":329},{"type":281,"tag":319,"props":9613,"children":9614},{"style":332},[9615],{"type":291,"value":335},{"type":281,"tag":319,"props":9617,"children":9618},{"class":321,"line":307},[9619,9623],{"type":281,"tag":319,"props":9620,"children":9621},{"style":326},[9622],{"type":291,"value":9593},{"type":281,"tag":319,"props":9624,"children":9625},{"style":332},[9626],{"type":291,"value":335},{"type":281,"tag":319,"props":9628,"children":9629},{"class":321,"line":308},[9630,9634,9638],{"type":281,"tag":319,"props":9631,"children":9632},{"style":326},[9633],{"type":291,"value":357},{"type":281,"tag":319,"props":9635,"children":9636},{"style":332},[9637],{"type":291,"value":362},{"type":281,"tag":319,"props":9639,"children":9640},{"style":365},[9641],{"type":291,"value":9642},"mariadb:11.8\n",{"type":281,"tag":319,"props":9644,"children":9645},{"class":321,"line":309},[9646,9650,9654],{"type":281,"tag":319,"props":9647,"children":9648},{"style":326},[9649],{"type":291,"value":928},{"type":281,"tag":319,"props":9651,"children":9652},{"style":332},[9653],{"type":291,"value":362},{"type":281,"tag":319,"props":9655,"children":9656},{"style":365},[9657],{"type":291,"value":9658},"unless-stopped\n",{"type":281,"tag":319,"props":9660,"children":9661},{"class":321,"line":310},[9662,9666],{"type":281,"tag":319,"props":9663,"children":9664},{"style":326},[9665],{"type":291,"value":1175},{"type":281,"tag":319,"props":9667,"children":9668},{"style":332},[9669],{"type":291,"value":335},{"type":281,"tag":319,"props":9671,"children":9672},{"class":321,"line":973},[9673,9677],{"type":281,"tag":319,"props":9674,"children":9675},{"style":332},[9676],{"type":291,"value":391},{"type":281,"tag":319,"props":9678,"children":9679},{"style":365},[9680],{"type":291,"value":9681},"db:/var/lib/mysql\n",{"type":281,"tag":319,"props":9683,"children":9684},{"class":321,"line":986},[9685,9690],{"type":281,"tag":319,"props":9686,"children":9687},{"style":326},[9688],{"type":291,"value":9689},"    environment",{"type":281,"tag":319,"props":9691,"children":9692},{"style":332},[9693],{"type":291,"value":335},{"type":281,"tag":319,"props":9695,"children":9696},{"class":321,"line":999},[9697,9701],{"type":281,"tag":319,"props":9698,"children":9699},{"style":332},[9700],{"type":291,"value":391},{"type":281,"tag":319,"props":9702,"children":9703},{"style":365},[9704],{"type":291,"value":9705},"MARIADB_ROOT_PASSWORD=${NEXTCLOUD_MARIADB_ROOT_PASSWORD:?error}\n",{"type":281,"tag":319,"props":9707,"children":9708},{"class":321,"line":1012},[9709,9713],{"type":281,"tag":319,"props":9710,"children":9711},{"style":332},[9712],{"type":291,"value":391},{"type":281,"tag":319,"props":9714,"children":9715},{"style":365},[9716],{"type":291,"value":9717},"MARIADB_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":281,"tag":319,"props":9719,"children":9720},{"class":321,"line":1025},[9721,9725],{"type":281,"tag":319,"props":9722,"children":9723},{"style":332},[9724],{"type":291,"value":391},{"type":281,"tag":319,"props":9726,"children":9727},{"style":365},[9728],{"type":291,"value":9729},"MARIADB_DATABASE=nextcloud\n",{"type":281,"tag":319,"props":9731,"children":9732},{"class":321,"line":1038},[9733,9737],{"type":281,"tag":319,"props":9734,"children":9735},{"style":332},[9736],{"type":291,"value":391},{"type":281,"tag":319,"props":9738,"children":9739},{"style":365},[9740],{"type":291,"value":9741},"MARIADB_USER=nextcloud\n",{"type":281,"tag":319,"props":9743,"children":9744},{"class":321,"line":1048},[9745,9749],{"type":281,"tag":319,"props":9746,"children":9747},{"style":326},[9748],{"type":291,"value":979},{"type":281,"tag":319,"props":9750,"children":9751},{"style":332},[9752],{"type":291,"value":335},{"type":281,"tag":319,"props":9754,"children":9755},{"class":321,"line":1061},[9756,9760],{"type":281,"tag":319,"props":9757,"children":9758},{"style":332},[9759],{"type":291,"value":391},{"type":281,"tag":319,"props":9761,"children":9762},{"style":365},[9763],{"type":291,"value":9764},"--transaction-isolation=READ-COMMITTED\n",{"type":281,"tag":319,"props":9766,"children":9767},{"class":321,"line":1074},[9768,9772],{"type":281,"tag":319,"props":9769,"children":9770},{"style":332},[9771],{"type":291,"value":391},{"type":281,"tag":319,"props":9773,"children":9774},{"style":365},[9775],{"type":291,"value":9776},"--log-bin=binlog\n",{"type":281,"tag":319,"props":9778,"children":9779},{"class":321,"line":1083},[9780,9784],{"type":281,"tag":319,"props":9781,"children":9782},{"style":332},[9783],{"type":291,"value":391},{"type":281,"tag":319,"props":9785,"children":9786},{"style":365},[9787],{"type":291,"value":9788},"--binlog-format=ROW\n",{"type":281,"tag":319,"props":9790,"children":9791},{"class":321,"line":1096},[9792,9797],{"type":281,"tag":319,"props":9793,"children":9794},{"style":326},[9795],{"type":291,"value":9796},"    healthcheck",{"type":281,"tag":319,"props":9798,"children":9799},{"style":332},[9800],{"type":291,"value":335},{"type":281,"tag":319,"props":9802,"children":9803},{"class":321,"line":1109},[9804,9809,9813,9818,9823,9828,9832,9837,9841,9846],{"type":281,"tag":319,"props":9805,"children":9806},{"style":326},[9807],{"type":291,"value":9808},"      test",{"type":281,"tag":319,"props":9810,"children":9811},{"style":332},[9812],{"type":291,"value":1778},{"type":281,"tag":319,"props":9814,"children":9815},{"style":365},[9816],{"type":291,"value":9817},"\"CMD\"",{"type":281,"tag":319,"props":9819,"children":9820},{"style":332},[9821],{"type":291,"value":9822},", ",{"type":281,"tag":319,"props":9824,"children":9825},{"style":365},[9826],{"type":291,"value":9827},"\"healthcheck.sh\"",{"type":281,"tag":319,"props":9829,"children":9830},{"style":332},[9831],{"type":291,"value":9822},{"type":281,"tag":319,"props":9833,"children":9834},{"style":365},[9835],{"type":291,"value":9836},"\"--connect\"",{"type":281,"tag":319,"props":9838,"children":9839},{"style":332},[9840],{"type":291,"value":9822},{"type":281,"tag":319,"props":9842,"children":9843},{"style":365},[9844],{"type":291,"value":9845},"\"--innodb_initialized\"",{"type":281,"tag":319,"props":9847,"children":9848},{"style":332},[9849],{"type":291,"value":1788},{"type":281,"tag":319,"props":9851,"children":9852},{"class":321,"line":1122},[9853,9858,9862],{"type":281,"tag":319,"props":9854,"children":9855},{"style":326},[9856],{"type":291,"value":9857},"      interval",{"type":281,"tag":319,"props":9859,"children":9860},{"style":332},[9861],{"type":291,"value":362},{"type":281,"tag":319,"props":9863,"children":9864},{"style":365},[9865],{"type":291,"value":9866},"15s\n",{"type":281,"tag":319,"props":9868,"children":9869},{"class":321,"line":1130},[9870,9875,9879],{"type":281,"tag":319,"props":9871,"children":9872},{"style":326},[9873],{"type":291,"value":9874},"      timeout",{"type":281,"tag":319,"props":9876,"children":9877},{"style":332},[9878],{"type":291,"value":362},{"type":281,"tag":319,"props":9880,"children":9881},{"style":365},[9882],{"type":291,"value":9883},"5s\n",{"type":281,"tag":319,"props":9885,"children":9886},{"class":321,"line":1143},[9887,9892,9896],{"type":281,"tag":319,"props":9888,"children":9889},{"style":326},[9890],{"type":291,"value":9891},"      retries",{"type":281,"tag":319,"props":9893,"children":9894},{"style":332},[9895],{"type":291,"value":362},{"type":281,"tag":319,"props":9897,"children":9898},{"style":1622},[9899],{"type":291,"value":9900},"6\n",{"type":281,"tag":319,"props":9902,"children":9903},{"class":321,"line":1156},[9904],{"type":281,"tag":319,"props":9905,"children":9906},{"emptyLinePlaceholder":1042},[9907],{"type":291,"value":1045},{"type":281,"tag":319,"props":9909,"children":9910},{"class":321,"line":1169},[9911,9915],{"type":281,"tag":319,"props":9912,"children":9913},{"style":326},[9914],{"type":291,"value":9581},{"type":281,"tag":319,"props":9916,"children":9917},{"style":332},[9918],{"type":291,"value":335},{"type":281,"tag":319,"props":9920,"children":9921},{"class":321,"line":1182},[9922,9926,9930],{"type":281,"tag":319,"props":9923,"children":9924},{"style":326},[9925],{"type":291,"value":357},{"type":281,"tag":319,"props":9927,"children":9928},{"style":332},[9929],{"type":291,"value":362},{"type":281,"tag":319,"props":9931,"children":9932},{"style":365},[9933],{"type":291,"value":9934},"nextcloud:32.0.0\n",{"type":281,"tag":319,"props":9936,"children":9937},{"class":321,"line":1195},[9938,9942,9946],{"type":281,"tag":319,"props":9939,"children":9940},{"style":326},[9941],{"type":291,"value":928},{"type":281,"tag":319,"props":9943,"children":9944},{"style":332},[9945],{"type":291,"value":362},{"type":281,"tag":319,"props":9947,"children":9948},{"style":365},[9949],{"type":291,"value":9658},{"type":281,"tag":319,"props":9951,"children":9952},{"class":321,"line":2048},[9953,9958],{"type":281,"tag":319,"props":9954,"children":9955},{"style":326},[9956],{"type":291,"value":9957},"    depends_on",{"type":281,"tag":319,"props":9959,"children":9960},{"style":332},[9961],{"type":291,"value":335},{"type":281,"tag":319,"props":9963,"children":9964},{"class":321,"line":2049},[9965,9970],{"type":281,"tag":319,"props":9966,"children":9967},{"style":326},[9968],{"type":291,"value":9969},"      db",{"type":281,"tag":319,"props":9971,"children":9972},{"style":332},[9973],{"type":291,"value":335},{"type":281,"tag":319,"props":9975,"children":9976},{"class":321,"line":2050},[9977,9982,9986],{"type":281,"tag":319,"props":9978,"children":9979},{"style":326},[9980],{"type":291,"value":9981},"        condition",{"type":281,"tag":319,"props":9983,"children":9984},{"style":332},[9985],{"type":291,"value":362},{"type":281,"tag":319,"props":9987,"children":9988},{"style":365},[9989],{"type":291,"value":9990},"service_healthy\n",{"type":281,"tag":319,"props":9992,"children":9993},{"class":321,"line":2051},[9994,9998],{"type":281,"tag":319,"props":9995,"children":9996},{"style":326},[9997],{"type":291,"value":1175},{"type":281,"tag":319,"props":9999,"children":10000},{"style":332},[10001],{"type":291,"value":335},{"type":281,"tag":319,"props":10003,"children":10004},{"class":321,"line":2052},[10005,10009],{"type":281,"tag":319,"props":10006,"children":10007},{"style":332},[10008],{"type":291,"value":391},{"type":281,"tag":319,"props":10010,"children":10011},{"style":365},[10012],{"type":291,"value":10013},"nextcloud:/var/www/html\n",{"type":281,"tag":319,"props":10015,"children":10016},{"class":321,"line":2053},[10017,10021],{"type":281,"tag":319,"props":10018,"children":10019},{"style":326},[10020],{"type":291,"value":9689},{"type":281,"tag":319,"props":10022,"children":10023},{"style":332},[10024],{"type":291,"value":335},{"type":281,"tag":319,"props":10026,"children":10027},{"class":321,"line":2054},[10028,10032],{"type":281,"tag":319,"props":10029,"children":10030},{"style":332},[10031],{"type":291,"value":391},{"type":281,"tag":319,"props":10033,"children":10034},{"style":365},[10035],{"type":291,"value":10036},"MYSQL_PASSWORD=${NEXTCLOUD_MARIADB_PASSWORD:?error}\n",{"type":281,"tag":319,"props":10038,"children":10039},{"class":321,"line":2055},[10040,10044],{"type":281,"tag":319,"props":10041,"children":10042},{"style":332},[10043],{"type":291,"value":391},{"type":281,"tag":319,"props":10045,"children":10046},{"style":365},[10047],{"type":291,"value":10048},"MYSQL_DATABASE=nextcloud\n",{"type":281,"tag":319,"props":10050,"children":10051},{"class":321,"line":2579},[10052,10056],{"type":281,"tag":319,"props":10053,"children":10054},{"style":332},[10055],{"type":291,"value":391},{"type":281,"tag":319,"props":10057,"children":10058},{"style":365},[10059],{"type":291,"value":10060},"MYSQL_USER=nextcloud\n",{"type":281,"tag":319,"props":10062,"children":10063},{"class":321,"line":2056},[10064,10068],{"type":281,"tag":319,"props":10065,"children":10066},{"style":332},[10067],{"type":291,"value":391},{"type":281,"tag":319,"props":10069,"children":10070},{"style":365},[10071],{"type":291,"value":10072},"MYSQL_HOST=db\n",{"type":281,"tag":301,"props":10074,"children":10078},{"className":10075,"code":10076,"language":10077,"meta":8,"style":8},"language-dotenv shiki shiki-themes github-dark github-dark monokai","NEXTCLOUD_MARIADB_ROOT_PASSWORD=\nNEXTCLOUD_MARIADB_PASSWORD=\n","dotenv",[10079],{"type":281,"tag":315,"props":10080,"children":10081},{"__ignoreMap":8},[10082,10096],{"type":281,"tag":319,"props":10083,"children":10084},{"class":321,"line":322},[10085,10091],{"type":281,"tag":319,"props":10086,"children":10088},{"style":10087},"--shiki-default:#FFAB70;--shiki-dark:#FFAB70;--shiki-sepia:#F8F8F2",[10089],{"type":291,"value":10090},"NEXTCLOUD_MARIADB_ROOT_PASSWORD",{"type":281,"tag":319,"props":10092,"children":10093},{"style":7965},[10094],{"type":291,"value":10095},"=\n",{"type":281,"tag":319,"props":10097,"children":10098},{"class":321,"line":338},[10099,10104],{"type":281,"tag":319,"props":10100,"children":10101},{"style":10087},[10102],{"type":291,"value":10103},"NEXTCLOUD_MARIADB_PASSWORD",{"type":281,"tag":319,"props":10105,"children":10106},{"style":7965},[10107],{"type":291,"value":10095},{"type":281,"tag":282,"props":10109,"children":10110},{},[10111,10113],{"type":291,"value":10112},"are stored as ",{"type":281,"tag":286,"props":10114,"children":10116},{"href":10115},"https://docs.gitlab.com/ci/variables/",[10117],{"type":291,"value":10118},"CI/CD Variables",{"type":281,"tag":832,"props":10120,"children":10121},{},[],{"type":281,"tag":282,"props":10123,"children":10124},{},[10125],{"type":291,"value":10126},"To deploy the stack, we have a pipeline:",{"type":281,"tag":301,"props":10128,"children":10130},{"className":312,"code":10129,"filename":8401,"language":311,"meta":8,"style":8},"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",[10131],{"type":281,"tag":315,"props":10132,"children":10133},{"__ignoreMap":8},[10134,10145,10157,10164,10175,10190,10206,10217,10234,10245,10257,10268],{"type":281,"tag":319,"props":10135,"children":10136},{"class":321,"line":322},[10137,10141],{"type":281,"tag":319,"props":10138,"children":10139},{"style":326},[10140],{"type":291,"value":1700},{"type":281,"tag":319,"props":10142,"children":10143},{"style":332},[10144],{"type":291,"value":335},{"type":281,"tag":319,"props":10146,"children":10147},{"class":321,"line":338},[10148,10152],{"type":281,"tag":319,"props":10149,"children":10150},{"style":332},[10151],{"type":291,"value":1712},{"type":281,"tag":319,"props":10153,"children":10154},{"style":365},[10155],{"type":291,"value":10156},"deploy\n",{"type":281,"tag":319,"props":10158,"children":10159},{"class":321,"line":351},[10160],{"type":281,"tag":319,"props":10161,"children":10162},{"emptyLinePlaceholder":1042},[10163],{"type":291,"value":1045},{"type":281,"tag":319,"props":10165,"children":10166},{"class":321,"line":371},[10167,10171],{"type":281,"tag":319,"props":10168,"children":10169},{"style":326},[10170],{"type":291,"value":8442},{"type":281,"tag":319,"props":10172,"children":10173},{"style":332},[10174],{"type":291,"value":335},{"type":281,"tag":319,"props":10176,"children":10177},{"class":321,"line":306},[10178,10182,10186],{"type":281,"tag":319,"props":10179,"children":10180},{"style":326},[10181],{"type":291,"value":2110},{"type":281,"tag":319,"props":10183,"children":10184},{"style":332},[10185],{"type":291,"value":362},{"type":281,"tag":319,"props":10187,"children":10188},{"style":365},[10189],{"type":291,"value":10156},{"type":281,"tag":319,"props":10191,"children":10192},{"class":321,"line":307},[10193,10197,10201],{"type":281,"tag":319,"props":10194,"children":10195},{"style":326},[10196],{"type":291,"value":2126},{"type":281,"tag":319,"props":10198,"children":10199},{"style":332},[10200],{"type":291,"value":362},{"type":281,"tag":319,"props":10202,"children":10203},{"style":365},[10204],{"type":291,"value":10205},"docker:28\n",{"type":281,"tag":319,"props":10207,"children":10208},{"class":321,"line":308},[10209,10213],{"type":281,"tag":319,"props":10210,"children":10211},{"style":326},[10212],{"type":291,"value":2276},{"type":281,"tag":319,"props":10214,"children":10215},{"style":332},[10216],{"type":291,"value":335},{"type":281,"tag":319,"props":10218,"children":10219},{"class":321,"line":309},[10220,10225,10229],{"type":281,"tag":319,"props":10221,"children":10222},{"style":326},[10223],{"type":291,"value":10224},"    DOCKER_HOST",{"type":281,"tag":319,"props":10226,"children":10227},{"style":332},[10228],{"type":291,"value":362},{"type":281,"tag":319,"props":10230,"children":10231},{"style":365},[10232],{"type":291,"value":10233},"ssh://[username@]\u003CIP or host>[:port]\n",{"type":281,"tag":319,"props":10235,"children":10236},{"class":321,"line":310},[10237,10241],{"type":281,"tag":319,"props":10238,"children":10239},{"style":326},[10240],{"type":291,"value":2585},{"type":281,"tag":319,"props":10242,"children":10243},{"style":332},[10244],{"type":291,"value":335},{"type":281,"tag":319,"props":10246,"children":10247},{"class":321,"line":973},[10248,10252],{"type":281,"tag":319,"props":10249,"children":10250},{"style":332},[10251],{"type":291,"value":2188},{"type":281,"tag":319,"props":10253,"children":10254},{"style":365},[10255],{"type":291,"value":10256},"for file in $(find . -type f -name docker-compose.yml); do docker compose -f $file up --remove-orphans --wait; done\n",{"type":281,"tag":319,"props":10258,"children":10259},{"class":321,"line":986},[10260,10264],{"type":281,"tag":319,"props":10261,"children":10262},{"style":326},[10263],{"type":291,"value":2774},{"type":281,"tag":319,"props":10265,"children":10266},{"style":332},[10267],{"type":291,"value":335},{"type":281,"tag":319,"props":10269,"children":10270},{"class":321,"line":999},[10271,10275,10279,10283],{"type":281,"tag":319,"props":10272,"children":10273},{"style":332},[10274],{"type":291,"value":2188},{"type":281,"tag":319,"props":10276,"children":10277},{"style":326},[10278],{"type":291,"value":1895},{"type":281,"tag":319,"props":10280,"children":10281},{"style":332},[10282],{"type":291,"value":362},{"type":281,"tag":319,"props":10284,"children":10285},{"style":365},[10286],{"type":291,"value":10287},"$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n",{"type":281,"tag":282,"props":10289,"children":10290},{},[10291,10293,10299],{"type":291,"value":10292},"The pipeline runs with every commit on the default branch, iterates through all ",{"type":281,"tag":315,"props":10294,"children":10296},{"className":10295},[],[10297],{"type":291,"value":10298},"docker-compose.yml",{"type":291,"value":10300}," files, and deploys them.",{"type":281,"tag":530,"props":10302,"children":10304},{"id":10303},"keep-your-deployments-up-to-date-with-renovate-bot",[10305],{"type":291,"value":10306},"Keep your deployments up-to-date with Renovate Bot",{"type":281,"tag":282,"props":10308,"children":10309},{},[10310],{"type":291,"value":10311},"Here is where Renovate kicks in.",{"type":281,"tag":301,"props":10313,"children":10316},{"className":5036,"code":10314,"filename":10315,"language":5040,"meta":8,"style":8},"{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:best-practices\"\n  ]\n}\n","renovate.json",[10317],{"type":281,"tag":315,"props":10318,"children":10319},{"__ignoreMap":8},[10320,10327,10348,10360,10368,10375],{"type":281,"tag":319,"props":10321,"children":10322},{"class":321,"line":322},[10323],{"type":281,"tag":319,"props":10324,"children":10325},{"style":332},[10326],{"type":291,"value":5052},{"type":281,"tag":319,"props":10328,"children":10329},{"class":321,"line":338},[10330,10335,10339,10344],{"type":281,"tag":319,"props":10331,"children":10332},{"style":5058},[10333],{"type":291,"value":10334},"  \"$schema\"",{"type":281,"tag":319,"props":10336,"children":10337},{"style":332},[10338],{"type":291,"value":362},{"type":281,"tag":319,"props":10340,"children":10341},{"style":5068},[10342],{"type":291,"value":10343},"\"https://docs.renovatebot.com/renovate-schema.json\"",{"type":281,"tag":319,"props":10345,"children":10346},{"style":332},[10347],{"type":291,"value":5076},{"type":281,"tag":319,"props":10349,"children":10350},{"class":321,"line":351},[10351,10356],{"type":281,"tag":319,"props":10352,"children":10353},{"style":5058},[10354],{"type":291,"value":10355},"  \"extends\"",{"type":281,"tag":319,"props":10357,"children":10358},{"style":332},[10359],{"type":291,"value":5293},{"type":281,"tag":319,"props":10361,"children":10362},{"class":321,"line":371},[10363],{"type":281,"tag":319,"props":10364,"children":10365},{"style":5068},[10366],{"type":291,"value":10367},"    \"config:best-practices\"\n",{"type":281,"tag":319,"props":10369,"children":10370},{"class":321,"line":306},[10371],{"type":281,"tag":319,"props":10372,"children":10373},{"style":332},[10374],{"type":291,"value":9188},{"type":281,"tag":319,"props":10376,"children":10377},{"class":321,"line":307},[10378],{"type":281,"tag":319,"props":10379,"children":10380},{"style":332},[10381],{"type":291,"value":6041},{"type":281,"tag":282,"props":10383,"children":10384},{},[10385],{"type":291,"value":10386},"Renovate will create Merge Requests for every update. Nice!",{"type":281,"tag":530,"props":10388,"children":10390},{"id":10389},"automated-security-updates-and-opt-in-for-minormajor-version-updates",[10391],{"type":291,"value":10392},"Automated security updates and opt-in for minor/major version updates",{"type":281,"tag":282,"props":10394,"children":10395},{},[10396],{"type":291,"value":10397},"The current configuration creates Merge Requests for every update, but we want security updates to happen without user interaction.",{"type":281,"tag":282,"props":10399,"children":10400},{},[10401,10403],{"type":291,"value":10402},"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":281,"tag":286,"props":10404,"children":10406},{"href":10405},"https://hub.docker.com/_/mariadb",[10407],{"type":291,"value":10408},"MariaDB",{"type":281,"tag":282,"props":10410,"children":10411},{},[10412,10414,10420],{"type":291,"value":10413},"There are ",{"type":281,"tag":315,"props":10415,"children":10417},{"className":10416},[],[10418],{"type":291,"value":10419},"11.8.3-noble, 11.8-noble, 11-noble, lts-noble, 11.8.3, 11.8, 11, lts",{"type":291,"value":10421},", all of which refer to the same image.",{"type":281,"tag":282,"props":10423,"children":10424},{},[10425,10431,10433,10439,10441,10447,10448,10454],{"type":281,"tag":315,"props":10426,"children":10428},{"className":10427},[],[10429],{"type":291,"value":10430},"11.8.3-noble",{"type":291,"value":10432}," means that we get MariaDB in version ",{"type":281,"tag":315,"props":10434,"children":10436},{"className":10435},[],[10437],{"type":291,"value":10438},"11.8.3",{"type":291,"value":10440}," based on Ubuntu Noble.\n",{"type":281,"tag":315,"props":10442,"children":10444},{"className":10443},[],[10445],{"type":291,"value":10446},"11.8-noble",{"type":291,"value":10432},{"type":281,"tag":315,"props":10449,"children":10451},{"className":10450},[],[10452],{"type":291,"value":10453},"11.8.\u003Clatest_path>",{"type":291,"value":10455}," based on Ubuntu Noble.",{"type":281,"tag":282,"props":10457,"children":10458},{},[10459,10461,10467,10469,10474,10476,10481],{"type":291,"value":10460},"When a neu version of MariaDB is released, e.g ",{"type":281,"tag":315,"props":10462,"children":10464},{"className":10463},[],[10465],{"type":291,"value":10466},"11.8.4-noble",{"type":291,"value":10468},", a new ",{"type":281,"tag":315,"props":10470,"children":10472},{"className":10471},[],[10473],{"type":291,"value":10466},{"type":291,"value":10475}," tag will be pushed, but the ",{"type":281,"tag":315,"props":10477,"children":10479},{"className":10478},[],[10480],{"type":291,"value":10446},{"type":291,"value":10482}," will be updated.",{"type":281,"tag":282,"props":10484,"children":10485},{},[10486,10488,10493],{"type":291,"value":10487},"This same is true for the Ubuntu update. The ",{"type":281,"tag":315,"props":10489,"children":10491},{"className":10490},[],[10492],{"type":291,"value":10430},{"type":291,"value":10494}," tag can be updated, if the image is rebuild with the latest Ubuntu image.",{"type":281,"tag":282,"props":10496,"children":10497},{},[10498,10500,10506,10508,10514],{"type":291,"value":10499},"Running ",{"type":281,"tag":315,"props":10501,"children":10503},{"className":10502},[],[10504],{"type":291,"value":10505},"docker compose up",{"type":291,"value":10507}," on ",{"type":281,"tag":315,"props":10509,"children":10511},{"className":10510},[],[10512],{"type":291,"value":10513},"mariadb:11.8-noble",{"type":291,"value":10515}," will do nothing, because Docker is not aware of that change.",{"type":281,"tag":282,"props":10517,"children":10518},{},[10519,10521,10527],{"type":291,"value":10520},"In the example above we reference ",{"type":281,"tag":315,"props":10522,"children":10524},{"className":10523},[],[10525],{"type":291,"value":10526},"mariadb:11.8",{"type":291,"value":10528},", because we want to use the latest patch version based on the most current OS.",{"type":281,"tag":832,"props":10530,"children":10531},{},[],{"type":281,"tag":282,"props":10533,"children":10534},{},[10535],{"type":291,"value":10536},"How to tell Docker that there is a new version?",{"type":281,"tag":282,"props":10538,"children":10539},{},[10540,10542,10548],{"type":291,"value":10541},"The main idea is to attach a ",{"type":281,"tag":286,"props":10543,"children":10545},{"href":10544},"https://docs.docker.com/dhi/core-concepts/digests/",[10546],{"type":291,"value":10547},"digest",{"type":291,"value":10549}," to the Docker image.",{"type":281,"tag":282,"props":10551,"children":10552},{},[10553,10555,10560,10562],{"type":291,"value":10554},"When running Renovate for the first time, it will find the reference to ",{"type":281,"tag":315,"props":10556,"children":10558},{"className":10557},[],[10559],{"type":291,"value":10526},{"type":291,"value":10561}," and create a merge request to pin the Digest to something like ",{"type":281,"tag":315,"props":10563,"children":10565},{"className":10564},[],[10566],{"type":291,"value":10567},"mariadb:11.8@sha256:ae6119716edac6998ae85508431b3d2e666530ddf4e94c61a10710caec9b0f71",{"type":281,"tag":282,"props":10569,"children":10570},{},[10571],{"type":291,"value":10572},"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":281,"tag":282,"props":10574,"children":10575},{},[10576],{"type":291,"value":10577},"To merge these updates automatically, we need to do some adjustments.",{"type":281,"tag":301,"props":10579,"children":10582},{"className":5036,"code":10580,"filename":10315,"highlights":10581,"language":5040,"meta":8,"style":8},"{\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",[306,307,308,309],[10583],{"type":281,"tag":315,"props":10584,"children":10585},{"__ignoreMap":8},[10586,10593,10612,10623,10635,10644,10652,10674,10691],{"type":281,"tag":319,"props":10587,"children":10588},{"class":321,"line":322},[10589],{"type":281,"tag":319,"props":10590,"children":10591},{"style":332},[10592],{"type":291,"value":5052},{"type":281,"tag":319,"props":10594,"children":10595},{"class":321,"line":338},[10596,10600,10604,10608],{"type":281,"tag":319,"props":10597,"children":10598},{"style":5058},[10599],{"type":291,"value":10334},{"type":281,"tag":319,"props":10601,"children":10602},{"style":332},[10603],{"type":291,"value":362},{"type":281,"tag":319,"props":10605,"children":10606},{"style":5068},[10607],{"type":291,"value":10343},{"type":281,"tag":319,"props":10609,"children":10610},{"style":332},[10611],{"type":291,"value":5076},{"type":281,"tag":319,"props":10613,"children":10614},{"class":321,"line":351},[10615,10619],{"type":281,"tag":319,"props":10616,"children":10617},{"style":5058},[10618],{"type":291,"value":10355},{"type":281,"tag":319,"props":10620,"children":10621},{"style":332},[10622],{"type":291,"value":5293},{"type":281,"tag":319,"props":10624,"children":10625},{"class":321,"line":371},[10626,10631],{"type":281,"tag":319,"props":10627,"children":10628},{"style":5068},[10629],{"type":291,"value":10630},"    \"config:best-practices\"",{"type":281,"tag":319,"props":10632,"children":10633},{"style":332},[10634],{"type":291,"value":5076},{"type":281,"tag":319,"props":10636,"children":10638},{"class":10637,"line":306},[321,385],[10639],{"type":281,"tag":319,"props":10640,"children":10641},{"style":5068},[10642],{"type":291,"value":10643},"    \"default:automergeDigest\"\n",{"type":281,"tag":319,"props":10645,"children":10647},{"class":10646,"line":307},[321,385],[10648],{"type":281,"tag":319,"props":10649,"children":10650},{"style":332},[10651],{"type":291,"value":5622},{"type":281,"tag":319,"props":10653,"children":10655},{"class":10654,"line":308},[321,385],[10656,10661,10665,10670],{"type":281,"tag":319,"props":10657,"children":10658},{"style":5058},[10659],{"type":291,"value":10660},"  \"automergeType\"",{"type":281,"tag":319,"props":10662,"children":10663},{"style":332},[10664],{"type":291,"value":362},{"type":281,"tag":319,"props":10666,"children":10667},{"style":5068},[10668],{"type":291,"value":10669},"\"branch\"",{"type":281,"tag":319,"props":10671,"children":10672},{"style":332},[10673],{"type":291,"value":5076},{"type":281,"tag":319,"props":10675,"children":10677},{"class":10676,"line":309},[321,385],[10678,10683,10687],{"type":281,"tag":319,"props":10679,"children":10680},{"style":5058},[10681],{"type":291,"value":10682},"  \"ignoreTests\"",{"type":281,"tag":319,"props":10684,"children":10685},{"style":332},[10686],{"type":291,"value":362},{"type":281,"tag":319,"props":10688,"children":10689},{"style":1622},[10690],{"type":291,"value":4800},{"type":281,"tag":319,"props":10692,"children":10693},{"class":321,"line":310},[10694],{"type":281,"tag":319,"props":10695,"children":10696},{"style":332},[10697],{"type":291,"value":6041},{"type":281,"tag":282,"props":10699,"children":10700},{},[10701,10703,10709,10710],{"type":291,"value":10702},"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":281,"tag":286,"props":10704,"children":10706},{"href":10705},"https://docs.renovatebot.com/key-concepts/automerge/#branch-vs-pr-automerging",[10707],{"type":291,"value":10708},"automergeType",{"type":291,"value":9323},{"type":281,"tag":286,"props":10711,"children":10713},{"href":10712},"https://docs.renovatebot.com/key-concepts/automerge/#absence-of-tests",[10714],{"type":291,"value":10715},"ignoreTests",{"type":281,"tag":1477,"props":10717,"children":10718},{},[10719],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":10721},[10722,10723,10724,10725,10726],{"id":9355,"depth":338,"text":9358},{"id":9392,"depth":338,"text":9395},{"id":9433,"depth":338,"text":9436},{"id":10303,"depth":338,"text":10306},{"id":10389,"depth":338,"text":10392},{"_path":72,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":73,"description":74,"author":11,"image":12,"releaseDate":75,"blogCategories":10728,"articleTags":10729,"tags":10730,"body":10731,"_type":20,"_id":79,"_source":22,"_file":80,"_stem":81,"_extension":25},[15,16],[16,33],[36,19],{"type":278,"children":10732,"toc":11254},[10733,10737,10748,10754,10767,10776,10807,10813,10840,10845,10873,11179,11184,11250],{"type":281,"tag":1499,"props":10734,"children":10736},{"alt":8,"aspect-ratio":1501,"height":1502,"object-fit":1503,"src":10735},"/blog/shopware-renovate.png",[],{"type":281,"tag":282,"props":10738,"children":10739},{},[10740,10746],{"type":281,"tag":286,"props":10741,"children":10743},{"href":10742},"https://docs.renovatebot.com/",[10744],{"type":291,"value":10745},"Renovate",{"type":291,"value":10747}," 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":281,"tag":530,"props":10749,"children":10751},{"id":10750},"shopware-versioning-scheme",[10752],{"type":291,"value":10753},"Shopware versioning scheme",{"type":281,"tag":282,"props":10755,"children":10756},{},[10757,10759,10765],{"type":291,"value":10758},"Shopware is using a custom versioning scheme. You can read the ",{"type":281,"tag":286,"props":10760,"children":10762},{"href":10761},"https://www.shopware.com/en/news/shopware-6-versioning-strategy/",[10763],{"type":291,"value":10764},"official article",{"type":291,"value":10766},", but in short:",{"type":281,"tag":10768,"props":10769,"children":10770},"blockquote",{},[10771],{"type":281,"tag":282,"props":10772,"children":10773},{},[10774],{"type":291,"value":10775},"Shopware implemented SemVer as  \"SemVer with benefits\".",{"type":281,"tag":10768,"props":10777,"children":10778},{},[10779,10784,10802],{"type":281,"tag":282,"props":10780,"children":10781},{},[10782],{"type":291,"value":10783},"A SemVer compliant version has three numbers: Major, Minor, and Patch. They are incremented following this ruleset:",{"type":281,"tag":455,"props":10785,"children":10786},{},[10787,10792,10797],{"type":281,"tag":459,"props":10788,"children":10789},{},[10790],{"type":291,"value":10791},"MAJOR: Incompatible API changes are made",{"type":281,"tag":459,"props":10793,"children":10794},{},[10795],{"type":291,"value":10796},"MINOR: Functionality is added in a backward-compatible manner",{"type":281,"tag":459,"props":10798,"children":10799},{},[10800],{"type":291,"value":10801},"PATCH: Backward-compatible bug fixes are made",{"type":281,"tag":282,"props":10803,"children":10804},{},[10805],{"type":291,"value":10806},"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":281,"tag":530,"props":10808,"children":10810},{"id":10809},"renovate-configuration",[10811],{"type":291,"value":10812},"Renovate configuration",{"type":281,"tag":282,"props":10814,"children":10815},{},[10816,10818,10824,10826,10832,10834],{"type":291,"value":10817},"The ",{"type":281,"tag":315,"props":10819,"children":10821},{"className":10820},[],[10822],{"type":291,"value":10823},"\"big marketing number\"",{"type":291,"value":10825}," or ",{"type":281,"tag":315,"props":10827,"children":10829},{"className":10828},[],[10830],{"type":291,"value":10831},"\"generation\"",{"type":291,"value":10833}," is reflected in Renovate as ",{"type":281,"tag":315,"props":10835,"children":10837},{"className":10836},[],[10838],{"type":291,"value":10839},"compatibility",{"type":281,"tag":282,"props":10841,"children":10842},{},[10843],{"type":291,"value":10844},"The following configuration will:",{"type":281,"tag":608,"props":10846,"children":10847},{},[10848,10853,10863,10868],{"type":281,"tag":459,"props":10849,"children":10850},{},[10851],{"type":291,"value":10852},"Group all shopware specific updates",{"type":281,"tag":459,"props":10854,"children":10855},{},[10856,10858],{"type":291,"value":10857},"Group the updates as ",{"type":281,"tag":315,"props":10859,"children":10861},{"className":10860},[],[10862],{"type":291,"value":36},{"type":281,"tag":459,"props":10864,"children":10865},{},[10866],{"type":291,"value":10867},"Tell Renovate how to extract the version",{"type":281,"tag":459,"props":10869,"children":10870},{},[10871],{"type":291,"value":10872},"Tell Renovate where to find changelog information",{"type":281,"tag":301,"props":10874,"children":10876},{"className":5036,"code":10875,"filename":10315,"language":5040,"meta":8,"style":8},"{\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",[10877],{"type":281,"tag":315,"props":10878,"children":10879},{"__ignoreMap":8},[10880,10887,10906,10918,10925,10946,10958,10966,10974,10986,10997,11009,11021,11029,11036,11057,11141,11158,11165,11172],{"type":281,"tag":319,"props":10881,"children":10882},{"class":321,"line":322},[10883],{"type":281,"tag":319,"props":10884,"children":10885},{"style":332},[10886],{"type":291,"value":5052},{"type":281,"tag":319,"props":10888,"children":10889},{"class":321,"line":338},[10890,10894,10898,10902],{"type":281,"tag":319,"props":10891,"children":10892},{"style":5058},[10893],{"type":291,"value":10334},{"type":281,"tag":319,"props":10895,"children":10896},{"style":332},[10897],{"type":291,"value":362},{"type":281,"tag":319,"props":10899,"children":10900},{"style":5068},[10901],{"type":291,"value":10343},{"type":281,"tag":319,"props":10903,"children":10904},{"style":332},[10905],{"type":291,"value":5076},{"type":281,"tag":319,"props":10907,"children":10908},{"class":321,"line":351},[10909,10914],{"type":281,"tag":319,"props":10910,"children":10911},{"style":5058},[10912],{"type":291,"value":10913},"  \"packageRules\"",{"type":281,"tag":319,"props":10915,"children":10916},{"style":332},[10917],{"type":291,"value":5293},{"type":281,"tag":319,"props":10919,"children":10920},{"class":321,"line":371},[10921],{"type":281,"tag":319,"props":10922,"children":10923},{"style":332},[10924],{"type":291,"value":5301},{"type":281,"tag":319,"props":10926,"children":10927},{"class":321,"line":306},[10928,10933,10937,10942],{"type":281,"tag":319,"props":10929,"children":10930},{"style":5058},[10931],{"type":291,"value":10932},"      \"description\"",{"type":281,"tag":319,"props":10934,"children":10935},{"style":332},[10936],{"type":291,"value":362},{"type":281,"tag":319,"props":10938,"children":10939},{"style":5068},[10940],{"type":291,"value":10941},"\"Follow Shopware version schema\"",{"type":281,"tag":319,"props":10943,"children":10944},{"style":332},[10945],{"type":291,"value":5076},{"type":281,"tag":319,"props":10947,"children":10948},{"class":321,"line":307},[10949,10954],{"type":281,"tag":319,"props":10950,"children":10951},{"style":5058},[10952],{"type":291,"value":10953},"      \"matchDatasources\"",{"type":281,"tag":319,"props":10955,"children":10956},{"style":332},[10957],{"type":291,"value":5293},{"type":281,"tag":319,"props":10959,"children":10960},{"class":321,"line":308},[10961],{"type":281,"tag":319,"props":10962,"children":10963},{"style":5068},[10964],{"type":291,"value":10965},"        \"packagist\"\n",{"type":281,"tag":319,"props":10967,"children":10968},{"class":321,"line":309},[10969],{"type":281,"tag":319,"props":10970,"children":10971},{"style":332},[10972],{"type":291,"value":10973},"      ],\n",{"type":281,"tag":319,"props":10975,"children":10976},{"class":321,"line":310},[10977,10982],{"type":281,"tag":319,"props":10978,"children":10979},{"style":5058},[10980],{"type":291,"value":10981},"      \"matchPackageNames\"",{"type":281,"tag":319,"props":10983,"children":10984},{"style":332},[10985],{"type":291,"value":5293},{"type":281,"tag":319,"props":10987,"children":10988},{"class":321,"line":973},[10989,10993],{"type":281,"tag":319,"props":10990,"children":10991},{"style":5068},[10992],{"type":291,"value":6449},{"type":281,"tag":319,"props":10994,"children":10995},{"style":332},[10996],{"type":291,"value":5076},{"type":281,"tag":319,"props":10998,"children":10999},{"class":321,"line":986},[11000,11005],{"type":281,"tag":319,"props":11001,"children":11002},{"style":5068},[11003],{"type":291,"value":11004},"        \"shopware/administration\"",{"type":281,"tag":319,"props":11006,"children":11007},{"style":332},[11008],{"type":291,"value":5076},{"type":281,"tag":319,"props":11010,"children":11011},{"class":321,"line":999},[11012,11017],{"type":281,"tag":319,"props":11013,"children":11014},{"style":5068},[11015],{"type":291,"value":11016},"        \"shopware/elasticsearch\"",{"type":281,"tag":319,"props":11018,"children":11019},{"style":332},[11020],{"type":291,"value":5076},{"type":281,"tag":319,"props":11022,"children":11023},{"class":321,"line":1012},[11024],{"type":281,"tag":319,"props":11025,"children":11026},{"style":5068},[11027],{"type":291,"value":11028},"        \"shopware/storefront\"\n",{"type":281,"tag":319,"props":11030,"children":11031},{"class":321,"line":1025},[11032],{"type":281,"tag":319,"props":11033,"children":11034},{"style":332},[11035],{"type":291,"value":10973},{"type":281,"tag":319,"props":11037,"children":11038},{"class":321,"line":1038},[11039,11044,11048,11053],{"type":281,"tag":319,"props":11040,"children":11041},{"style":5058},[11042],{"type":291,"value":11043},"      \"groupName\"",{"type":281,"tag":319,"props":11045,"children":11046},{"style":332},[11047],{"type":291,"value":362},{"type":281,"tag":319,"props":11049,"children":11050},{"style":5068},[11051],{"type":291,"value":11052},"\"shopware\"",{"type":281,"tag":319,"props":11054,"children":11055},{"style":332},[11056],{"type":291,"value":5076},{"type":281,"tag":319,"props":11058,"children":11059},{"class":321,"line":1048},[11060,11065,11069,11074,11078,11083,11087,11092,11096,11101,11105,11110,11114,11119,11123,11128,11132,11137],{"type":281,"tag":319,"props":11061,"children":11062},{"style":5058},[11063],{"type":291,"value":11064},"      \"versioning\"",{"type":281,"tag":319,"props":11066,"children":11067},{"style":332},[11068],{"type":291,"value":362},{"type":281,"tag":319,"props":11070,"children":11071},{"style":5068},[11072],{"type":291,"value":11073},"\"regex:(?\u003Ccompatibility>",{"type":281,"tag":319,"props":11075,"children":11076},{"style":1622},[11077],{"type":291,"value":5660},{"type":281,"tag":319,"props":11079,"children":11080},{"style":5068},[11081],{"type":291,"value":11082},"d+)",{"type":281,"tag":319,"props":11084,"children":11085},{"style":1622},[11086],{"type":291,"value":5660},{"type":281,"tag":319,"props":11088,"children":11089},{"style":5068},[11090],{"type":291,"value":11091},".(?\u003Cmajor>",{"type":281,"tag":319,"props":11093,"children":11094},{"style":1622},[11095],{"type":291,"value":5660},{"type":281,"tag":319,"props":11097,"children":11098},{"style":5068},[11099],{"type":291,"value":11100},"d+)(",{"type":281,"tag":319,"props":11102,"children":11103},{"style":1622},[11104],{"type":291,"value":5660},{"type":281,"tag":319,"props":11106,"children":11107},{"style":5068},[11108],{"type":291,"value":11109},".(?\u003Cminor>",{"type":281,"tag":319,"props":11111,"children":11112},{"style":1622},[11113],{"type":291,"value":5660},{"type":281,"tag":319,"props":11115,"children":11116},{"style":5068},[11117],{"type":291,"value":11118},"d+))?(",{"type":281,"tag":319,"props":11120,"children":11121},{"style":1622},[11122],{"type":291,"value":5660},{"type":281,"tag":319,"props":11124,"children":11125},{"style":5068},[11126],{"type":291,"value":11127},".(?\u003Cpatch>",{"type":281,"tag":319,"props":11129,"children":11130},{"style":1622},[11131],{"type":291,"value":5660},{"type":281,"tag":319,"props":11133,"children":11134},{"style":5068},[11135],{"type":291,"value":11136},"d+))?$\"",{"type":281,"tag":319,"props":11138,"children":11139},{"style":332},[11140],{"type":291,"value":5076},{"type":281,"tag":319,"props":11142,"children":11143},{"class":321,"line":1061},[11144,11149,11153],{"type":281,"tag":319,"props":11145,"children":11146},{"style":5058},[11147],{"type":291,"value":11148},"      \"sourceUrl\"",{"type":281,"tag":319,"props":11150,"children":11151},{"style":332},[11152],{"type":291,"value":362},{"type":281,"tag":319,"props":11154,"children":11155},{"style":5068},[11156],{"type":291,"value":11157},"\"https://github.com/shopware/shopware\"\n",{"type":281,"tag":319,"props":11159,"children":11160},{"class":321,"line":1074},[11161],{"type":281,"tag":319,"props":11162,"children":11163},{"style":332},[11164],{"type":291,"value":5614},{"type":281,"tag":319,"props":11166,"children":11167},{"class":321,"line":1083},[11168],{"type":281,"tag":319,"props":11169,"children":11170},{"style":332},[11171],{"type":291,"value":9188},{"type":281,"tag":319,"props":11173,"children":11174},{"class":321,"line":1096},[11175],{"type":281,"tag":319,"props":11176,"children":11177},{"style":332},[11178],{"type":291,"value":6041},{"type":281,"tag":282,"props":11180,"children":11181},{},[11182],{"type":291,"value":11183},"This should result in creation of following merge/pull requests",{"type":281,"tag":455,"props":11185,"children":11186},{},[11187,11221],{"type":281,"tag":459,"props":11188,"children":11189},{},[11190,11192,11198,11199,11205,11206,11212,11213,11219],{"type":291,"value":11191},"fix(deps): update shopware (",{"type":281,"tag":315,"props":11193,"children":11195},{"className":11194},[],[11196],{"type":291,"value":11197},"shopware/administration",{"type":291,"value":9822},{"type":281,"tag":315,"props":11200,"children":11202},{"className":11201},[],[11203],{"type":291,"value":11204},"shopware/core",{"type":291,"value":9822},{"type":281,"tag":315,"props":11207,"children":11209},{"className":11208},[],[11210],{"type":291,"value":11211},"shopware/elasticsearch",{"type":291,"value":9822},{"type":281,"tag":315,"props":11214,"children":11216},{"className":11215},[],[11217],{"type":291,"value":11218},"shopware/storefront",{"type":291,"value":11220},")`",{"type":281,"tag":459,"props":11222,"children":11223},{},[11224,11226,11231,11232,11237,11238,11243,11244,11249],{"type":291,"value":11225},"fix(deps): update shopware to v7 (major) (",{"type":281,"tag":315,"props":11227,"children":11229},{"className":11228},[],[11230],{"type":291,"value":11197},{"type":291,"value":9822},{"type":281,"tag":315,"props":11233,"children":11235},{"className":11234},[],[11236],{"type":291,"value":11204},{"type":291,"value":9822},{"type":281,"tag":315,"props":11239,"children":11241},{"className":11240},[],[11242],{"type":291,"value":11211},{"type":291,"value":9822},{"type":281,"tag":315,"props":11245,"children":11247},{"className":11246},[],[11248],{"type":291,"value":11218},{"type":291,"value":11220},{"type":281,"tag":1477,"props":11251,"children":11252},{},[11253],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":11255},[11256,11257],{"id":10750,"depth":338,"text":10753},{"id":10809,"depth":338,"text":10812},{"_path":83,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":84,"description":85,"author":86,"image":87,"releaseDate":88,"blogCategories":11259,"articleTags":11260,"tags":11261,"body":11262,"_type":20,"_id":95,"_source":22,"_file":96,"_stem":97,"_extension":25},[90],[92],[94],{"type":278,"children":11263,"toc":12748},[11264,11270,11276,11298,11306,11361,11375,11378,11381,11387,11424,11440,11468,11478,11493,11499,11549,11565,11645,11657,11666,11890,11902,11911,12024,12060,12082,12197,12208,12246,12275,12281,12299,12304,12385,12391,12608,12614,12630,12653,12668,12674,12684,12689,12696,12737,12743],{"type":281,"tag":1499,"props":11265,"children":11269},{"alt":11266,"aspect-ratio":11267,"height":1502,"object-fit":1503,"src":11268},"Fictional draft of a warning letter from the market surveillance authority with the description \"Non-compliance with accessibility requirements.\"","1.7","/blog/Abmahnung-Barrierefreiheitsstaerkungsgesetz.png",[],{"type":281,"tag":530,"props":11271,"children":11273},{"id":11272},"accessibility-becomes-mandatory-what-the-german-accessibility-strengthening-act-means-for-digital-services-from-2025",[11274],{"type":291,"value":11275},"Accessibility Becomes Mandatory: What the German Accessibility Strengthening Act Means for Digital Services from 2025",{"type":281,"tag":282,"props":11277,"children":11278},{},[11279,11285,11287,11296],{"type":281,"tag":11280,"props":11281,"children":11282},"strong",{},[11283],{"type":291,"value":11284},"Accessibility has been mandatory for many digital products and services since mid-2025.",{"type":291,"value":11286},"\nWe already explained this in our article \"Accessibility Will Be a Recommendation – and a Requirement.\"\nBeyond technical implementation, it's important to note that an\n",{"type":281,"tag":286,"props":11288,"children":11290},{"href":11289},"https://helmundwalter.de/blog/accessibility-will-be-recommended?utm_source=chatgpt.com",[11291],{"type":281,"tag":11280,"props":11292,"children":11293},{},[11294],{"type":291,"value":11295},"Accessibility Statement (AS)",{"type":291,"value":11297},"\nis legally required, and incorrect formulation can lead to warnings or regulatory pressure.",{"type":281,"tag":282,"props":11299,"children":11300},{},[11301],{"type":281,"tag":11280,"props":11302,"children":11303},{},[11304],{"type":291,"value":11305},"Contents of this blog post:",{"type":281,"tag":455,"props":11307,"children":11308},{},[11309,11321,11326,11336,11346,11356],{"type":281,"tag":459,"props":11310,"children":11311},{},[11312,11314,11319],{"type":291,"value":11313},"Why an ",{"type":281,"tag":11280,"props":11315,"children":11316},{},[11317],{"type":291,"value":11318},"Accessibility Statement according to BFSG",{"type":291,"value":11320}," is legally required",{"type":281,"tag":459,"props":11322,"children":11323},{},[11324],{"type":291,"value":11325},"What this statement must contain",{"type":281,"tag":459,"props":11327,"children":11328},{},[11329,11334],{"type":281,"tag":11280,"props":11330,"children":11331},{},[11332],{"type":291,"value":11333},"A proposal for a possible accessibility statement",{"type":291,"value":11335}," / AS",{"type":281,"tag":459,"props":11337,"children":11338},{},[11339,11341],{"type":291,"value":11340},"Brief explanation of where you should ",{"type":281,"tag":11280,"props":11342,"children":11343},{},[11344],{"type":291,"value":11345},"customize the statement individually and truthfully to your service",{"type":281,"tag":459,"props":11347,"children":11348},{},[11349,11354],{"type":281,"tag":11280,"props":11350,"children":11351},{},[11352],{"type":291,"value":11353},"Our experience with legal consultation",{"type":291,"value":11355}," on formulation",{"type":281,"tag":459,"props":11357,"children":11358},{},[11359],{"type":291,"value":11360},"What consequences non-compliance may have",{"type":281,"tag":319,"props":11362,"children":11365},{"className":11363},[11364],"text-right",[11366],{"type":281,"tag":282,"props":11367,"children":11368},{},[11369],{"type":281,"tag":11370,"props":11371,"children":11372},"em",{},[11373],{"type":291,"value":11374},"Reading time: approx. 15 minutes",{"type":281,"tag":1314,"props":11376,"children":11377},{},[],{"type":281,"tag":832,"props":11379,"children":11380},{},[],{"type":281,"tag":530,"props":11382,"children":11384},{"id":11383},"what-is-the-bfsg-and-accessibility-statement-about",[11385],{"type":291,"value":11386},"What is the BFSG and Accessibility Statement About?",{"type":281,"tag":282,"props":11388,"children":11389},{},[11390,11391,11397,11399,11408,11410,11415,11417,11422],{"type":291,"value":10817},{"type":281,"tag":286,"props":11392,"children":11394},{"href":11393},"https://bfsg-gesetz.de",[11395],{"type":291,"value":11396},"German Accessibility Strengthening Act (BFSG)",{"type":291,"value":11398}," requires digital offerings such as online shops, banking apps, or booking portals to be accessibly designed since June 28, 2025.\nThis follows the EU-wide ",{"type":281,"tag":286,"props":11400,"children":11402},{"href":11401},"https://commission.europa.eu/strategy-and-policy/policies/justice-and-fundamental-rights/disability/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en",[11403],{"type":281,"tag":11280,"props":11404,"children":11405},{},[11406],{"type":291,"value":11407},"European Accessibility Act (EAA)",{"type":291,"value":11409}," and the ",{"type":281,"tag":11280,"props":11411,"children":11412},{},[11413],{"type":291,"value":11414},"EN 301 549 standard",{"type":291,"value":11416},", which usually defines ",{"type":281,"tag":11280,"props":11418,"children":11419},{},[11420],{"type":291,"value":11421},"WCAG 2.1 AA",{"type":291,"value":11423}," as the technical target. Micro-enterprises with fewer than 10 employees and less than\n2 million € annual turnover are exempt.",{"type":281,"tag":282,"props":11425,"children":11426},{},[11427,11429,11438],{"type":291,"value":11428},"According to ",{"type":281,"tag":286,"props":11430,"children":11432},{"href":11431},"https://bfsg-gesetz.de/anlage-3/",[11433],{"type":281,"tag":11280,"props":11434,"children":11435},{},[11436],{"type":291,"value":11437},"§ 14 BFSG and Annex 3",{"type":291,"value":11439},", providers must publish an accessibility statement that contains the following points:",{"type":281,"tag":455,"props":11441,"children":11442},{},[11443,11448,11453,11458,11463],{"type":281,"tag":459,"props":11444,"children":11445},{},[11446],{"type":291,"value":11447},"General description of the digital service",{"type":281,"tag":459,"props":11449,"children":11450},{},[11451],{"type":291,"value":11452},"Compliance status of accessibility requirements (e.g., WCAG, EN 301 549)",{"type":281,"tag":459,"props":11454,"children":11455},{},[11456],{"type":291,"value":11457},"Contact options of the service provider for feedback on barriers",{"type":281,"tag":459,"props":11459,"children":11460},{},[11461],{"type":291,"value":11462},"Market surveillance authority as the responsible control body",{"type":281,"tag":459,"props":11464,"children":11465},{},[11466],{"type":291,"value":11467},"Optional information: Date of last review, review methodology, feedback mechanism",{"type":281,"tag":282,"props":11469,"children":11470},{},[11471,11476],{"type":281,"tag":11280,"props":11472,"children":11473},{},[11474],{"type":291,"value":11475},"There is no official template for the accessibility statement.",{"type":291,"value":11477},"\nTo our current knowledge, none is planned either.",{"type":281,"tag":282,"props":11479,"children":11480},{},[11481],{"type":281,"tag":11280,"props":11482,"children":11483},{},[11484,11486,11491],{"type":291,"value":11485},"Therefore, we will discuss below what such an\n",{"type":281,"tag":11370,"props":11487,"children":11488},{},[11489],{"type":291,"value":11490},"Accessibility Statement",{"type":291,"value":11492}," could look like.",{"type":281,"tag":530,"props":11494,"children":11496},{"id":11495},"our-template-for-your-as",[11497],{"type":291,"value":11498},"Our Template for Your AS",{"type":281,"tag":11500,"props":11501,"children":11505},"div",{"className":11502},[11503,11504],"doc-sheet","doc-sheet__border-top",[11506],{"type":281,"tag":11500,"props":11507,"children":11510},{"className":11508},[11509],"doc-sheet__section",[11511,11518,11543],{"type":281,"tag":11512,"props":11513,"children":11515},"h1",{"id":11514},"accessibility-information",[11516],{"type":291,"value":11517},"Accessibility Information",{"type":281,"tag":282,"props":11519,"children":11520},{},[11521,11523,11527,11529,11534,11536,11541],{"type":291,"value":11522},"We commit to implementing the requirements of the ",{"type":281,"tag":11280,"props":11524,"children":11525},{},[11526],{"type":291,"value":11396},{"type":291,"value":11528}," as well as the underlying ",{"type":281,"tag":11280,"props":11530,"children":11531},{},[11532],{"type":291,"value":11533},"EU Directive (EU) 2019/882 on accessibility requirements for products and services",{"type":291,"value":11535},". Our goal is to design our digital offerings – especially web applications and online services – so that they are ",{"type":281,"tag":11280,"props":11537,"children":11538},{},[11539],{"type":291,"value":11540},"accessibly available",{"type":291,"value":11542}," to all people, regardless of individual abilities or technical assistive devices.",{"type":281,"tag":530,"props":11544,"children":11546},{"id":11545},"service-description",[11547],{"type":291,"value":11548},"Service Description",{"type":281,"tag":11500,"props":11550,"children":11559},{"className":11551},[11552,11553,11554,11555,11556,11557,11558],"mt-8","mb-5","pl-0","pr-0","pt-5","pb-5","pa-sm-5",[11560],{"type":281,"tag":282,"props":11561,"children":11562},{},[11563],{"type":291,"value":11564},"You must individually adapt this part to your digital service.\nWe have provided an example for a classic online shop at this point.",{"type":281,"tag":11500,"props":11566,"children":11569},{"className":11567},[11503,11568],"doc-sheet__border-sides",[11570],{"type":281,"tag":11500,"props":11571,"children":11573},{"className":11572},[11509],[11574,11586,11626],{"type":281,"tag":282,"props":11575,"children":11576},{},[11577,11579,11584],{"type":291,"value":11578},"Our online shop enables users to\n",{"type":281,"tag":11280,"props":11580,"children":11581},{},[11582],{"type":291,"value":11583},"obtain information about products, digitally select and purchase products",{"type":291,"value":11585},".\nThe goods are each offered on their own product page with description, price, and\npossibly available variants such as size or color.",{"type":281,"tag":282,"props":11587,"children":11588},{},[11589,11591,11596,11598,11603,11605,11610,11612,11617,11619,11624],{"type":291,"value":11590},"The desired products can be added to a ",{"type":281,"tag":11280,"props":11592,"children":11593},{},[11594],{"type":291,"value":11595},"virtual shopping cart",{"type":291,"value":11597},".\nAfter selecting all items, the ordering process leads through the ",{"type":281,"tag":11280,"props":11599,"children":11600},{},[11601],{"type":291,"value":11602},"checkout area",{"type":291,"value":11604},",\nwhere a ",{"type":281,"tag":11280,"props":11606,"children":11607},{},[11608],{"type":291,"value":11609},"delivery address",{"type":291,"value":11611}," and possibly different ",{"type":281,"tag":11280,"props":11613,"children":11614},{},[11615],{"type":291,"value":11616},"billing address",{"type":291,"value":11618},"\nmust be entered, and a ",{"type":281,"tag":11280,"props":11620,"children":11621},{},[11622],{"type":291,"value":11623},"payment method",{"type":291,"value":11625}," must be selected.",{"type":281,"tag":282,"props":11627,"children":11628},{},[11629,11631,11636,11638,11643],{"type":291,"value":11630},"After successful ordering,\n",{"type":281,"tag":11280,"props":11632,"children":11633},{},[11634],{"type":291,"value":11635},"order confirmation and shipping confirmations are sent via email",{"type":291,"value":11637}," to the email address\nprovided during ordering.\n",{"type":281,"tag":11280,"props":11639,"children":11640},{},[11641],{"type":291,"value":11642},"Redirection to third-party services",{"type":291,"value":11644}," for processing payments may occur.\nWe have limited influence on the design and technical execution of these services.",{"type":281,"tag":319,"props":11646,"children":11648},{"className":11647},[11364],[11649],{"type":281,"tag":282,"props":11650,"children":11651},{},[11652],{"type":281,"tag":11370,"props":11653,"children":11654},{},[11655],{"type":291,"value":11656},"Adapt to individual service",{"type":281,"tag":11500,"props":11658,"children":11660},{"className":11659},[11552,11553,11554,11555,11556,11557,11558],[11661],{"type":281,"tag":282,"props":11662,"children":11663},{},[11664],{"type":291,"value":11665},"You don't necessarily need to provide the following part.\nHowever, it clarifies your previous efforts and measures, as well as your commitment\nin the area of accessibility, and offers a point of contact beyond the\nmarket surveillance authority.",{"type":281,"tag":11500,"props":11667,"children":11669},{"className":11668},[11503,11568],[11670],{"type":281,"tag":11500,"props":11671,"children":11673},{"className":11672},[11509],[11674,11680,11692,11704,11743,11754,11760,11798,11804,11816,11824,11864],{"type":281,"tag":530,"props":11675,"children":11677},{"id":11676},"accessibility-status",[11678],{"type":291,"value":11679},"Accessibility Status",{"type":281,"tag":282,"props":11681,"children":11682},{},[11683,11685,11690],{"type":291,"value":11684},"Our website and digital services are continuously adapted to applicable\n",{"type":281,"tag":11280,"props":11686,"children":11687},{},[11688],{"type":291,"value":11689},"accessibility standards (e.g., WCAG 2.1 AA and EN 301 549)",{"type":291,"value":11691},".\nWe actively pursue the goal of identifying, reducing, and ultimately completely eliminating existing barriers.",{"type":281,"tag":282,"props":11693,"children":11694},{},[11695,11697,11702],{"type":291,"value":11696},"Despite all care, ",{"type":281,"tag":11280,"props":11698,"children":11699},{},[11700],{"type":291,"value":11701},"temporary or partial barriers",{"type":291,"value":11703}," may occur in individual cases.\nThis can particularly happen:",{"type":281,"tag":455,"props":11705,"children":11706},{},[11707,11719,11731],{"type":281,"tag":459,"props":11708,"children":11709},{},[11710,11712,11717],{"type":291,"value":11711},"due to ongoing ",{"type":281,"tag":11280,"props":11713,"children":11714},{},[11715],{"type":291,"value":11716},"editorial or technical revisions",{"type":291,"value":11718}," of individual content and pages,",{"type":281,"tag":459,"props":11720,"children":11721},{},[11722,11724,11729],{"type":291,"value":11723},"due to ",{"type":281,"tag":11280,"props":11725,"children":11726},{},[11727],{"type":291,"value":11728},"different interpretations",{"type":291,"value":11730}," of technical accessibility requirements,",{"type":281,"tag":459,"props":11732,"children":11733},{},[11734,11736,11741],{"type":291,"value":11735},"or with ",{"type":281,"tag":11280,"props":11737,"children":11738},{},[11739],{"type":291,"value":11740},"complex functionalities",{"type":291,"value":11742}," for which no completely accessible solution is yet available.",{"type":281,"tag":282,"props":11744,"children":11745},{},[11746,11748,11753],{"type":291,"value":11747},"We continuously work to identify such deviations and\ndevelop solutions to enable all users ",{"type":281,"tag":11280,"props":11749,"children":11750},{},[11751],{"type":291,"value":11752},"low-threshold and equivalent access",{"type":291,"value":564},{"type":281,"tag":1248,"props":11755,"children":11757},{"id":11756},"last-review",[11758],{"type":291,"value":11759},"Last Review",{"type":281,"tag":282,"props":11761,"children":11762},{},[11763,11765,11770,11772,11777,11779,11784,11786,11790,11791,11796],{"type":291,"value":11764},"The last exemplary accessibility review took place on ",{"type":281,"tag":11370,"props":11766,"children":11767},{},[11768],{"type":291,"value":11769},"[Date of last review]",{"type":291,"value":11771},"\nby ",{"type":281,"tag":11370,"props":11773,"children":11774},{},[11775],{"type":291,"value":11776},"[Enter company – an external company is better here]",{"type":291,"value":11778},".\nA ",{"type":281,"tag":11280,"props":11780,"children":11781},{},[11782],{"type":291,"value":11783},"selection of representative pages and functions",{"type":291,"value":11785}," was examined for compliance\nwith the requirements of ",{"type":281,"tag":11280,"props":11787,"children":11788},{},[11789],{"type":291,"value":11421},{"type":291,"value":9323},{"type":281,"tag":11280,"props":11792,"children":11793},{},[11794],{"type":291,"value":11795},"EN 301 549",{"type":291,"value":11797},".\nNot all content or pages were individually tested.\nThe selection was based on usage frequency and central functionalities\nof our online offering.",{"type":281,"tag":530,"props":11799,"children":11801},{"id":11800},"feedback-and-contact",[11802],{"type":291,"value":11803},"Feedback and Contact",{"type":281,"tag":282,"props":11805,"children":11806},{},[11807,11809,11814],{"type":291,"value":11808},"Should you notice ",{"type":281,"tag":11280,"props":11810,"children":11811},{},[11812],{"type":291,"value":11813},"barriers",{"type":291,"value":11815}," when visiting our digital offerings,\nwe ask you to inform us.\nEvery hint helps us better understand existing weaknesses and improve them in a targeted manner.",{"type":281,"tag":282,"props":11817,"children":11818},{},[11819],{"type":281,"tag":11280,"props":11820,"children":11821},{},[11822],{"type":291,"value":11823},"Contact for accessibility feedback:",{"type":281,"tag":282,"props":11825,"children":11826},{},[11827,11832,11835,11840,11843,11848,11851,11856,11859],{"type":281,"tag":11370,"props":11828,"children":11829},{},[11830],{"type":291,"value":11831},"[Name or department]",{"type":281,"tag":1314,"props":11833,"children":11834},{},[],{"type":281,"tag":11370,"props":11836,"children":11837},{},[11838],{"type":291,"value":11839},"[Company]",{"type":281,"tag":1314,"props":11841,"children":11842},{},[],{"type":281,"tag":11370,"props":11844,"children":11845},{},[11846],{"type":291,"value":11847},"[Address, optional]",{"type":281,"tag":1314,"props":11849,"children":11850},{},[],{"type":281,"tag":11370,"props":11852,"children":11853},{},[11854],{"type":291,"value":11855},"[Email address]",{"type":281,"tag":1314,"props":11857,"children":11858},{},[],{"type":281,"tag":11370,"props":11860,"children":11861},{},[11862],{"type":291,"value":11863},"[Phone number, optional]",{"type":281,"tag":282,"props":11865,"children":11866},{},[11867,11869,11874,11876,11881,11883,11888],{"type":291,"value":11868},"We assure you that we will ",{"type":281,"tag":11280,"props":11870,"children":11871},{},[11872],{"type":291,"value":11873},"editorially and technically review",{"type":291,"value":11875}," incoming feedback as quickly as possible and, if possible, ",{"type":281,"tag":11280,"props":11877,"children":11878},{},[11879],{"type":291,"value":11880},"remedy",{"type":291,"value":11882}," it within a reasonable timeframe.\nShould a short-term technical solution not be possible, we will work with you to find ",{"type":281,"tag":11280,"props":11884,"children":11885},{},[11886],{"type":291,"value":11887},"alternative access routes or supporting measures",{"type":291,"value":11889}," to still enable you to use the service.",{"type":281,"tag":319,"props":11891,"children":11893},{"className":11892},[11364],[11894],{"type":281,"tag":282,"props":11895,"children":11896},{},[11897],{"type":281,"tag":11370,"props":11898,"children":11899},{},[11900],{"type":291,"value":11901},"optional",{"type":281,"tag":11500,"props":11903,"children":11905},{"className":11904},[11552,11553,11554,11555,11556,11557,11558],[11906],{"type":281,"tag":282,"props":11907,"children":11908},{},[11909],{"type":291,"value":11910},"The following part is important again, as the market surveillance authority must be named here\nand you should refer to the currently valid Terms and Conditions, which may close possible gaps in the\ndescription of the service or product.",{"type":281,"tag":11500,"props":11912,"children":11914},{"className":11913},[11503,11568],[11915],{"type":281,"tag":11500,"props":11916,"children":11918},{"className":11917},[11509],[11919,11925,11942,11961,11966,11977,11983,11988],{"type":281,"tag":530,"props":11920,"children":11922},{"id":11921},"additional-information",[11923],{"type":291,"value":11924},"Additional Information",{"type":281,"tag":282,"props":11926,"children":11927},{},[11928,11930,11935,11937],{"type":291,"value":11929},"Please note that the use of our digital services and all associated\nfunctions is additionally subject to our ",{"type":281,"tag":11280,"props":11931,"children":11932},{},[11933],{"type":291,"value":11934},"General Terms and Conditions (GTC)",{"type":291,"value":11936},".\nThese GTC regulate, among other things, contract conclusion, payment processing, and\ndelivery. In case of contradictions or deviations, the GTC in their\ncurrent version apply, insofar as they do not restrict or override accessibility requirements.\nAn accessible version of our GTC is available here: ",{"type":281,"tag":11370,"props":11938,"children":11939},{},[11940],{"type":291,"value":11941},"[Link to GTC]",{"type":281,"tag":282,"props":11943,"children":11944},{},[11945,11947,11952,11954,11959],{"type":291,"value":11946},"We understand accessibility not as a one-time measure, but as an\n",{"type":281,"tag":11280,"props":11948,"children":11949},{},[11950],{"type":291,"value":11951},"ongoing process",{"type":291,"value":11953},". Therefore, our content and systems are regularly reviewed\nand revised. In individual cases, this may temporarily lead to\n",{"type":281,"tag":11280,"props":11955,"children":11956},{},[11957],{"type":291,"value":11958},"limitations in accessibility",{"type":291,"value":11960},". We ask for your understanding.",{"type":281,"tag":282,"props":11962,"children":11963},{},[11964],{"type":291,"value":11965},"For further information on the German Accessibility Strengthening Act, we refer to\nthe responsible national enforcement agency:",{"type":281,"tag":282,"props":11967,"children":11968},{},[11969,11975],{"type":281,"tag":286,"props":11970,"children":11972},{"href":11971},"https://www.bundesfachstelle-barrierefreiheit.de",[11973],{"type":291,"value":11974},"German Federal Agency for Accessibility",{"type":291,"value":11976}," (Operated by: Knappschaft-Bahn-See)",{"type":281,"tag":1248,"props":11978,"children":11980},{"id":11979},"responsible-market-surveillance-authority",[11981],{"type":291,"value":11982},"Responsible Market Surveillance Authority",{"type":281,"tag":282,"props":11984,"children":11985},{},[11986],{"type":291,"value":11987},"Market Surveillance Authority of the States for Accessibility of Products and\nServices (MLBF) in Magdeburg, Saxony-Anhalt.",{"type":281,"tag":282,"props":11989,"children":11990},{},[11991,11996,11999,12001,12004,12006,12009,12011,12014,12017,12019,12022],{"type":281,"tag":11280,"props":11992,"children":11993},{},[11994],{"type":291,"value":11995},"MLBF (under establishment)",{"type":281,"tag":1314,"props":11997,"children":11998},{},[],{"type":291,"value":12000},"\nc/o Ministry of Labor, Social Affairs, Health and Equal Opportunities Saxony-Anhalt",{"type":281,"tag":1314,"props":12002,"children":12003},{},[],{"type":291,"value":12005},"\nP.O. Box 39 11 55",{"type":281,"tag":1314,"props":12007,"children":12008},{},[],{"type":291,"value":12010},"\n39135 Magdeburg",{"type":281,"tag":1314,"props":12012,"children":12013},{},[],{"type":281,"tag":1314,"props":12015,"children":12016},{},[],{"type":291,"value":12018},"\nPhone: 0391 567 6970",{"type":281,"tag":1314,"props":12020,"children":12021},{},[],{"type":291,"value":12023},"\nEmail: MLBF(at)ms.sachsen-anhalt.de.",{"type":281,"tag":11500,"props":12025,"children":12030},{"className":12026},[12027,12028,12029],"hint","hint--warning","mt-5",[12031],{"type":281,"tag":282,"props":12032,"children":12033},{},[12034,12039,12042,12044,12051,12053,12058],{"type":281,"tag":11280,"props":12035,"children":12036},{},[12037],{"type":291,"value":12038},"Note:",{"type":281,"tag":1314,"props":12040,"children":12041},{},[],{"type":291,"value":12043},"\nAccording to ",{"type":281,"tag":11370,"props":12045,"children":12046},{},[12047],{"type":281,"tag":286,"props":12048,"children":12049},{"href":11431},[12050],{"type":291,"value":11431},{"type":291,"value":12052}," §1 c,\n\"",{"type":281,"tag":11370,"props":12054,"children":12055},{},[12056],{"type":291,"value":12057},"a description of how the service fulfills the relevant accessibility requirements\nlisted in the regulation to be issued pursuant to §3 paragraph 2;",{"type":291,"value":12059},"\"\nshould be included – i.e., a precise description of how the service was designed to be accessible.",{"type":281,"tag":11500,"props":12061,"children":12065},{"className":12062},[12063,11553,11554,11555,11556,11557,11558,12064],"mt-0","pt-0",[12066,12072,12077],{"type":281,"tag":1248,"props":12067,"children":12069},{"id":12068},"example-of-a-description-of-concrete-measures",[12070],{"type":291,"value":12071},"Example of a Description of Concrete Measures",{"type":281,"tag":282,"props":12073,"children":12074},{},[12075],{"type":291,"value":12076},"Below is an example of concrete measures as we typically provide and implement\nas an agency for our clients in projects.",{"type":281,"tag":282,"props":12078,"children":12079},{},[12080],{"type":291,"value":12081},"These measures would need to be truthfully and individually adapted to your measures.",{"type":281,"tag":11500,"props":12083,"children":12086},{"className":12084},[11503,12085],"doc-sheet__border-bottom",[12087],{"type":281,"tag":11500,"props":12088,"children":12090},{"className":12089},[11509],[12091,12097,12102,12108,12113,12119,12124,12130,12135,12141,12146,12152,12157,12163,12168,12174,12192],{"type":281,"tag":530,"props":12092,"children":12094},{"id":12093},"concrete-implementation-of-accessibility-requirements",[12095],{"type":291,"value":12096},"Concrete Implementation of Accessibility Requirements",{"type":281,"tag":282,"props":12098,"children":12099},{},[12100],{"type":291,"value":12101},"To fulfill legal accessibility requirements, the following technical\nand design measures have been implemented:",{"type":281,"tag":1248,"props":12103,"children":12105},{"id":12104},"technical-structure-and-semantics",[12106],{"type":291,"value":12107},"Technical Structure and Semantics",{"type":281,"tag":282,"props":12109,"children":12110},{},[12111],{"type":291,"value":12112},"The HTML structures of our website correspond to the semantic purpose of the respective\ncontent and interaction elements. Additionally, ARIA markups were used to make complex\nfunctionalities and their status accessible to assistive technologies.",{"type":281,"tag":1248,"props":12114,"children":12116},{"id":12115},"content-design-and-editorial-measures",[12117],{"type":291,"value":12118},"Content Design and Editorial Measures",{"type":281,"tag":282,"props":12120,"children":12121},{},[12122],{"type":291,"value":12123},"Editorially responsible persons have been trained in the correct use of text structures\nand hierarchical heading levels. When creating content, attention is paid to\nclear, understandable language. Complex matters are presented in a structured manner\nand organized with subheadings. Link texts are meaningfully formulated and clearly\ndescribe the destination of the link. Lists and other structuring HTML elements are\nstrategically used to clarify content structure. Tables are provided with appropriate\nheadings and descriptions to make their content and structure understandable.",{"type":281,"tag":1248,"props":12125,"children":12127},{"id":12126},"visual-design-and-responsive-design",[12128],{"type":291,"value":12129},"Visual Design and Responsive Design",{"type":281,"tag":282,"props":12131,"children":12132},{},[12133],{"type":291,"value":12134},"In color design, attention was paid to high-contrast presentation according to\nWCAG Level AA. Information is not conveyed exclusively through visual\nproperties such as color, shape, or position, but supplemented by additional\ntextual or structural hints. The website is responsively designed\nand usable on various output devices. Text size can be adjusted using browser zoom\nto at least 200% without loss of functionality. Navigation and\ncontrol elements are consistently designed and positioned in comparable locations.",{"type":281,"tag":1248,"props":12136,"children":12138},{"id":12137},"text-alternatives-media-and-time-based-content",[12139],{"type":291,"value":12140},"Text Alternatives, Media and Time-based Content",{"type":281,"tag":282,"props":12142,"children":12143},{},[12144],{"type":291,"value":12145},"Provisions have been made for all images and graphics so that users can\ncreate meaningful alternative texts when creating content or mark pure\ndecorative graphics with empty alternative texts.\nVideo content, insofar as it is under our control, is provided with subtitles.\nTime-controlled displays or automatic notifications have been avoided.\nIf such elements are necessary for functional reasons, they can be paused and\ncontrolled by users.\nContent that might require attention does not blink or flash.",{"type":281,"tag":1248,"props":12147,"children":12149},{"id":12148},"navigation-and-operation",[12150],{"type":291,"value":12151},"Navigation and Operation",{"type":281,"tag":282,"props":12153,"children":12154},{},[12155],{"type":291,"value":12156},"The website is fully keyboard operable. The keyboard focus is always clearly\nvisible and follows a logical order corresponding to the page structure.\nUnnecessary focus movement within a page as well as unintended\nreset when reloading pages are avoided to prevent context and\norientation loss.",{"type":281,"tag":1248,"props":12158,"children":12160},{"id":12159},"forms-and-input",[12161],{"type":291,"value":12162},"Forms and Input",{"type":281,"tag":282,"props":12164,"children":12165},{},[12166],{"type":291,"value":12167},"In all forms, clear label assignments to the corresponding form and\ncontrol elements are provided.\nError and status messages are presented clearly and accessibly\nto facilitate operation and understanding of inputs.",{"type":281,"tag":1248,"props":12169,"children":12171},{"id":12170},"additional-measures",[12172],{"type":291,"value":12173},"Additional Measures",{"type":281,"tag":455,"props":12175,"children":12176},{},[12177,12182,12187],{"type":281,"tag":459,"props":12178,"children":12179},{},[12180],{"type":291,"value":12181},"Automatic page redirections without user interaction have been avoided.",{"type":281,"tag":459,"props":12183,"children":12184},{},[12185],{"type":291,"value":12186},"Click and touch targets have sufficient minimum size for easy operation.",{"type":281,"tag":459,"props":12188,"children":12189},{},[12190],{"type":291,"value":12191},"In linear navigation through assistive technologies, content follows a meaningful and understandable order.",{"type":281,"tag":282,"props":12193,"children":12194},{},[12195],{"type":291,"value":12196},"These measures ensure a high degree of compatibility with common assistive\ntechnologies and enable equivalent use of our digital services for\npeople with different abilities.",{"type":281,"tag":319,"props":12198,"children":12200},{"className":12199},[11364],[12201],{"type":281,"tag":282,"props":12202,"children":12203},{},[12204],{"type":281,"tag":11370,"props":12205,"children":12206},{},[12207],{"type":291,"value":11656},{"type":281,"tag":11500,"props":12209,"children":12212},{"className":12210},[12027,12211],"hint--info",[12213,12219,12230],{"type":281,"tag":530,"props":12214,"children":12216},{"id":12215},"possible-short-version",[12217],{"type":291,"value":12218},"Possible Short Version:",{"type":281,"tag":282,"props":12220,"children":12221},{},[12222,12224,12228],{"type":291,"value":12223},"We design our digital offerings according to the\n",{"type":281,"tag":11280,"props":12225,"children":12226},{},[12227],{"type":291,"value":11396},{"type":291,"value":12229}," and applicable standards\n(e.g., WCAG 2.1 AA) to be accessible and continuously expand this accessibility.",{"type":281,"tag":282,"props":12231,"children":12232},{},[12233,12234,12239,12241],{"type":291,"value":11696},{"type":281,"tag":11280,"props":12235,"children":12236},{},[12237],{"type":291,"value":12238},"temporary or technical limitations",{"type":291,"value":12240}," may occasionally occur.\nWe welcome feedback on barriers and strive for quick\nsolutions. ",{"type":281,"tag":11370,"props":12242,"children":12243},{},[12244],{"type":291,"value":12245},"[Here's the link to complete accessibility information](LINK)",{"type":281,"tag":11500,"props":12247,"children":12249},{"className":12248},[12027,12028],[12250,12262],{"type":281,"tag":282,"props":12251,"children":12252},{},[12253,12257,12260],{"type":281,"tag":11280,"props":12254,"children":12255},{},[12256],{"type":291,"value":12038},{"type":281,"tag":1314,"props":12258,"children":12259},{},[],{"type":291,"value":12261},"\nDo not incorporate the AS/IBE into the GTC, as this might influence other\n\"legal transactions.\"\nInstead, place an individual \"Accessibility\" link in the footer\nthat refers to the \"Accessibility Information\" as a standalone page.",{"type":281,"tag":10768,"props":12263,"children":12264},{},[12265],{"type":281,"tag":282,"props":12266,"children":12267},{},[12268,12269,12274],{"type":291,"value":5665},{"type":281,"tag":11370,"props":12270,"children":12271},{},[12272],{"type":291,"value":12273},"The service provider indicates in relation to their service within the meaning of\n§ 1 paragraph 3 in their General Terms and Conditions or in another\nclearly perceptible way how they fulfill the accessibility requirements of\nthe regulation to be issued pursuant to § 3 paragraph 2.",{"type":291,"value":5665},{"type":281,"tag":530,"props":12276,"children":12278},{"id":12277},"our-experience-with-legal-consultation-on-this-topic",[12279],{"type":291,"value":12280},"Our Experience with Legal Consultation on This Topic",{"type":281,"tag":282,"props":12282,"children":12283},{},[12284,12286,12291,12292,12297],{"type":291,"value":12285},"It should be noted that among the legal advisors we have had contact with over time on this topic, there has been some discourse regarding the implementation of the measures described in the law. The distinction between a ",{"type":281,"tag":11370,"props":12287,"children":12288},{},[12289],{"type":291,"value":12290},"narrow",{"type":291,"value":9323},{"type":281,"tag":11370,"props":12293,"children":12294},{},[12295],{"type":291,"value":12296},"broad",{"type":291,"value":12298}," interpretation of accessibility requirements is primarily the starting point for the required level of detail and depth of described measures.",{"type":281,"tag":282,"props":12300,"children":12301},{},[12302],{"type":291,"value":12303},"Many law firms dealing with digital accessibility recommend:",{"type":281,"tag":455,"props":12305,"children":12306},{},[12307,12331,12342,12365,12375],{"type":281,"tag":459,"props":12308,"children":12309},{},[12310,12315,12317,12322,12324,12329],{"type":281,"tag":11280,"props":12311,"children":12312},{},[12313],{"type":291,"value":12314},"Not integrating",{"type":291,"value":12316}," the AS ",{"type":281,"tag":11280,"props":12318,"children":12319},{},[12320],{"type":291,"value":12321},"into the GTC",{"type":291,"value":12323},", but maintaining it as a ",{"type":281,"tag":11280,"props":12325,"children":12326},{},[12327],{"type":291,"value":12328},"standalone, easily findable page",{"type":291,"value":12330}," – such as under /accessibility and then linking it in the website footer.",{"type":281,"tag":459,"props":12332,"children":12333},{},[12334,12335,12340],{"type":291,"value":10817},{"type":281,"tag":11280,"props":12336,"children":12337},{},[12338],{"type":291,"value":12339},"AS must explicitly refer to the GTC",{"type":291,"value":12341}," (e.g., to close explanatory gaps in business activities, etc.)",{"type":281,"tag":459,"props":12343,"children":12344},{},[12345,12350,12352,12357,12358,12363],{"type":281,"tag":11280,"props":12346,"children":12347},{},[12348],{"type":291,"value":12349},"Avoid legally binding assurances",{"type":291,"value":12351}," (",{"type":281,"tag":11370,"props":12353,"children":12354},{},[12355],{"type":291,"value":12356},"\"complete accessibility\"",{"type":291,"value":9822},{"type":281,"tag":11370,"props":12359,"children":12360},{},[12361],{"type":291,"value":12362},"\"guaranteed conformity\"",{"type":291,"value":12364},") if these cannot be fulfilled 100%",{"type":281,"tag":459,"props":12366,"children":12367},{},[12368,12373],{"type":281,"tag":11280,"props":12369,"children":12370},{},[12371],{"type":291,"value":12372},"Name a contact person for feedback",{"type":291,"value":12374}," – preferably with email address and optionally phone number",{"type":281,"tag":459,"props":12376,"children":12377},{},[12378,12383],{"type":281,"tag":11280,"props":12379,"children":12380},{},[12381],{"type":291,"value":12382},"Specifically:",{"type":291,"value":12384}," To avoid being caught in warning campaigns, the corresponding legal text should be adopted almost verbatim. This reduces the risk of being targeted for omissions in the statement during (semi-)automatic reviews (copy or cite BFSG Annex 3)",{"type":281,"tag":1248,"props":12386,"children":12388},{"id":12387},"a-possible-additional-formulation-for-improved-defense-against-warnings",[12389],{"type":291,"value":12390},"A Possible Additional Formulation for Improved Defense Against Warnings",{"type":281,"tag":11500,"props":12392,"children":12395},{"className":12393},[11503,12394],"doc-sheet__border-all",[12396],{"type":281,"tag":11500,"props":12397,"children":12399},{"className":12398},[11509],[12400,12406,12411,12454,12460,12465,12503,12542,12548,12553,12559,12564,12597],{"type":281,"tag":530,"props":12401,"children":12403},{"id":12402},"service-design-for-accessible-access",[12404],{"type":291,"value":12405},"Service Design for Accessible Access",{"type":281,"tag":282,"props":12407,"children":12408},{},[12409],{"type":291,"value":12410},"Our digital service has been designed to enable people with\nvarious limitations equivalent use.\nWe base this on the following principles:",{"type":281,"tag":455,"props":12412,"children":12413},{},[12414,12419,12424,12429,12434,12439,12444,12449],{"type":281,"tag":459,"props":12415,"children":12416},{},[12417],{"type":291,"value":12418},"High-contrast user interface design",{"type":281,"tag":459,"props":12420,"children":12421},{},[12422],{"type":291,"value":12423},"Providing information on multiple perception levels (text-based, auditory, visual)",{"type":281,"tag":459,"props":12425,"children":12426},{},[12427],{"type":291,"value":12428},"Alternative content for visual or auditory media",{"type":281,"tag":459,"props":12430,"children":12431},{},[12432],{"type":291,"value":12433},"Operation of all functions via keyboard",{"type":281,"tag":459,"props":12435,"children":12436},{},[12437],{"type":291,"value":12438},"Support for screen readers and comparable assistive technologies",{"type":281,"tag":459,"props":12440,"children":12441},{},[12442],{"type":291,"value":12443},"Avoiding time-critical interactions without accessible alternatives",{"type":281,"tag":459,"props":12445,"children":12446},{},[12447],{"type":291,"value":12448},"Using simple language and understandable content",{"type":281,"tag":459,"props":12450,"children":12451},{},[12452],{"type":291,"value":12453},"Intuitive navigation and logically structured content",{"type":281,"tag":1248,"props":12455,"children":12457},{"id":12456},"general-accessible-information-provision",[12458],{"type":291,"value":12459},"General Accessible Information Provision",{"type":281,"tag":282,"props":12461,"children":12462},{},[12463],{"type":291,"value":12464},"Information about our services is conveyed to users so that they:",{"type":281,"tag":455,"props":12466,"children":12467},{},[12468,12473,12478,12483,12488,12493,12498],{"type":281,"tag":459,"props":12469,"children":12470},{},[12471],{"type":291,"value":12472},"can be perceived through multiple user senses (e.g., visually and/or auditorily),",{"type":281,"tag":459,"props":12474,"children":12475},{},[12476],{"type":291,"value":12477},"are provided in an easily findable way for users,",{"type":281,"tag":459,"props":12479,"children":12480},{},[12481],{"type":291,"value":12482},"are written in an understandable manner,",{"type":281,"tag":459,"props":12484,"children":12485},{},[12486],{"type":291,"value":12487},"are available in a universal text format (font, size, contrasts, spacing) to enable conversions to assistive output forms,",{"type":281,"tag":459,"props":12489,"children":12490},{},[12491],{"type":291,"value":12492},"are designed with easily readable font size, appropriate typography, and sufficient contrast and spacing,",{"type":281,"tag":459,"props":12494,"children":12495},{},[12496],{"type":291,"value":12497},"provide alternative textual descriptions for non-text content,",{"type":281,"tag":459,"props":12499,"children":12500},{},[12501],{"type":291,"value":12502},"are digitally designed to function consistently, accessibly, intuitively, and stably.",{"type":281,"tag":282,"props":12504,"children":12505},{},[12506,12508,12513,12514,12519,12520,12525,12527,12532,12534,12540],{"type":291,"value":12507},"Both our web offerings, digital services, and mobile applications\nfollow these principles.\nThe design consistently follows the principles of\n",{"type":281,"tag":11280,"props":12509,"children":12510},{},[12511],{"type":291,"value":12512},"Perceivability",{"type":291,"value":9822},{"type":281,"tag":11280,"props":12515,"children":12516},{},[12517],{"type":291,"value":12518},"Operability",{"type":291,"value":9822},{"type":281,"tag":11280,"props":12521,"children":12522},{},[12523],{"type":291,"value":12524},"Understandability",{"type":291,"value":12526},", and ",{"type":281,"tag":11280,"props":12528,"children":12529},{},[12530],{"type":291,"value":12531},"Robustness",{"type":291,"value":12533},"\n(according to ",{"type":281,"tag":286,"props":12535,"children":12537},{"href":12536},"https://www.barrierefreiheit-dienstekonsolidierung.bund.de/Webs/PB/DE/gesetze-und-richtlinien/wcag/wcag-artikel.html",[12538],{"type":291,"value":12539},"WCAG criteria",{"type":291,"value":12541},").",{"type":281,"tag":1248,"props":12543,"children":12545},{"id":12544},"accessibility-of-supporting-services",[12546],{"type":291,"value":12547},"Accessibility of Supporting Services",{"type":281,"tag":282,"props":12549,"children":12550},{},[12551],{"type":291,"value":12552},"When additional support services such as support hotlines, training offerings, or\ntechnical consulting are provided, we ensure that these services also\nmake accessibility information and compatibility accessible through accessible means.",{"type":281,"tag":1248,"props":12554,"children":12556},{"id":12555},"functional-requirements-for-special-limitations",[12557],{"type":291,"value":12558},"Functional Requirements for Special Limitations",{"type":281,"tag":282,"props":12560,"children":12561},{},[12562],{"type":291,"value":12563},"Our services consider the following accessible interaction forms\nfor users:",{"type":281,"tag":455,"props":12565,"children":12566},{},[12567,12572,12577,12582,12587,12592],{"type":281,"tag":459,"props":12568,"children":12569},{},[12570],{"type":291,"value":12571},"For visual limitations: at least one option without visual elements and one that functions independently of color distinction.",{"type":281,"tag":459,"props":12573,"children":12574},{},[12575],{"type":291,"value":12576},"For people with hearing limitations: at least one usage option without sound and one with adjustable audio functions.",{"type":281,"tag":459,"props":12578,"children":12579},{},[12580],{"type":291,"value":12581},"For vocally limited users: at least one operating variant without voice input.",{"type":281,"tag":459,"props":12583,"children":12584},{},[12585],{"type":291,"value":12586},"For motor-limited users: at least one operating form without complex movement sequences or muscle strength, as well as an option for limited reach.",{"type":281,"tag":459,"props":12588,"children":12589},{},[12590],{"type":291,"value":12591},"For people with cognitive limitations: user-friendly structures, reduced complexity where possible, and supportive hints.",{"type":281,"tag":459,"props":12593,"children":12594},{},[12595],{"type":291,"value":12596},"For all accessibility functions: User privacy is maintained.",{"type":281,"tag":282,"props":12598,"children":12599},{},[12600,12602,12606],{"type":291,"value":12601},"These measures are oriented toward the requirements of the\n",{"type":281,"tag":11280,"props":12603,"children":12604},{},[12605],{"type":291,"value":11396},{"type":291,"value":12607}," and have been integrated into our technical and\ndesign processes to ensure the most comprehensive accessibility possible.",{"type":281,"tag":530,"props":12609,"children":12611},{"id":12610},"what-are-the-consequences-without-an-as",[12612],{"type":291,"value":12613},"What Are the Consequences Without an AS?",{"type":281,"tag":282,"props":12615,"children":12616},{},[12617,12619,12628],{"type":291,"value":12618},"Without a valid and verifiable statement, according to ",{"type":281,"tag":286,"props":12620,"children":12622},{"href":12621},"https://bfsg-gesetz.de/37-bfsg/",[12623],{"type":281,"tag":11280,"props":12624,"children":12625},{},[12626],{"type":291,"value":12627},"§ 37 BFSG",{"type":291,"value":12629},", the following can happen:",{"type":281,"tag":455,"props":12631,"children":12632},{},[12633,12638,12643,12648],{"type":281,"tag":459,"props":12634,"children":12635},{},[12636],{"type":291,"value":12637},"Operating or distribution ban (of the respective services or products)",{"type":281,"tag":459,"props":12639,"children":12640},{},[12641],{"type":291,"value":12642},"Fines up to 100,000 euros (depending on the violation)",{"type":281,"tag":459,"props":12644,"children":12645},{},[12646],{"type":291,"value":12647},"Formal objection by market surveillance",{"type":281,"tag":459,"props":12649,"children":12650},{},[12651],{"type":291,"value":12652},"Warnings from competitors or consumer organizations",{"type":281,"tag":282,"props":12654,"children":12655},{},[12656,12658,12666],{"type":291,"value":12657},"This is particularly relevant\n",{"type":281,"tag":11280,"props":12659,"children":12660},{},[12661],{"type":281,"tag":11370,"props":12662,"children":12663},{},[12664],{"type":291,"value":12665},"because any institution, company, or natural person can alert inspection bodies to a violation of the BFSG",{"type":291,"value":12667},". Thus, it can be assumed\nthat at least your competition will pay close attention to this!",{"type":281,"tag":530,"props":12669,"children":12671},{"id":12670},"conclusion-clarity-protects-against-warnings",[12672],{"type":291,"value":12673},"Conclusion - Clarity Protects Against Warnings",{"type":281,"tag":282,"props":12675,"children":12676},{},[12677,12678,12682],{"type":291,"value":10817},{"type":281,"tag":11280,"props":12679,"children":12680},{},[12681],{"type":291,"value":11490},{"type":291,"value":12683}," is only a small part of your digital service but with great impact.\nThose who take it seriously and individually tailor it to their own service show not only legal compliance,\nbut also respect toward all users. It also protects against legal pitfalls and economic damage.",{"type":281,"tag":282,"props":12685,"children":12686},{},[12687],{"type":291,"value":12688},"If you need support in creating or formulating one, please contact us.\nWe help create accessible web applications and show how you can meaningfully\nimplement legal requirements.",{"type":281,"tag":12690,"props":12691,"children":12693},"h4",{"id":12692},"legal-notice",[12694],{"type":291,"value":12695},"Legal Notice",{"type":281,"tag":282,"props":12697,"children":12698},{},[12699,12701,12709,12710,12715,12717,12722,12723,12728,12730,12735],{"type":291,"value":12700},"This blog post ",{"type":281,"tag":11280,"props":12702,"children":12703},{},[12704],{"type":281,"tag":11370,"props":12705,"children":12706},{},[12707],{"type":291,"value":12708},"does not constitute legal advice",{"type":291,"value":9323},{"type":281,"tag":11280,"props":12711,"children":12712},{},[12713],{"type":291,"value":12714},"does not replace legal review of your accessibility statement",{"type":291,"value":12716},". The contained formulations and hints have been carefully researched, but make ",{"type":281,"tag":11280,"props":12718,"children":12719},{},[12720],{"type":291,"value":12721},"no claim to completeness",{"type":291,"value":10825},{"type":281,"tag":11280,"props":12724,"children":12725},{},[12726],{"type":291,"value":12727},"legal binding",{"type":291,"value":12729},". For actual implementation according to ",{"type":281,"tag":11280,"props":12731,"children":12732},{},[12733],{"type":291,"value":12734},"BFSG",{"type":291,"value":12736}," and applicable regulations, legal review in individual cases is recommended.",{"type":281,"tag":12690,"props":12738,"children":12740},{"id":12739},"note-on-creating-this-post",[12741],{"type":291,"value":12742},"Note on Creating This Post",{"type":281,"tag":282,"props":12744,"children":12745},{},[12746],{"type":291,"value":12747},"This post was also created and translated with the help of AI OpenAI GPT-4 (2024-06, Model: GPT-4o). The basis was editorial research, personal experiences, legal sources, and a company template. Final editing and professional approval were done by the article author and accessibility officer Dr.-Ing. Jens Bornschein.",{"title":8,"searchDepth":338,"depth":338,"links":12749},[12750,12751,12752,12755,12756,12759,12760],{"id":11272,"depth":338,"text":11275},{"id":11383,"depth":338,"text":11386},{"id":11495,"depth":338,"text":11498,"children":12753},[12754],{"id":12068,"depth":351,"text":12071},{"id":12215,"depth":338,"text":12218},{"id":12277,"depth":338,"text":12280,"children":12757},[12758],{"id":12387,"depth":351,"text":12390},{"id":12610,"depth":338,"text":12613},{"id":12670,"depth":338,"text":12673},{"_path":99,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":100,"description":101,"author":11,"image":12,"releaseDate":102,"blogCategories":12762,"articleTags":12763,"tags":12764,"body":12765,"_type":20,"_id":107,"_source":22,"_file":108,"_stem":109,"_extension":25},[15,104],[16],[19],{"type":278,"children":12766,"toc":15663},[12767,12771,12777,12787,13038,13043,13049,13054,13059,13064,13163,13169,13174,13413,13419,13424,13442,13448,13464,13791,13796,13859,13865,13880,13904,14276,14280,14316,14319,14327,14330,14333,14339,14350,14360,14373,14376,14383,14777,14781,14806,14809,14812,14822,14828,15184,15188,15201,15204,15209,15639,15643,15659],{"type":281,"tag":1499,"props":12768,"children":12770},{"alt":8,"aspect-ratio":1501,"height":1502,"object-fit":1503,"src":12769},"/blog/gitlab-traefik.png",[],{"type":281,"tag":530,"props":12772,"children":12774},{"id":12773},"the-simplest-way-to-install-gitlab",[12775],{"type":291,"value":12776},"The simplest way to install GitLab",{"type":281,"tag":282,"props":12778,"children":12779},{},[12780,12782],{"type":291,"value":12781},"GitLab provides official instructions to install it using Docker and Docker Compose. You can find it in ",{"type":281,"tag":286,"props":12783,"children":12785},{"href":12784},"https://docs.gitlab.com/install/docker/installation/#install-gitlab-by-using-docker-compose",[12786],{"type":291,"value":9406},{"type":281,"tag":301,"props":12788,"children":12791},{"className":312,"code":12789,"filename":12790,"language":311,"meta":8,"style":8},"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",[12792],{"type":281,"tag":315,"props":12793,"children":12794},{"__ignoreMap":8},[12795,12806,12818,12834,12850,12865,12882,12893,12910,12918,12926,12938,12950,12962,12974,12985,12997,13009,13021],{"type":281,"tag":319,"props":12796,"children":12797},{"class":321,"line":322},[12798,12802],{"type":281,"tag":319,"props":12799,"children":12800},{"style":326},[12801],{"type":291,"value":329},{"type":281,"tag":319,"props":12803,"children":12804},{"style":332},[12805],{"type":291,"value":335},{"type":281,"tag":319,"props":12807,"children":12808},{"class":321,"line":338},[12809,12814],{"type":281,"tag":319,"props":12810,"children":12811},{"style":326},[12812],{"type":291,"value":12813},"  gitlab",{"type":281,"tag":319,"props":12815,"children":12816},{"style":332},[12817],{"type":291,"value":335},{"type":281,"tag":319,"props":12819,"children":12820},{"class":321,"line":351},[12821,12825,12829],{"type":281,"tag":319,"props":12822,"children":12823},{"style":326},[12824],{"type":291,"value":357},{"type":281,"tag":319,"props":12826,"children":12827},{"style":332},[12828],{"type":291,"value":362},{"type":281,"tag":319,"props":12830,"children":12831},{"style":365},[12832],{"type":291,"value":12833},"gitlab/gitlab-ee:\u003Cversion>-ce.0\n",{"type":281,"tag":319,"props":12835,"children":12836},{"class":321,"line":371},[12837,12841,12845],{"type":281,"tag":319,"props":12838,"children":12839},{"style":326},[12840],{"type":291,"value":911},{"type":281,"tag":319,"props":12842,"children":12843},{"style":332},[12844],{"type":291,"value":362},{"type":281,"tag":319,"props":12846,"children":12847},{"style":365},[12848],{"type":291,"value":12849},"gitlab\n",{"type":281,"tag":319,"props":12851,"children":12852},{"class":321,"line":306},[12853,12857,12861],{"type":281,"tag":319,"props":12854,"children":12855},{"style":326},[12856],{"type":291,"value":928},{"type":281,"tag":319,"props":12858,"children":12859},{"style":332},[12860],{"type":291,"value":362},{"type":281,"tag":319,"props":12862,"children":12863},{"style":365},[12864],{"type":291,"value":937},{"type":281,"tag":319,"props":12866,"children":12867},{"class":321,"line":307},[12868,12873,12877],{"type":281,"tag":319,"props":12869,"children":12870},{"style":326},[12871],{"type":291,"value":12872},"    hostname",{"type":281,"tag":319,"props":12874,"children":12875},{"style":332},[12876],{"type":291,"value":362},{"type":281,"tag":319,"props":12878,"children":12879},{"style":365},[12880],{"type":291,"value":12881},"'\u003Cgitlab.example.com>'\n",{"type":281,"tag":319,"props":12883,"children":12884},{"class":321,"line":308},[12885,12889],{"type":281,"tag":319,"props":12886,"children":12887},{"style":326},[12888],{"type":291,"value":9689},{"type":281,"tag":319,"props":12890,"children":12891},{"style":332},[12892],{"type":291,"value":335},{"type":281,"tag":319,"props":12894,"children":12895},{"class":321,"line":309},[12896,12901,12905],{"type":281,"tag":319,"props":12897,"children":12898},{"style":326},[12899],{"type":291,"value":12900},"      GITLAB_OMNIBUS_CONFIG",{"type":281,"tag":319,"props":12902,"children":12903},{"style":332},[12904],{"type":291,"value":362},{"type":281,"tag":319,"props":12906,"children":12907},{"style":7965},[12908],{"type":291,"value":12909},"|\n",{"type":281,"tag":319,"props":12911,"children":12912},{"class":321,"line":310},[12913],{"type":281,"tag":319,"props":12914,"children":12915},{"style":365},[12916],{"type":291,"value":12917},"        # Add any other gitlab.rb configuration here, each on its own line\n",{"type":281,"tag":319,"props":12919,"children":12920},{"class":321,"line":973},[12921],{"type":281,"tag":319,"props":12922,"children":12923},{"style":365},[12924],{"type":291,"value":12925},"        external_url 'https://\u003Cgitlab.example.com>'\n",{"type":281,"tag":319,"props":12927,"children":12928},{"class":321,"line":986},[12929,12934],{"type":281,"tag":319,"props":12930,"children":12931},{"style":326},[12932],{"type":291,"value":12933},"    ports",{"type":281,"tag":319,"props":12935,"children":12936},{"style":332},[12937],{"type":291,"value":335},{"type":281,"tag":319,"props":12939,"children":12940},{"class":321,"line":999},[12941,12945],{"type":281,"tag":319,"props":12942,"children":12943},{"style":332},[12944],{"type":291,"value":391},{"type":281,"tag":319,"props":12946,"children":12947},{"style":365},[12948],{"type":291,"value":12949},"'80:80'\n",{"type":281,"tag":319,"props":12951,"children":12952},{"class":321,"line":1012},[12953,12957],{"type":281,"tag":319,"props":12954,"children":12955},{"style":332},[12956],{"type":291,"value":391},{"type":281,"tag":319,"props":12958,"children":12959},{"style":365},[12960],{"type":291,"value":12961},"'443:443'\n",{"type":281,"tag":319,"props":12963,"children":12964},{"class":321,"line":1025},[12965,12969],{"type":281,"tag":319,"props":12966,"children":12967},{"style":332},[12968],{"type":291,"value":391},{"type":281,"tag":319,"props":12970,"children":12971},{"style":365},[12972],{"type":291,"value":12973},"'22:22'\n",{"type":281,"tag":319,"props":12975,"children":12976},{"class":321,"line":1038},[12977,12981],{"type":281,"tag":319,"props":12978,"children":12979},{"style":326},[12980],{"type":291,"value":1175},{"type":281,"tag":319,"props":12982,"children":12983},{"style":332},[12984],{"type":291,"value":335},{"type":281,"tag":319,"props":12986,"children":12987},{"class":321,"line":1048},[12988,12992],{"type":281,"tag":319,"props":12989,"children":12990},{"style":332},[12991],{"type":291,"value":391},{"type":281,"tag":319,"props":12993,"children":12994},{"style":365},[12995],{"type":291,"value":12996},"'$GITLAB_HOME/config:/etc/gitlab'\n",{"type":281,"tag":319,"props":12998,"children":12999},{"class":321,"line":1061},[13000,13004],{"type":281,"tag":319,"props":13001,"children":13002},{"style":332},[13003],{"type":291,"value":391},{"type":281,"tag":319,"props":13005,"children":13006},{"style":365},[13007],{"type":291,"value":13008},"'$GITLAB_HOME/logs:/var/log/gitlab'\n",{"type":281,"tag":319,"props":13010,"children":13011},{"class":321,"line":1074},[13012,13016],{"type":281,"tag":319,"props":13013,"children":13014},{"style":332},[13015],{"type":291,"value":391},{"type":281,"tag":319,"props":13017,"children":13018},{"style":365},[13019],{"type":291,"value":13020},"'$GITLAB_HOME/data:/var/opt/gitlab'\n",{"type":281,"tag":319,"props":13022,"children":13023},{"class":321,"line":1083},[13024,13029,13033],{"type":281,"tag":319,"props":13025,"children":13026},{"style":326},[13027],{"type":291,"value":13028},"    shm_size",{"type":281,"tag":319,"props":13030,"children":13031},{"style":332},[13032],{"type":291,"value":362},{"type":281,"tag":319,"props":13034,"children":13035},{"style":365},[13036],{"type":291,"value":13037},"'256m'\n",{"type":281,"tag":282,"props":13039,"children":13040},{},[13041],{"type":291,"value":13042},"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":281,"tag":530,"props":13044,"children":13046},{"id":13045},"integrating-gitlab-alongside-other-deployments",[13047],{"type":291,"value":13048},"Integrating GitLab alongside other deployments",{"type":281,"tag":282,"props":13050,"children":13051},{},[13052],{"type":291,"value":13053},"What if you can't or don't want to install GitLab on a dedicated server?",{"type":281,"tag":282,"props":13055,"children":13056},{},[13057],{"type":291,"value":13058},"Maybe you just want a single server for all you services?",{"type":281,"tag":282,"props":13060,"children":13061},{},[13062],{"type":291,"value":13063},"This is an example structure how you could organize your deployments:",{"type":281,"tag":301,"props":13065,"children":13067},{"className":1597,"code":13066,"language":1596,"meta":8,"style":8},".\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",[13068],{"type":281,"tag":315,"props":13069,"children":13070},{"__ignoreMap":8},[13071,13078,13095,13112,13129,13146],{"type":281,"tag":319,"props":13072,"children":13073},{"class":321,"line":322},[13074],{"type":281,"tag":319,"props":13075,"children":13076},{"style":9454},[13077],{"type":291,"value":9457},{"type":281,"tag":319,"props":13079,"children":13080},{"class":321,"line":338},[13081,13085,13090],{"type":281,"tag":319,"props":13082,"children":13083},{"style":1607},[13084],{"type":291,"value":9479},{"type":281,"tag":319,"props":13086,"children":13087},{"style":365},[13088],{"type":291,"value":13089}," gitlab/",{"type":281,"tag":319,"props":13091,"children":13092},{"style":9468},[13093],{"type":291,"value":13094},"                # GitLab service stack\n",{"type":281,"tag":319,"props":13096,"children":13097},{"class":321,"line":351},[13098,13102,13107],{"type":281,"tag":319,"props":13099,"children":13100},{"style":1607},[13101],{"type":291,"value":9479},{"type":281,"tag":319,"props":13103,"children":13104},{"style":365},[13105],{"type":291,"value":13106}," gitlab-runner/",{"type":281,"tag":319,"props":13108,"children":13109},{"style":9468},[13110],{"type":291,"value":13111},"         # GitLab Runner for CI/CD\n",{"type":281,"tag":319,"props":13113,"children":13114},{"class":321,"line":371},[13115,13119,13124],{"type":281,"tag":319,"props":13116,"children":13117},{"style":1607},[13118],{"type":291,"value":9479},{"type":281,"tag":319,"props":13120,"children":13121},{"style":365},[13122],{"type":291,"value":13123}," mattermost/",{"type":281,"tag":319,"props":13125,"children":13126},{"style":9468},[13127],{"type":291,"value":13128},"            # Mattermost team collaboration\n",{"type":281,"tag":319,"props":13130,"children":13131},{"class":321,"line":306},[13132,13136,13141],{"type":281,"tag":319,"props":13133,"children":13134},{"style":1607},[13135],{"type":291,"value":9479},{"type":281,"tag":319,"props":13137,"children":13138},{"style":365},[13139],{"type":291,"value":13140}," nextcloud/",{"type":281,"tag":319,"props":13142,"children":13143},{"style":9468},[13144],{"type":291,"value":13145},"             # Nextcloud file hosting and collaboration\n",{"type":281,"tag":319,"props":13147,"children":13148},{"class":321,"line":307},[13149,13153,13158],{"type":281,"tag":319,"props":13150,"children":13151},{"style":1607},[13152],{"type":291,"value":9532},{"type":281,"tag":319,"props":13154,"children":13155},{"style":365},[13156],{"type":291,"value":13157}," traefik/",{"type":281,"tag":319,"props":13159,"children":13160},{"style":9468},[13161],{"type":291,"value":13162},"               # Traefik reverse proxy configuration\n",{"type":281,"tag":1248,"props":13164,"children":13166},{"id":13165},"using-a-dedicated-ip",[13167],{"type":291,"value":13168},"Using a dedicated IP",{"type":281,"tag":282,"props":13170,"children":13171},{},[13172],{"type":291,"value":13173},"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":281,"tag":301,"props":13175,"children":13178},{"className":312,"code":13176,"filename":12790,"highlights":13177,"language":311,"meta":8,"style":8},"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",[999,1012,1025],[13179],{"type":281,"tag":315,"props":13180,"children":13181},{"__ignoreMap":8},[13182,13193,13204,13219,13234,13249,13264,13275,13290,13297,13304,13315,13328,13341,13354,13365,13376,13387,13398],{"type":281,"tag":319,"props":13183,"children":13184},{"class":321,"line":322},[13185,13189],{"type":281,"tag":319,"props":13186,"children":13187},{"style":326},[13188],{"type":291,"value":329},{"type":281,"tag":319,"props":13190,"children":13191},{"style":332},[13192],{"type":291,"value":335},{"type":281,"tag":319,"props":13194,"children":13195},{"class":321,"line":338},[13196,13200],{"type":281,"tag":319,"props":13197,"children":13198},{"style":326},[13199],{"type":291,"value":12813},{"type":281,"tag":319,"props":13201,"children":13202},{"style":332},[13203],{"type":291,"value":335},{"type":281,"tag":319,"props":13205,"children":13206},{"class":321,"line":351},[13207,13211,13215],{"type":281,"tag":319,"props":13208,"children":13209},{"style":326},[13210],{"type":291,"value":357},{"type":281,"tag":319,"props":13212,"children":13213},{"style":332},[13214],{"type":291,"value":362},{"type":281,"tag":319,"props":13216,"children":13217},{"style":365},[13218],{"type":291,"value":12833},{"type":281,"tag":319,"props":13220,"children":13221},{"class":321,"line":371},[13222,13226,13230],{"type":281,"tag":319,"props":13223,"children":13224},{"style":326},[13225],{"type":291,"value":911},{"type":281,"tag":319,"props":13227,"children":13228},{"style":332},[13229],{"type":291,"value":362},{"type":281,"tag":319,"props":13231,"children":13232},{"style":365},[13233],{"type":291,"value":12849},{"type":281,"tag":319,"props":13235,"children":13236},{"class":321,"line":306},[13237,13241,13245],{"type":281,"tag":319,"props":13238,"children":13239},{"style":326},[13240],{"type":291,"value":928},{"type":281,"tag":319,"props":13242,"children":13243},{"style":332},[13244],{"type":291,"value":362},{"type":281,"tag":319,"props":13246,"children":13247},{"style":365},[13248],{"type":291,"value":937},{"type":281,"tag":319,"props":13250,"children":13251},{"class":321,"line":307},[13252,13256,13260],{"type":281,"tag":319,"props":13253,"children":13254},{"style":326},[13255],{"type":291,"value":12872},{"type":281,"tag":319,"props":13257,"children":13258},{"style":332},[13259],{"type":291,"value":362},{"type":281,"tag":319,"props":13261,"children":13262},{"style":365},[13263],{"type":291,"value":12881},{"type":281,"tag":319,"props":13265,"children":13266},{"class":321,"line":308},[13267,13271],{"type":281,"tag":319,"props":13268,"children":13269},{"style":326},[13270],{"type":291,"value":9689},{"type":281,"tag":319,"props":13272,"children":13273},{"style":332},[13274],{"type":291,"value":335},{"type":281,"tag":319,"props":13276,"children":13277},{"class":321,"line":309},[13278,13282,13286],{"type":281,"tag":319,"props":13279,"children":13280},{"style":326},[13281],{"type":291,"value":12900},{"type":281,"tag":319,"props":13283,"children":13284},{"style":332},[13285],{"type":291,"value":362},{"type":281,"tag":319,"props":13287,"children":13288},{"style":7965},[13289],{"type":291,"value":12909},{"type":281,"tag":319,"props":13291,"children":13292},{"class":321,"line":310},[13293],{"type":281,"tag":319,"props":13294,"children":13295},{"style":365},[13296],{"type":291,"value":12917},{"type":281,"tag":319,"props":13298,"children":13299},{"class":321,"line":973},[13300],{"type":281,"tag":319,"props":13301,"children":13302},{"style":365},[13303],{"type":291,"value":12925},{"type":281,"tag":319,"props":13305,"children":13306},{"class":321,"line":986},[13307,13311],{"type":281,"tag":319,"props":13308,"children":13309},{"style":326},[13310],{"type":291,"value":12933},{"type":281,"tag":319,"props":13312,"children":13313},{"style":332},[13314],{"type":291,"value":335},{"type":281,"tag":319,"props":13316,"children":13318},{"class":13317,"line":999},[321,385],[13319,13323],{"type":281,"tag":319,"props":13320,"children":13321},{"style":332},[13322],{"type":291,"value":391},{"type":281,"tag":319,"props":13324,"children":13325},{"style":365},[13326],{"type":291,"value":13327},"'192.168.0.1:80:80'\n",{"type":281,"tag":319,"props":13329,"children":13331},{"class":13330,"line":1012},[321,385],[13332,13336],{"type":281,"tag":319,"props":13333,"children":13334},{"style":332},[13335],{"type":291,"value":391},{"type":281,"tag":319,"props":13337,"children":13338},{"style":365},[13339],{"type":291,"value":13340},"'192.168.0.1:443:443'\n",{"type":281,"tag":319,"props":13342,"children":13344},{"class":13343,"line":1025},[321,385],[13345,13349],{"type":281,"tag":319,"props":13346,"children":13347},{"style":332},[13348],{"type":291,"value":391},{"type":281,"tag":319,"props":13350,"children":13351},{"style":365},[13352],{"type":291,"value":13353},"'192.168.0.1:22:22'\n",{"type":281,"tag":319,"props":13355,"children":13356},{"class":321,"line":1038},[13357,13361],{"type":281,"tag":319,"props":13358,"children":13359},{"style":326},[13360],{"type":291,"value":1175},{"type":281,"tag":319,"props":13362,"children":13363},{"style":332},[13364],{"type":291,"value":335},{"type":281,"tag":319,"props":13366,"children":13367},{"class":321,"line":1048},[13368,13372],{"type":281,"tag":319,"props":13369,"children":13370},{"style":332},[13371],{"type":291,"value":391},{"type":281,"tag":319,"props":13373,"children":13374},{"style":365},[13375],{"type":291,"value":12996},{"type":281,"tag":319,"props":13377,"children":13378},{"class":321,"line":1061},[13379,13383],{"type":281,"tag":319,"props":13380,"children":13381},{"style":332},[13382],{"type":291,"value":391},{"type":281,"tag":319,"props":13384,"children":13385},{"style":365},[13386],{"type":291,"value":13008},{"type":281,"tag":319,"props":13388,"children":13389},{"class":321,"line":1074},[13390,13394],{"type":281,"tag":319,"props":13391,"children":13392},{"style":332},[13393],{"type":291,"value":391},{"type":281,"tag":319,"props":13395,"children":13396},{"style":365},[13397],{"type":291,"value":13020},{"type":281,"tag":319,"props":13399,"children":13400},{"class":321,"line":1083},[13401,13405,13409],{"type":281,"tag":319,"props":13402,"children":13403},{"style":326},[13404],{"type":291,"value":13028},{"type":281,"tag":319,"props":13406,"children":13407},{"style":332},[13408],{"type":291,"value":362},{"type":281,"tag":319,"props":13410,"children":13411},{"style":365},[13412],{"type":291,"value":13037},{"type":281,"tag":1248,"props":13414,"children":13416},{"id":13415},"using-traefik-as-a-reverse-proxy",[13417],{"type":291,"value":13418},"Using Traefik as a reverse proxy",{"type":281,"tag":282,"props":13420,"children":13421},{},[13422],{"type":291,"value":13423},"In this case I assume that you:",{"type":281,"tag":455,"props":13425,"children":13426},{},[13427,13432,13437],{"type":281,"tag":459,"props":13428,"children":13429},{},[13430],{"type":291,"value":13431},"can't or don't want to assign a dedicated IP for GitLab",{"type":281,"tag":459,"props":13433,"children":13434},{},[13435],{"type":291,"value":13436},"can't or don't want to change you default ssh port",{"type":281,"tag":459,"props":13438,"children":13439},{},[13440],{"type":291,"value":13441},"want to use Traefik as a reverse proxy",{"type":281,"tag":12690,"props":13443,"children":13445},{"id":13444},"the-traefik-deployment",[13446],{"type":291,"value":13447},"The Traefik deployment",{"type":281,"tag":282,"props":13449,"children":13450},{},[13451,13453,13462],{"type":291,"value":13452},"Remember to replace ",{"type":281,"tag":11280,"props":13454,"children":13455},{},[13456],{"type":281,"tag":315,"props":13457,"children":13459},{"className":13458},[],[13460],{"type":291,"value":13461},"\u003Cinfo@example.com>",{"type":291,"value":13463}," with your own email.",{"type":281,"tag":301,"props":13465,"children":13467},{"className":312,"code":13466,"filename":843,"language":311,"meta":8,"style":8},"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",[13468],{"type":281,"tag":315,"props":13469,"children":13470},{"__ignoreMap":8},[13471,13482,13493,13500,13511,13522,13537,13552,13567,13582,13593,13604,13616,13627,13639,13646,13657,13668,13679,13686,13697,13708,13715,13727,13739,13746,13758,13769,13780],{"type":281,"tag":319,"props":13472,"children":13473},{"class":321,"line":322},[13474,13478],{"type":281,"tag":319,"props":13475,"children":13476},{"style":326},[13477],{"type":291,"value":856},{"type":281,"tag":319,"props":13479,"children":13480},{"style":332},[13481],{"type":291,"value":335},{"type":281,"tag":319,"props":13483,"children":13484},{"class":321,"line":338},[13485,13489],{"type":281,"tag":319,"props":13486,"children":13487},{"style":326},[13488],{"type":291,"value":868},{"type":281,"tag":319,"props":13490,"children":13491},{"style":332},[13492],{"type":291,"value":335},{"type":281,"tag":319,"props":13494,"children":13495},{"class":321,"line":351},[13496],{"type":281,"tag":319,"props":13497,"children":13498},{"emptyLinePlaceholder":1042},[13499],{"type":291,"value":1045},{"type":281,"tag":319,"props":13501,"children":13502},{"class":321,"line":371},[13503,13507],{"type":281,"tag":319,"props":13504,"children":13505},{"style":326},[13506],{"type":291,"value":329},{"type":281,"tag":319,"props":13508,"children":13509},{"style":332},[13510],{"type":291,"value":335},{"type":281,"tag":319,"props":13512,"children":13513},{"class":321,"line":306},[13514,13518],{"type":281,"tag":319,"props":13515,"children":13516},{"style":326},[13517],{"type":291,"value":899},{"type":281,"tag":319,"props":13519,"children":13520},{"style":332},[13521],{"type":291,"value":335},{"type":281,"tag":319,"props":13523,"children":13524},{"class":321,"line":307},[13525,13529,13533],{"type":281,"tag":319,"props":13526,"children":13527},{"style":326},[13528],{"type":291,"value":357},{"type":281,"tag":319,"props":13530,"children":13531},{"style":332},[13532],{"type":291,"value":362},{"type":281,"tag":319,"props":13534,"children":13535},{"style":365},[13536],{"type":291,"value":953},{"type":281,"tag":319,"props":13538,"children":13539},{"class":321,"line":308},[13540,13544,13548],{"type":281,"tag":319,"props":13541,"children":13542},{"style":326},[13543],{"type":291,"value":911},{"type":281,"tag":319,"props":13545,"children":13546},{"style":332},[13547],{"type":291,"value":362},{"type":281,"tag":319,"props":13549,"children":13550},{"style":365},[13551],{"type":291,"value":920},{"type":281,"tag":319,"props":13553,"children":13554},{"class":321,"line":309},[13555,13559,13563],{"type":281,"tag":319,"props":13556,"children":13557},{"style":326},[13558],{"type":291,"value":928},{"type":281,"tag":319,"props":13560,"children":13561},{"style":332},[13562],{"type":291,"value":362},{"type":281,"tag":319,"props":13564,"children":13565},{"style":365},[13566],{"type":291,"value":937},{"type":281,"tag":319,"props":13568,"children":13569},{"class":321,"line":310},[13570,13574,13578],{"type":281,"tag":319,"props":13571,"children":13572},{"style":326},[13573],{"type":291,"value":961},{"type":281,"tag":319,"props":13575,"children":13576},{"style":332},[13577],{"type":291,"value":362},{"type":281,"tag":319,"props":13579,"children":13580},{"style":365},[13581],{"type":291,"value":970},{"type":281,"tag":319,"props":13583,"children":13584},{"class":321,"line":973},[13585,13589],{"type":281,"tag":319,"props":13586,"children":13587},{"style":326},[13588],{"type":291,"value":1175},{"type":281,"tag":319,"props":13590,"children":13591},{"style":332},[13592],{"type":291,"value":335},{"type":281,"tag":319,"props":13594,"children":13595},{"class":321,"line":986},[13596,13600],{"type":281,"tag":319,"props":13597,"children":13598},{"style":332},[13599],{"type":291,"value":391},{"type":281,"tag":319,"props":13601,"children":13602},{"style":365},[13603],{"type":291,"value":1192},{"type":281,"tag":319,"props":13605,"children":13606},{"class":321,"line":999},[13607,13611],{"type":281,"tag":319,"props":13608,"children":13609},{"style":332},[13610],{"type":291,"value":391},{"type":281,"tag":319,"props":13612,"children":13613},{"style":365},[13614],{"type":291,"value":13615},"letsencrypt:/letsencrypt\n",{"type":281,"tag":319,"props":13617,"children":13618},{"class":321,"line":1012},[13619,13623],{"type":281,"tag":319,"props":13620,"children":13621},{"style":326},[13622],{"type":291,"value":979},{"type":281,"tag":319,"props":13624,"children":13625},{"style":332},[13626],{"type":291,"value":335},{"type":281,"tag":319,"props":13628,"children":13629},{"class":321,"line":1025},[13630,13634],{"type":281,"tag":319,"props":13631,"children":13632},{"style":332},[13633],{"type":291,"value":391},{"type":281,"tag":319,"props":13635,"children":13636},{"style":365},[13637],{"type":291,"value":13638},"--log.level=INFO\n",{"type":281,"tag":319,"props":13640,"children":13641},{"class":321,"line":1038},[13642],{"type":281,"tag":319,"props":13643,"children":13644},{"emptyLinePlaceholder":1042},[13645],{"type":291,"value":1045},{"type":281,"tag":319,"props":13647,"children":13648},{"class":321,"line":1048},[13649,13653],{"type":281,"tag":319,"props":13650,"children":13651},{"style":332},[13652],{"type":291,"value":391},{"type":281,"tag":319,"props":13654,"children":13655},{"style":365},[13656],{"type":291,"value":1058},{"type":281,"tag":319,"props":13658,"children":13659},{"class":321,"line":1061},[13660,13664],{"type":281,"tag":319,"props":13661,"children":13662},{"style":332},[13663],{"type":291,"value":391},{"type":281,"tag":319,"props":13665,"children":13666},{"style":365},[13667],{"type":291,"value":1093},{"type":281,"tag":319,"props":13669,"children":13670},{"class":321,"line":1074},[13671,13675],{"type":281,"tag":319,"props":13672,"children":13673},{"style":332},[13674],{"type":291,"value":391},{"type":281,"tag":319,"props":13676,"children":13677},{"style":365},[13678],{"type":291,"value":1106},{"type":281,"tag":319,"props":13680,"children":13681},{"class":321,"line":1083},[13682],{"type":281,"tag":319,"props":13683,"children":13684},{"emptyLinePlaceholder":1042},[13685],{"type":291,"value":1045},{"type":281,"tag":319,"props":13687,"children":13688},{"class":321,"line":1096},[13689,13693],{"type":281,"tag":319,"props":13690,"children":13691},{"style":332},[13692],{"type":291,"value":391},{"type":281,"tag":319,"props":13694,"children":13695},{"style":365},[13696],{"type":291,"value":1071},{"type":281,"tag":319,"props":13698,"children":13699},{"class":321,"line":1109},[13700,13704],{"type":281,"tag":319,"props":13701,"children":13702},{"style":332},[13703],{"type":291,"value":391},{"type":281,"tag":319,"props":13705,"children":13706},{"style":365},[13707],{"type":291,"value":1119},{"type":281,"tag":319,"props":13709,"children":13710},{"class":321,"line":1122},[13711],{"type":281,"tag":319,"props":13712,"children":13713},{"emptyLinePlaceholder":1042},[13714],{"type":291,"value":1045},{"type":281,"tag":319,"props":13716,"children":13717},{"class":321,"line":1130},[13718,13722],{"type":281,"tag":319,"props":13719,"children":13720},{"style":332},[13721],{"type":291,"value":391},{"type":281,"tag":319,"props":13723,"children":13724},{"style":365},[13725],{"type":291,"value":13726},"--providers.docker=true\n",{"type":281,"tag":319,"props":13728,"children":13729},{"class":321,"line":1143},[13730,13734],{"type":281,"tag":319,"props":13731,"children":13732},{"style":332},[13733],{"type":291,"value":391},{"type":281,"tag":319,"props":13735,"children":13736},{"style":365},[13737],{"type":291,"value":13738},"--providers.docker.exposedByDefault=false\n",{"type":281,"tag":319,"props":13740,"children":13741},{"class":321,"line":1156},[13742],{"type":281,"tag":319,"props":13743,"children":13744},{"emptyLinePlaceholder":1042},[13745],{"type":291,"value":1045},{"type":281,"tag":319,"props":13747,"children":13748},{"class":321,"line":1169},[13749,13753],{"type":281,"tag":319,"props":13750,"children":13751},{"style":332},[13752],{"type":291,"value":391},{"type":281,"tag":319,"props":13754,"children":13755},{"style":365},[13756],{"type":291,"value":13757},"--certificatesresolvers.letsencrypt.acme.email=\u003Cinfo@example.com>\n",{"type":281,"tag":319,"props":13759,"children":13760},{"class":321,"line":1182},[13761,13765],{"type":281,"tag":319,"props":13762,"children":13763},{"style":332},[13764],{"type":291,"value":391},{"type":281,"tag":319,"props":13766,"children":13767},{"style":365},[13768],{"type":291,"value":1022},{"type":281,"tag":319,"props":13770,"children":13771},{"class":321,"line":1195},[13772,13776],{"type":281,"tag":319,"props":13773,"children":13774},{"style":332},[13775],{"type":291,"value":391},{"type":281,"tag":319,"props":13777,"children":13778},{"style":365},[13779],{"type":291,"value":996},{"type":281,"tag":319,"props":13781,"children":13782},{"class":321,"line":2048},[13783,13787],{"type":281,"tag":319,"props":13784,"children":13785},{"style":332},[13786],{"type":291,"value":391},{"type":281,"tag":319,"props":13788,"children":13789},{"style":365},[13790],{"type":291,"value":1035},{"type":281,"tag":282,"props":13792,"children":13793},{},[13794],{"type":291,"value":13795},"This setup will:",{"type":281,"tag":455,"props":13797,"children":13798},{},[13799,13808,13817,13822,13839,13848],{"type":281,"tag":459,"props":13800,"children":13801},{},[13802],{"type":281,"tag":286,"props":13803,"children":13805},{"href":13804},"https://doc.traefik.io/traefik/reference/install-configuration/providers/docker/",[13806],{"type":291,"value":13807},"enable the docker provider",{"type":281,"tag":459,"props":13809,"children":13810},{},[13811],{"type":281,"tag":286,"props":13812,"children":13814},{"href":13813},"https://doc.traefik.io/traefik/providers/docker/#exposedbydefault",[13815],{"type":291,"value":13816},"disable the container discovery",{"type":281,"tag":459,"props":13818,"children":13819},{},[13820],{"type":291,"value":13821},"redirect all HTTP traffic to HTTPS",{"type":281,"tag":459,"props":13823,"children":13824},{},[13825],{"type":281,"tag":286,"props":13826,"children":13828},{"href":13827},"https://doc.traefik.io/traefik/https/acme/#httpchallenge",[13829,13831,13837],{"type":291,"value":13830},"configure Let's Encrypt with ",{"type":281,"tag":315,"props":13832,"children":13834},{"className":13833},[],[13835],{"type":291,"value":13836},"HTTP-01",{"type":291,"value":13838}," challenge",{"type":281,"tag":459,"props":13840,"children":13841},{},[13842],{"type":281,"tag":286,"props":13843,"children":13845},{"href":13844},"https://doc.traefik.io/traefik/routing/entrypoints/#tls",[13846],{"type":291,"value":13847},"apply the TLS configuration to all routes",{"type":281,"tag":459,"props":13849,"children":13850},{},[13851,13857],{"type":281,"tag":286,"props":13852,"children":13854},{"href":13853},"https://docs.docker.com/engine/network/tutorials/host/",[13855],{"type":291,"value":13856},"start the Traefik container bound directly to host's network",{"type":291,"value":13858},", so no addition configuration is required for traefik",{"type":281,"tag":12690,"props":13860,"children":13862},{"id":13861},"the-gitlab-deployment",[13863],{"type":291,"value":13864},"The GitLab deployment",{"type":281,"tag":282,"props":13866,"children":13867},{},[13868,13869,13878],{"type":291,"value":13452},{"type":281,"tag":11280,"props":13870,"children":13871},{},[13872],{"type":281,"tag":315,"props":13873,"children":13875},{"className":13874},[],[13876],{"type":291,"value":13877},"\u003Cgitlab.example.com>",{"type":291,"value":13879}," with your own domain.",{"type":281,"tag":282,"props":13881,"children":13882},{},[13883,13885,13891,13893,13902],{"type":291,"value":13884},"Please take a look in the ",{"type":281,"tag":286,"props":13886,"children":13888},{"href":13887},"https://docs.gitlab.com/install/docker/installation/#create-a-directory-for-the-volumes",[13889],{"type":291,"value":13890},"official dokumentation",{"type":291,"value":13892}," about ",{"type":281,"tag":11280,"props":13894,"children":13895},{},[13896],{"type":281,"tag":315,"props":13897,"children":13899},{"className":13898},[],[13900],{"type":291,"value":13901},"GITLAB_HOME",{"type":291,"value":13903}," directory",{"type":281,"tag":301,"props":13905,"children":13908},{"className":312,"code":13906,"filename":12790,"highlights":13907,"language":311,"meta":8,"style":8},"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",[306,307,308,309,310,1061,1083,1096,1109,1122,1130,1143,1169,1195],[13909],{"type":281,"tag":315,"props":13910,"children":13911},{"__ignoreMap":8},[13912,13923,13934,13950,13965,13977,13989,14002,14015,14028,14043,14059,14070,14085,14092,14100,14108,14117,14124,14133,14142,14151,14160,14169,14177,14184,14193,14204,14217,14228,14239,14250,14261],{"type":281,"tag":319,"props":13913,"children":13914},{"class":321,"line":322},[13915,13919],{"type":281,"tag":319,"props":13916,"children":13917},{"style":326},[13918],{"type":291,"value":329},{"type":281,"tag":319,"props":13920,"children":13921},{"style":332},[13922],{"type":291,"value":335},{"type":281,"tag":319,"props":13924,"children":13925},{"class":321,"line":338},[13926,13930],{"type":281,"tag":319,"props":13927,"children":13928},{"style":326},[13929],{"type":291,"value":12813},{"type":281,"tag":319,"props":13931,"children":13932},{"style":332},[13933],{"type":291,"value":335},{"type":281,"tag":319,"props":13935,"children":13936},{"class":321,"line":351},[13937,13941,13945],{"type":281,"tag":319,"props":13938,"children":13939},{"style":326},[13940],{"type":291,"value":357},{"type":281,"tag":319,"props":13942,"children":13943},{"style":332},[13944],{"type":291,"value":362},{"type":281,"tag":319,"props":13946,"children":13947},{"style":365},[13948],{"type":291,"value":13949},"gitlab/gitlab-ce:\u003Cversion>-ce.0\n",{"type":281,"tag":319,"props":13951,"children":13952},{"class":321,"line":371},[13953,13957,13961],{"type":281,"tag":319,"props":13954,"children":13955},{"style":326},[13956],{"type":291,"value":911},{"type":281,"tag":319,"props":13958,"children":13959},{"style":332},[13960],{"type":291,"value":362},{"type":281,"tag":319,"props":13962,"children":13963},{"style":365},[13964],{"type":291,"value":12849},{"type":281,"tag":319,"props":13966,"children":13968},{"class":13967,"line":306},[321,385],[13969,13973],{"type":281,"tag":319,"props":13970,"children":13971},{"style":326},[13972],{"type":291,"value":377},{"type":281,"tag":319,"props":13974,"children":13975},{"style":332},[13976],{"type":291,"value":335},{"type":281,"tag":319,"props":13978,"children":13980},{"class":13979,"line":307},[321,385],[13981,13985],{"type":281,"tag":319,"props":13982,"children":13983},{"style":332},[13984],{"type":291,"value":391},{"type":281,"tag":319,"props":13986,"children":13987},{"style":365},[13988],{"type":291,"value":396},{"type":281,"tag":319,"props":13990,"children":13992},{"class":13991,"line":308},[321,385],[13993,13997],{"type":281,"tag":319,"props":13994,"children":13995},{"style":332},[13996],{"type":291,"value":391},{"type":281,"tag":319,"props":13998,"children":13999},{"style":365},[14000],{"type":291,"value":14001},"\"traefik.http.routers.gitlab.rule=Host(`\u003Cgitlab.example.com>`)\"\n",{"type":281,"tag":319,"props":14003,"children":14005},{"class":14004,"line":309},[321,385],[14006,14010],{"type":281,"tag":319,"props":14007,"children":14008},{"style":332},[14009],{"type":291,"value":391},{"type":281,"tag":319,"props":14011,"children":14012},{"style":365},[14013],{"type":291,"value":14014},"\"traefik.http.routers.gitlab.service=gitlab\"\n",{"type":281,"tag":319,"props":14016,"children":14018},{"class":14017,"line":310},[321,385],[14019,14023],{"type":281,"tag":319,"props":14020,"children":14021},{"style":332},[14022],{"type":291,"value":391},{"type":281,"tag":319,"props":14024,"children":14025},{"style":365},[14026],{"type":291,"value":14027},"\"traefik.http.services.gitlab.loadbalancer.server.port=80\"\n",{"type":281,"tag":319,"props":14029,"children":14030},{"class":321,"line":973},[14031,14035,14039],{"type":281,"tag":319,"props":14032,"children":14033},{"style":326},[14034],{"type":291,"value":928},{"type":281,"tag":319,"props":14036,"children":14037},{"style":332},[14038],{"type":291,"value":362},{"type":281,"tag":319,"props":14040,"children":14041},{"style":365},[14042],{"type":291,"value":937},{"type":281,"tag":319,"props":14044,"children":14045},{"class":321,"line":986},[14046,14050,14054],{"type":281,"tag":319,"props":14047,"children":14048},{"style":326},[14049],{"type":291,"value":12872},{"type":281,"tag":319,"props":14051,"children":14052},{"style":332},[14053],{"type":291,"value":362},{"type":281,"tag":319,"props":14055,"children":14056},{"style":365},[14057],{"type":291,"value":14058},"'gitlab.example.com'\n",{"type":281,"tag":319,"props":14060,"children":14061},{"class":321,"line":999},[14062,14066],{"type":281,"tag":319,"props":14063,"children":14064},{"style":326},[14065],{"type":291,"value":9689},{"type":281,"tag":319,"props":14067,"children":14068},{"style":332},[14069],{"type":291,"value":335},{"type":281,"tag":319,"props":14071,"children":14072},{"class":321,"line":1012},[14073,14077,14081],{"type":281,"tag":319,"props":14074,"children":14075},{"style":326},[14076],{"type":291,"value":12900},{"type":281,"tag":319,"props":14078,"children":14079},{"style":332},[14080],{"type":291,"value":362},{"type":281,"tag":319,"props":14082,"children":14083},{"style":7965},[14084],{"type":291,"value":12909},{"type":281,"tag":319,"props":14086,"children":14087},{"class":321,"line":1025},[14088],{"type":281,"tag":319,"props":14089,"children":14090},{"style":365},[14091],{"type":291,"value":12917},{"type":281,"tag":319,"props":14093,"children":14094},{"class":321,"line":1038},[14095],{"type":281,"tag":319,"props":14096,"children":14097},{"style":365},[14098],{"type":291,"value":14099},"        external_url '\u003Chttps://gitlab.example.com>'\n",{"type":281,"tag":319,"props":14101,"children":14102},{"class":321,"line":1048},[14103],{"type":281,"tag":319,"props":14104,"children":14105},{"style":365},[14106],{"type":291,"value":14107},"        \n",{"type":281,"tag":319,"props":14109,"children":14111},{"class":14110,"line":1061},[321,385],[14112],{"type":281,"tag":319,"props":14113,"children":14114},{"style":365},[14115],{"type":291,"value":14116},"        letsencrypt['enable'] = false\n",{"type":281,"tag":319,"props":14118,"children":14119},{"class":321,"line":1074},[14120],{"type":281,"tag":319,"props":14121,"children":14122},{"style":365},[14123],{"type":291,"value":14107},{"type":281,"tag":319,"props":14125,"children":14127},{"class":14126,"line":1083},[321,385],[14128],{"type":281,"tag":319,"props":14129,"children":14130},{"style":365},[14131],{"type":291,"value":14132},"        nginx['listen_port'] = 80\n",{"type":281,"tag":319,"props":14134,"children":14136},{"class":14135,"line":1096},[321,385],[14137],{"type":281,"tag":319,"props":14138,"children":14139},{"style":365},[14140],{"type":291,"value":14141},"        nginx['listen_https'] = false\n",{"type":281,"tag":319,"props":14143,"children":14145},{"class":14144,"line":1109},[321,385],[14146],{"type":281,"tag":319,"props":14147,"children":14148},{"style":365},[14149],{"type":291,"value":14150},"        nginx['proxy_set_headers'] = {\n",{"type":281,"tag":319,"props":14152,"children":14154},{"class":14153,"line":1122},[321,385],[14155],{"type":281,"tag":319,"props":14156,"children":14157},{"style":365},[14158],{"type":291,"value":14159},"          \"X-Forwarded-Proto\" => \"https\",\n",{"type":281,"tag":319,"props":14161,"children":14163},{"class":14162,"line":1130},[321,385],[14164],{"type":281,"tag":319,"props":14165,"children":14166},{"style":365},[14167],{"type":291,"value":14168},"          \"X-Forwarded-Ssl\" => \"on\"\n",{"type":281,"tag":319,"props":14170,"children":14172},{"class":14171,"line":1143},[321,385],[14173],{"type":281,"tag":319,"props":14174,"children":14175},{"style":365},[14176],{"type":291,"value":6565},{"type":281,"tag":319,"props":14178,"children":14179},{"class":321,"line":1156},[14180],{"type":281,"tag":319,"props":14181,"children":14182},{"style":365},[14183],{"type":291,"value":14107},{"type":281,"tag":319,"props":14185,"children":14187},{"class":14186,"line":1169},[321,385],[14188],{"type":281,"tag":319,"props":14189,"children":14190},{"style":365},[14191],{"type":291,"value":14192},"        gitlab_rails['gitlab_shell_ssh_port'] = 2424\n",{"type":281,"tag":319,"props":14194,"children":14195},{"class":321,"line":1182},[14196,14200],{"type":281,"tag":319,"props":14197,"children":14198},{"style":326},[14199],{"type":291,"value":12933},{"type":281,"tag":319,"props":14201,"children":14202},{"style":332},[14203],{"type":291,"value":335},{"type":281,"tag":319,"props":14205,"children":14207},{"class":14206,"line":1195},[321,385],[14208,14212],{"type":281,"tag":319,"props":14209,"children":14210},{"style":332},[14211],{"type":291,"value":391},{"type":281,"tag":319,"props":14213,"children":14214},{"style":365},[14215],{"type":291,"value":14216},"'2424:22'\n",{"type":281,"tag":319,"props":14218,"children":14219},{"class":321,"line":2048},[14220,14224],{"type":281,"tag":319,"props":14221,"children":14222},{"style":326},[14223],{"type":291,"value":1175},{"type":281,"tag":319,"props":14225,"children":14226},{"style":332},[14227],{"type":291,"value":335},{"type":281,"tag":319,"props":14229,"children":14230},{"class":321,"line":2049},[14231,14235],{"type":281,"tag":319,"props":14232,"children":14233},{"style":332},[14234],{"type":291,"value":391},{"type":281,"tag":319,"props":14236,"children":14237},{"style":365},[14238],{"type":291,"value":12996},{"type":281,"tag":319,"props":14240,"children":14241},{"class":321,"line":2050},[14242,14246],{"type":281,"tag":319,"props":14243,"children":14244},{"style":332},[14245],{"type":291,"value":391},{"type":281,"tag":319,"props":14247,"children":14248},{"style":365},[14249],{"type":291,"value":13008},{"type":281,"tag":319,"props":14251,"children":14252},{"class":321,"line":2051},[14253,14257],{"type":281,"tag":319,"props":14254,"children":14255},{"style":332},[14256],{"type":291,"value":391},{"type":281,"tag":319,"props":14258,"children":14259},{"style":365},[14260],{"type":291,"value":13020},{"type":281,"tag":319,"props":14262,"children":14263},{"class":321,"line":2052},[14264,14268,14272],{"type":281,"tag":319,"props":14265,"children":14266},{"style":326},[14267],{"type":291,"value":13028},{"type":281,"tag":319,"props":14269,"children":14270},{"style":332},[14271],{"type":291,"value":362},{"type":281,"tag":319,"props":14273,"children":14274},{"style":365},[14275],{"type":291,"value":13037},{"type":281,"tag":282,"props":14277,"children":14278},{},[14279],{"type":291,"value":13795},{"type":281,"tag":455,"props":14281,"children":14282},{},[14283,14288,14293,14298,14303],{"type":281,"tag":459,"props":14284,"children":14285},{},[14286],{"type":291,"value":14287},"disable the Let's Encrypt",{"type":281,"tag":459,"props":14289,"children":14290},{},[14291],{"type":291,"value":14292},"disable listening on https and listen on port 80",{"type":281,"tag":459,"props":14294,"children":14295},{},[14296],{"type":291,"value":14297},"set the required proxy headers",{"type":281,"tag":459,"props":14299,"children":14300},{},[14301],{"type":291,"value":14302},"change the ssh port to 2424",{"type":281,"tag":459,"props":14304,"children":14305},{},[14306,14308,14314],{"type":291,"value":14307},"instruct Traefik to route all traffic for ",{"type":281,"tag":315,"props":14309,"children":14311},{"className":14310},[],[14312],{"type":291,"value":14313},"gitlab.example.com",{"type":291,"value":14315}," to port 80 of the container",{"type":281,"tag":1314,"props":14317,"children":14318},{},[],{"type":281,"tag":282,"props":14320,"children":14321},{},[14322],{"type":281,"tag":319,"props":14323,"children":14325},{"className":14324},[4894],[14326],{"type":291,"value":4897},{"type":281,"tag":1314,"props":14328,"children":14329},{},[],{"type":281,"tag":832,"props":14331,"children":14332},{},[],{"type":281,"tag":1248,"props":14334,"children":14336},{"id":14335},"gitlab-container-registry",[14337],{"type":291,"value":14338},"GitLab Container registry",{"type":281,"tag":282,"props":14340,"children":14341},{},[14342,14344],{"type":291,"value":14343},"When you got so far, you probably also want to set up the ",{"type":281,"tag":286,"props":14345,"children":14347},{"href":14346},"https://docs.gitlab.com/administration/packages/container_registry/",[14348],{"type":291,"value":14349},"container registry",{"type":281,"tag":12690,"props":14351,"children":14353},{"id":14352},"configure-container-registry-under-its-own-domain",[14354],{"type":281,"tag":286,"props":14355,"children":14357},{"href":14356},"https://docs.gitlab.com/administration/packages/container_registry/#configure-container-registry-under-its-own-domain",[14358],{"type":291,"value":14359},"Configure container registry under its own domain",{"type":281,"tag":282,"props":14361,"children":14362},{},[14363,14365,14371],{"type":291,"value":14364},"This setup is easy. We just need to set the ",{"type":281,"tag":315,"props":14366,"children":14368},{"className":14367},[],[14369],{"type":291,"value":14370},"registry_external_url",{"type":291,"value":14372}," and instruct Traefik where to route the requests",{"type":281,"tag":1314,"props":14374,"children":14375},{},[],{"type":281,"tag":14377,"props":14378,"children":14380},"h5",{"id":14379},"update-the-gitlab-config",[14381],{"type":291,"value":14382},"Update the GitLab config",{"type":281,"tag":301,"props":14384,"children":14387},{"className":312,"code":14385,"filename":12790,"highlights":14386,"language":311,"meta":8,"style":8},"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",[973,986,2049,2050],[14388],{"type":281,"tag":315,"props":14389,"children":14390},{"__ignoreMap":8},[14391,14402,14413,14428,14443,14454,14465,14476,14487,14498,14511,14524,14539,14554,14565,14580,14587,14594,14601,14608,14615,14622,14629,14636,14643,14650,14657,14664,14671,14678,14687,14696,14707,14718,14729,14740,14751,14762],{"type":281,"tag":319,"props":14392,"children":14393},{"class":321,"line":322},[14394,14398],{"type":281,"tag":319,"props":14395,"children":14396},{"style":326},[14397],{"type":291,"value":329},{"type":281,"tag":319,"props":14399,"children":14400},{"style":332},[14401],{"type":291,"value":335},{"type":281,"tag":319,"props":14403,"children":14404},{"class":321,"line":338},[14405,14409],{"type":281,"tag":319,"props":14406,"children":14407},{"style":326},[14408],{"type":291,"value":12813},{"type":281,"tag":319,"props":14410,"children":14411},{"style":332},[14412],{"type":291,"value":335},{"type":281,"tag":319,"props":14414,"children":14415},{"class":321,"line":351},[14416,14420,14424],{"type":281,"tag":319,"props":14417,"children":14418},{"style":326},[14419],{"type":291,"value":357},{"type":281,"tag":319,"props":14421,"children":14422},{"style":332},[14423],{"type":291,"value":362},{"type":281,"tag":319,"props":14425,"children":14426},{"style":365},[14427],{"type":291,"value":13949},{"type":281,"tag":319,"props":14429,"children":14430},{"class":321,"line":371},[14431,14435,14439],{"type":281,"tag":319,"props":14432,"children":14433},{"style":326},[14434],{"type":291,"value":911},{"type":281,"tag":319,"props":14436,"children":14437},{"style":332},[14438],{"type":291,"value":362},{"type":281,"tag":319,"props":14440,"children":14441},{"style":365},[14442],{"type":291,"value":12849},{"type":281,"tag":319,"props":14444,"children":14445},{"class":321,"line":306},[14446,14450],{"type":281,"tag":319,"props":14447,"children":14448},{"style":326},[14449],{"type":291,"value":377},{"type":281,"tag":319,"props":14451,"children":14452},{"style":332},[14453],{"type":291,"value":335},{"type":281,"tag":319,"props":14455,"children":14456},{"class":321,"line":307},[14457,14461],{"type":281,"tag":319,"props":14458,"children":14459},{"style":332},[14460],{"type":291,"value":391},{"type":281,"tag":319,"props":14462,"children":14463},{"style":365},[14464],{"type":291,"value":396},{"type":281,"tag":319,"props":14466,"children":14467},{"class":321,"line":308},[14468,14472],{"type":281,"tag":319,"props":14469,"children":14470},{"style":332},[14471],{"type":291,"value":391},{"type":281,"tag":319,"props":14473,"children":14474},{"style":365},[14475],{"type":291,"value":14001},{"type":281,"tag":319,"props":14477,"children":14478},{"class":321,"line":309},[14479,14483],{"type":281,"tag":319,"props":14480,"children":14481},{"style":332},[14482],{"type":291,"value":391},{"type":281,"tag":319,"props":14484,"children":14485},{"style":365},[14486],{"type":291,"value":14014},{"type":281,"tag":319,"props":14488,"children":14489},{"class":321,"line":310},[14490,14494],{"type":281,"tag":319,"props":14491,"children":14492},{"style":332},[14493],{"type":291,"value":391},{"type":281,"tag":319,"props":14495,"children":14496},{"style":365},[14497],{"type":291,"value":14027},{"type":281,"tag":319,"props":14499,"children":14501},{"class":14500,"line":973},[321,385],[14502,14506],{"type":281,"tag":319,"props":14503,"children":14504},{"style":332},[14505],{"type":291,"value":391},{"type":281,"tag":319,"props":14507,"children":14508},{"style":365},[14509],{"type":291,"value":14510},"\"traefik.http.routers.container-registry.rule=Host(`registry.gitlab.example.com`)\"\n",{"type":281,"tag":319,"props":14512,"children":14514},{"class":14513,"line":986},[321,385],[14515,14519],{"type":281,"tag":319,"props":14516,"children":14517},{"style":332},[14518],{"type":291,"value":391},{"type":281,"tag":319,"props":14520,"children":14521},{"style":365},[14522],{"type":291,"value":14523},"\"traefik.http.services.container-registry.loadbalancer.server.port=5000\"\n",{"type":281,"tag":319,"props":14525,"children":14526},{"class":321,"line":999},[14527,14531,14535],{"type":281,"tag":319,"props":14528,"children":14529},{"style":326},[14530],{"type":291,"value":928},{"type":281,"tag":319,"props":14532,"children":14533},{"style":332},[14534],{"type":291,"value":362},{"type":281,"tag":319,"props":14536,"children":14537},{"style":365},[14538],{"type":291,"value":937},{"type":281,"tag":319,"props":14540,"children":14541},{"class":321,"line":1012},[14542,14546,14550],{"type":281,"tag":319,"props":14543,"children":14544},{"style":326},[14545],{"type":291,"value":12872},{"type":281,"tag":319,"props":14547,"children":14548},{"style":332},[14549],{"type":291,"value":362},{"type":281,"tag":319,"props":14551,"children":14552},{"style":365},[14553],{"type":291,"value":14058},{"type":281,"tag":319,"props":14555,"children":14556},{"class":321,"line":1025},[14557,14561],{"type":281,"tag":319,"props":14558,"children":14559},{"style":326},[14560],{"type":291,"value":9689},{"type":281,"tag":319,"props":14562,"children":14563},{"style":332},[14564],{"type":291,"value":335},{"type":281,"tag":319,"props":14566,"children":14567},{"class":321,"line":1038},[14568,14572,14576],{"type":281,"tag":319,"props":14569,"children":14570},{"style":326},[14571],{"type":291,"value":12900},{"type":281,"tag":319,"props":14573,"children":14574},{"style":332},[14575],{"type":291,"value":362},{"type":281,"tag":319,"props":14577,"children":14578},{"style":7965},[14579],{"type":291,"value":12909},{"type":281,"tag":319,"props":14581,"children":14582},{"class":321,"line":1048},[14583],{"type":281,"tag":319,"props":14584,"children":14585},{"style":365},[14586],{"type":291,"value":12917},{"type":281,"tag":319,"props":14588,"children":14589},{"class":321,"line":1061},[14590],{"type":281,"tag":319,"props":14591,"children":14592},{"style":365},[14593],{"type":291,"value":14099},{"type":281,"tag":319,"props":14595,"children":14596},{"class":321,"line":1074},[14597],{"type":281,"tag":319,"props":14598,"children":14599},{"emptyLinePlaceholder":1042},[14600],{"type":291,"value":1045},{"type":281,"tag":319,"props":14602,"children":14603},{"class":321,"line":1083},[14604],{"type":281,"tag":319,"props":14605,"children":14606},{"style":365},[14607],{"type":291,"value":14116},{"type":281,"tag":319,"props":14609,"children":14610},{"class":321,"line":1096},[14611],{"type":281,"tag":319,"props":14612,"children":14613},{"emptyLinePlaceholder":1042},[14614],{"type":291,"value":1045},{"type":281,"tag":319,"props":14616,"children":14617},{"class":321,"line":1109},[14618],{"type":281,"tag":319,"props":14619,"children":14620},{"style":365},[14621],{"type":291,"value":14132},{"type":281,"tag":319,"props":14623,"children":14624},{"class":321,"line":1122},[14625],{"type":281,"tag":319,"props":14626,"children":14627},{"style":365},[14628],{"type":291,"value":14141},{"type":281,"tag":319,"props":14630,"children":14631},{"class":321,"line":1130},[14632],{"type":281,"tag":319,"props":14633,"children":14634},{"style":365},[14635],{"type":291,"value":14150},{"type":281,"tag":319,"props":14637,"children":14638},{"class":321,"line":1143},[14639],{"type":281,"tag":319,"props":14640,"children":14641},{"style":365},[14642],{"type":291,"value":14159},{"type":281,"tag":319,"props":14644,"children":14645},{"class":321,"line":1156},[14646],{"type":281,"tag":319,"props":14647,"children":14648},{"style":365},[14649],{"type":291,"value":14168},{"type":281,"tag":319,"props":14651,"children":14652},{"class":321,"line":1169},[14653],{"type":281,"tag":319,"props":14654,"children":14655},{"style":365},[14656],{"type":291,"value":6565},{"type":281,"tag":319,"props":14658,"children":14659},{"class":321,"line":1182},[14660],{"type":281,"tag":319,"props":14661,"children":14662},{"emptyLinePlaceholder":1042},[14663],{"type":291,"value":1045},{"type":281,"tag":319,"props":14665,"children":14666},{"class":321,"line":1195},[14667],{"type":281,"tag":319,"props":14668,"children":14669},{"style":365},[14670],{"type":291,"value":14192},{"type":281,"tag":319,"props":14672,"children":14673},{"class":321,"line":2048},[14674],{"type":281,"tag":319,"props":14675,"children":14676},{"emptyLinePlaceholder":1042},[14677],{"type":291,"value":1045},{"type":281,"tag":319,"props":14679,"children":14681},{"class":14680,"line":2049},[321,385],[14682],{"type":281,"tag":319,"props":14683,"children":14684},{"style":365},[14685],{"type":291,"value":14686},"        registry_external_url '\u003Chttps://registry.gitlab.example.com>'\n",{"type":281,"tag":319,"props":14688,"children":14690},{"class":14689,"line":2050},[321,385],[14691],{"type":281,"tag":319,"props":14692,"children":14693},{"style":365},[14694],{"type":291,"value":14695},"        registry_nginx['enable'] = false\n",{"type":281,"tag":319,"props":14697,"children":14698},{"class":321,"line":2051},[14699,14703],{"type":281,"tag":319,"props":14700,"children":14701},{"style":326},[14702],{"type":291,"value":12933},{"type":281,"tag":319,"props":14704,"children":14705},{"style":332},[14706],{"type":291,"value":335},{"type":281,"tag":319,"props":14708,"children":14709},{"class":321,"line":2052},[14710,14714],{"type":281,"tag":319,"props":14711,"children":14712},{"style":332},[14713],{"type":291,"value":391},{"type":281,"tag":319,"props":14715,"children":14716},{"style":365},[14717],{"type":291,"value":14216},{"type":281,"tag":319,"props":14719,"children":14720},{"class":321,"line":2053},[14721,14725],{"type":281,"tag":319,"props":14722,"children":14723},{"style":326},[14724],{"type":291,"value":1175},{"type":281,"tag":319,"props":14726,"children":14727},{"style":332},[14728],{"type":291,"value":335},{"type":281,"tag":319,"props":14730,"children":14731},{"class":321,"line":2054},[14732,14736],{"type":281,"tag":319,"props":14733,"children":14734},{"style":332},[14735],{"type":291,"value":391},{"type":281,"tag":319,"props":14737,"children":14738},{"style":365},[14739],{"type":291,"value":12996},{"type":281,"tag":319,"props":14741,"children":14742},{"class":321,"line":2055},[14743,14747],{"type":281,"tag":319,"props":14744,"children":14745},{"style":332},[14746],{"type":291,"value":391},{"type":281,"tag":319,"props":14748,"children":14749},{"style":365},[14750],{"type":291,"value":13008},{"type":281,"tag":319,"props":14752,"children":14753},{"class":321,"line":2579},[14754,14758],{"type":281,"tag":319,"props":14755,"children":14756},{"style":332},[14757],{"type":291,"value":391},{"type":281,"tag":319,"props":14759,"children":14760},{"style":365},[14761],{"type":291,"value":13020},{"type":281,"tag":319,"props":14763,"children":14764},{"class":321,"line":2056},[14765,14769,14773],{"type":281,"tag":319,"props":14766,"children":14767},{"style":326},[14768],{"type":291,"value":13028},{"type":281,"tag":319,"props":14770,"children":14771},{"style":332},[14772],{"type":291,"value":362},{"type":281,"tag":319,"props":14774,"children":14775},{"style":365},[14776],{"type":291,"value":13037},{"type":281,"tag":282,"props":14778,"children":14779},{},[14780],{"type":291,"value":13795},{"type":281,"tag":455,"props":14782,"children":14783},{},[14784,14789,14794],{"type":281,"tag":459,"props":14785,"children":14786},{},[14787],{"type":291,"value":14788},"set the registry external url",{"type":281,"tag":459,"props":14790,"children":14791},{},[14792],{"type":291,"value":14793},"disable the nginx for the registry",{"type":281,"tag":459,"props":14795,"children":14796},{},[14797,14798,14804],{"type":291,"value":14307},{"type":281,"tag":315,"props":14799,"children":14801},{"className":14800},[],[14802],{"type":291,"value":14803},"registry.gitlab.example.com",{"type":291,"value":14805}," to port 5000 of the container",{"type":281,"tag":1314,"props":14807,"children":14808},{},[],{"type":281,"tag":832,"props":14810,"children":14811},{},[],{"type":281,"tag":12690,"props":14813,"children":14815},{"id":14814},"configure-container-registry-under-an-existing-gitlab-domain",[14816],{"type":281,"tag":286,"props":14817,"children":14819},{"href":14818},"https://docs.gitlab.com/administration/packages/container_registry/#configure-container-registry-under-an-existing-gitlab-domain",[14820],{"type":291,"value":14821},"Configure container registry under an existing GitLab domain",{"type":281,"tag":14377,"props":14823,"children":14825},{"id":14824},"update-the-traefik-config",[14826],{"type":291,"value":14827},"Update the Traefik config",{"type":281,"tag":301,"props":14829,"children":14832},{"className":312,"code":14830,"filename":843,"highlights":14831,"language":311,"meta":8,"style":8},"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",[1130,1143],[14833],{"type":281,"tag":315,"props":14834,"children":14835},{"__ignoreMap":8},[14836,14847,14858,14865,14876,14887,14902,14917,14932,14947,14958,14969,14980,14991,15002,15009,15020,15031,15042,15049,15060,15071,15078,15091,15104,15111,15122,15133,15140,15151,15162,15173],{"type":281,"tag":319,"props":14837,"children":14838},{"class":321,"line":322},[14839,14843],{"type":281,"tag":319,"props":14840,"children":14841},{"style":326},[14842],{"type":291,"value":856},{"type":281,"tag":319,"props":14844,"children":14845},{"style":332},[14846],{"type":291,"value":335},{"type":281,"tag":319,"props":14848,"children":14849},{"class":321,"line":338},[14850,14854],{"type":281,"tag":319,"props":14851,"children":14852},{"style":326},[14853],{"type":291,"value":868},{"type":281,"tag":319,"props":14855,"children":14856},{"style":332},[14857],{"type":291,"value":335},{"type":281,"tag":319,"props":14859,"children":14860},{"class":321,"line":351},[14861],{"type":281,"tag":319,"props":14862,"children":14863},{"emptyLinePlaceholder":1042},[14864],{"type":291,"value":1045},{"type":281,"tag":319,"props":14866,"children":14867},{"class":321,"line":371},[14868,14872],{"type":281,"tag":319,"props":14869,"children":14870},{"style":326},[14871],{"type":291,"value":329},{"type":281,"tag":319,"props":14873,"children":14874},{"style":332},[14875],{"type":291,"value":335},{"type":281,"tag":319,"props":14877,"children":14878},{"class":321,"line":306},[14879,14883],{"type":281,"tag":319,"props":14880,"children":14881},{"style":326},[14882],{"type":291,"value":899},{"type":281,"tag":319,"props":14884,"children":14885},{"style":332},[14886],{"type":291,"value":335},{"type":281,"tag":319,"props":14888,"children":14889},{"class":321,"line":307},[14890,14894,14898],{"type":281,"tag":319,"props":14891,"children":14892},{"style":326},[14893],{"type":291,"value":357},{"type":281,"tag":319,"props":14895,"children":14896},{"style":332},[14897],{"type":291,"value":362},{"type":281,"tag":319,"props":14899,"children":14900},{"style":365},[14901],{"type":291,"value":953},{"type":281,"tag":319,"props":14903,"children":14904},{"class":321,"line":308},[14905,14909,14913],{"type":281,"tag":319,"props":14906,"children":14907},{"style":326},[14908],{"type":291,"value":911},{"type":281,"tag":319,"props":14910,"children":14911},{"style":332},[14912],{"type":291,"value":362},{"type":281,"tag":319,"props":14914,"children":14915},{"style":365},[14916],{"type":291,"value":920},{"type":281,"tag":319,"props":14918,"children":14919},{"class":321,"line":309},[14920,14924,14928],{"type":281,"tag":319,"props":14921,"children":14922},{"style":326},[14923],{"type":291,"value":928},{"type":281,"tag":319,"props":14925,"children":14926},{"style":332},[14927],{"type":291,"value":362},{"type":281,"tag":319,"props":14929,"children":14930},{"style":365},[14931],{"type":291,"value":937},{"type":281,"tag":319,"props":14933,"children":14934},{"class":321,"line":310},[14935,14939,14943],{"type":281,"tag":319,"props":14936,"children":14937},{"style":326},[14938],{"type":291,"value":961},{"type":281,"tag":319,"props":14940,"children":14941},{"style":332},[14942],{"type":291,"value":362},{"type":281,"tag":319,"props":14944,"children":14945},{"style":365},[14946],{"type":291,"value":970},{"type":281,"tag":319,"props":14948,"children":14949},{"class":321,"line":973},[14950,14954],{"type":281,"tag":319,"props":14951,"children":14952},{"style":326},[14953],{"type":291,"value":1175},{"type":281,"tag":319,"props":14955,"children":14956},{"style":332},[14957],{"type":291,"value":335},{"type":281,"tag":319,"props":14959,"children":14960},{"class":321,"line":986},[14961,14965],{"type":281,"tag":319,"props":14962,"children":14963},{"style":332},[14964],{"type":291,"value":391},{"type":281,"tag":319,"props":14966,"children":14967},{"style":365},[14968],{"type":291,"value":1192},{"type":281,"tag":319,"props":14970,"children":14971},{"class":321,"line":999},[14972,14976],{"type":281,"tag":319,"props":14973,"children":14974},{"style":332},[14975],{"type":291,"value":391},{"type":281,"tag":319,"props":14977,"children":14978},{"style":365},[14979],{"type":291,"value":13615},{"type":281,"tag":319,"props":14981,"children":14982},{"class":321,"line":1012},[14983,14987],{"type":281,"tag":319,"props":14984,"children":14985},{"style":326},[14986],{"type":291,"value":979},{"type":281,"tag":319,"props":14988,"children":14989},{"style":332},[14990],{"type":291,"value":335},{"type":281,"tag":319,"props":14992,"children":14993},{"class":321,"line":1025},[14994,14998],{"type":281,"tag":319,"props":14995,"children":14996},{"style":332},[14997],{"type":291,"value":391},{"type":281,"tag":319,"props":14999,"children":15000},{"style":365},[15001],{"type":291,"value":13638},{"type":281,"tag":319,"props":15003,"children":15004},{"class":321,"line":1038},[15005],{"type":281,"tag":319,"props":15006,"children":15007},{"emptyLinePlaceholder":1042},[15008],{"type":291,"value":1045},{"type":281,"tag":319,"props":15010,"children":15011},{"class":321,"line":1048},[15012,15016],{"type":281,"tag":319,"props":15013,"children":15014},{"style":332},[15015],{"type":291,"value":391},{"type":281,"tag":319,"props":15017,"children":15018},{"style":365},[15019],{"type":291,"value":1058},{"type":281,"tag":319,"props":15021,"children":15022},{"class":321,"line":1061},[15023,15027],{"type":281,"tag":319,"props":15024,"children":15025},{"style":332},[15026],{"type":291,"value":391},{"type":281,"tag":319,"props":15028,"children":15029},{"style":365},[15030],{"type":291,"value":1093},{"type":281,"tag":319,"props":15032,"children":15033},{"class":321,"line":1074},[15034,15038],{"type":281,"tag":319,"props":15035,"children":15036},{"style":332},[15037],{"type":291,"value":391},{"type":281,"tag":319,"props":15039,"children":15040},{"style":365},[15041],{"type":291,"value":1106},{"type":281,"tag":319,"props":15043,"children":15044},{"class":321,"line":1083},[15045],{"type":281,"tag":319,"props":15046,"children":15047},{"emptyLinePlaceholder":1042},[15048],{"type":291,"value":1045},{"type":281,"tag":319,"props":15050,"children":15051},{"class":321,"line":1096},[15052,15056],{"type":281,"tag":319,"props":15053,"children":15054},{"style":332},[15055],{"type":291,"value":391},{"type":281,"tag":319,"props":15057,"children":15058},{"style":365},[15059],{"type":291,"value":1071},{"type":281,"tag":319,"props":15061,"children":15062},{"class":321,"line":1109},[15063,15067],{"type":281,"tag":319,"props":15064,"children":15065},{"style":332},[15066],{"type":291,"value":391},{"type":281,"tag":319,"props":15068,"children":15069},{"style":365},[15070],{"type":291,"value":1119},{"type":281,"tag":319,"props":15072,"children":15073},{"class":321,"line":1122},[15074],{"type":281,"tag":319,"props":15075,"children":15076},{"style":332},[15077],{"type":291,"value":14107},{"type":281,"tag":319,"props":15079,"children":15081},{"class":15080,"line":1130},[321,385],[15082,15086],{"type":281,"tag":319,"props":15083,"children":15084},{"style":332},[15085],{"type":291,"value":391},{"type":281,"tag":319,"props":15087,"children":15088},{"style":365},[15089],{"type":291,"value":15090},"--entrypoints.container-registry.address=:5050\n",{"type":281,"tag":319,"props":15092,"children":15094},{"class":15093,"line":1143},[321,385],[15095,15099],{"type":281,"tag":319,"props":15096,"children":15097},{"style":332},[15098],{"type":291,"value":391},{"type":281,"tag":319,"props":15100,"children":15101},{"style":365},[15102],{"type":291,"value":15103},"--entrypoints.container-registry.http.tls.certresolver=letsencrypt\n",{"type":281,"tag":319,"props":15105,"children":15106},{"class":321,"line":1156},[15107],{"type":281,"tag":319,"props":15108,"children":15109},{"emptyLinePlaceholder":1042},[15110],{"type":291,"value":1045},{"type":281,"tag":319,"props":15112,"children":15113},{"class":321,"line":1169},[15114,15118],{"type":281,"tag":319,"props":15115,"children":15116},{"style":332},[15117],{"type":291,"value":391},{"type":281,"tag":319,"props":15119,"children":15120},{"style":365},[15121],{"type":291,"value":13726},{"type":281,"tag":319,"props":15123,"children":15124},{"class":321,"line":1182},[15125,15129],{"type":281,"tag":319,"props":15126,"children":15127},{"style":332},[15128],{"type":291,"value":391},{"type":281,"tag":319,"props":15130,"children":15131},{"style":365},[15132],{"type":291,"value":13738},{"type":281,"tag":319,"props":15134,"children":15135},{"class":321,"line":1195},[15136],{"type":281,"tag":319,"props":15137,"children":15138},{"emptyLinePlaceholder":1042},[15139],{"type":291,"value":1045},{"type":281,"tag":319,"props":15141,"children":15142},{"class":321,"line":2048},[15143,15147],{"type":281,"tag":319,"props":15144,"children":15145},{"style":332},[15146],{"type":291,"value":391},{"type":281,"tag":319,"props":15148,"children":15149},{"style":365},[15150],{"type":291,"value":13757},{"type":281,"tag":319,"props":15152,"children":15153},{"class":321,"line":2049},[15154,15158],{"type":281,"tag":319,"props":15155,"children":15156},{"style":332},[15157],{"type":291,"value":391},{"type":281,"tag":319,"props":15159,"children":15160},{"style":365},[15161],{"type":291,"value":1022},{"type":281,"tag":319,"props":15163,"children":15164},{"class":321,"line":2050},[15165,15169],{"type":281,"tag":319,"props":15166,"children":15167},{"style":332},[15168],{"type":291,"value":391},{"type":281,"tag":319,"props":15170,"children":15171},{"style":365},[15172],{"type":291,"value":996},{"type":281,"tag":319,"props":15174,"children":15175},{"class":321,"line":2051},[15176,15180],{"type":281,"tag":319,"props":15177,"children":15178},{"style":332},[15179],{"type":291,"value":391},{"type":281,"tag":319,"props":15181,"children":15182},{"style":365},[15183],{"type":291,"value":1035},{"type":281,"tag":282,"props":15185,"children":15186},{},[15187],{"type":291,"value":13795},{"type":281,"tag":455,"props":15189,"children":15190},{},[15191,15196],{"type":281,"tag":459,"props":15192,"children":15193},{},[15194],{"type":291,"value":15195},"add a new entry point for the container registry",{"type":281,"tag":459,"props":15197,"children":15198},{},[15199],{"type":291,"value":15200},"apply the TLS configuration to all routes in this entrypoint",{"type":281,"tag":1314,"props":15202,"children":15203},{},[],{"type":281,"tag":14377,"props":15205,"children":15207},{"id":15206},"update-the-gitlab-config-1",[15208],{"type":291,"value":14382},{"type":281,"tag":301,"props":15210,"children":15213},{"className":312,"code":15211,"filename":12790,"highlights":15212,"language":311,"meta":8,"style":8},"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",[309,986,999,1012,1025,2052],[15214],{"type":281,"tag":315,"props":15215,"children":15216},{"__ignoreMap":8},[15217,15228,15239,15254,15269,15280,15291,15302,15315,15326,15337,15350,15363,15376,15388,15403,15418,15429,15444,15451,15458,15465,15472,15479,15486,15493,15500,15507,15514,15521,15528,15535,15542,15551,15558,15569,15580,15591,15602,15613,15624],{"type":281,"tag":319,"props":15218,"children":15219},{"class":321,"line":322},[15220,15224],{"type":281,"tag":319,"props":15221,"children":15222},{"style":326},[15223],{"type":291,"value":329},{"type":281,"tag":319,"props":15225,"children":15226},{"style":332},[15227],{"type":291,"value":335},{"type":281,"tag":319,"props":15229,"children":15230},{"class":321,"line":338},[15231,15235],{"type":281,"tag":319,"props":15232,"children":15233},{"style":326},[15234],{"type":291,"value":12813},{"type":281,"tag":319,"props":15236,"children":15237},{"style":332},[15238],{"type":291,"value":335},{"type":281,"tag":319,"props":15240,"children":15241},{"class":321,"line":351},[15242,15246,15250],{"type":281,"tag":319,"props":15243,"children":15244},{"style":326},[15245],{"type":291,"value":357},{"type":281,"tag":319,"props":15247,"children":15248},{"style":332},[15249],{"type":291,"value":362},{"type":281,"tag":319,"props":15251,"children":15252},{"style":365},[15253],{"type":291,"value":13949},{"type":281,"tag":319,"props":15255,"children":15256},{"class":321,"line":371},[15257,15261,15265],{"type":281,"tag":319,"props":15258,"children":15259},{"style":326},[15260],{"type":291,"value":911},{"type":281,"tag":319,"props":15262,"children":15263},{"style":332},[15264],{"type":291,"value":362},{"type":281,"tag":319,"props":15266,"children":15267},{"style":365},[15268],{"type":291,"value":12849},{"type":281,"tag":319,"props":15270,"children":15271},{"class":321,"line":306},[15272,15276],{"type":281,"tag":319,"props":15273,"children":15274},{"style":326},[15275],{"type":291,"value":377},{"type":281,"tag":319,"props":15277,"children":15278},{"style":332},[15279],{"type":291,"value":335},{"type":281,"tag":319,"props":15281,"children":15282},{"class":321,"line":307},[15283,15287],{"type":281,"tag":319,"props":15284,"children":15285},{"style":332},[15286],{"type":291,"value":391},{"type":281,"tag":319,"props":15288,"children":15289},{"style":365},[15290],{"type":291,"value":396},{"type":281,"tag":319,"props":15292,"children":15293},{"class":321,"line":308},[15294,15298],{"type":281,"tag":319,"props":15295,"children":15296},{"style":332},[15297],{"type":291,"value":391},{"type":281,"tag":319,"props":15299,"children":15300},{"style":365},[15301],{"type":291,"value":14001},{"type":281,"tag":319,"props":15303,"children":15305},{"class":15304,"line":309},[321,385],[15306,15310],{"type":281,"tag":319,"props":15307,"children":15308},{"style":332},[15309],{"type":291,"value":391},{"type":281,"tag":319,"props":15311,"children":15312},{"style":365},[15313],{"type":291,"value":15314},"\"traefik.http.routers.gitlab.entrypoints=web,websecure\"\n",{"type":281,"tag":319,"props":15316,"children":15317},{"class":321,"line":310},[15318,15322],{"type":281,"tag":319,"props":15319,"children":15320},{"style":332},[15321],{"type":291,"value":391},{"type":281,"tag":319,"props":15323,"children":15324},{"style":365},[15325],{"type":291,"value":14014},{"type":281,"tag":319,"props":15327,"children":15328},{"class":321,"line":973},[15329,15333],{"type":281,"tag":319,"props":15330,"children":15331},{"style":332},[15332],{"type":291,"value":391},{"type":281,"tag":319,"props":15334,"children":15335},{"style":365},[15336],{"type":291,"value":14027},{"type":281,"tag":319,"props":15338,"children":15340},{"class":15339,"line":986},[321,385],[15341,15345],{"type":281,"tag":319,"props":15342,"children":15343},{"style":332},[15344],{"type":291,"value":391},{"type":281,"tag":319,"props":15346,"children":15347},{"style":365},[15348],{"type":291,"value":15349},"\"traefik.http.routers.container-registry.rule=Host(`gitlab.example.com`)\"\n",{"type":281,"tag":319,"props":15351,"children":15353},{"class":15352,"line":999},[321,385],[15354,15358],{"type":281,"tag":319,"props":15355,"children":15356},{"style":332},[15357],{"type":291,"value":391},{"type":281,"tag":319,"props":15359,"children":15360},{"style":365},[15361],{"type":291,"value":15362},"\"traefik.http.routers.container-registry.entrypoints=container-registry\"\n",{"type":281,"tag":319,"props":15364,"children":15366},{"class":15365,"line":1012},[321,385],[15367,15371],{"type":281,"tag":319,"props":15368,"children":15369},{"style":332},[15370],{"type":291,"value":391},{"type":281,"tag":319,"props":15372,"children":15373},{"style":365},[15374],{"type":291,"value":15375},"\"traefik.http.routers.container-registry.service=container-registry\"\n",{"type":281,"tag":319,"props":15377,"children":15379},{"class":15378,"line":1025},[321,385],[15380,15384],{"type":281,"tag":319,"props":15381,"children":15382},{"style":332},[15383],{"type":291,"value":391},{"type":281,"tag":319,"props":15385,"children":15386},{"style":365},[15387],{"type":291,"value":14523},{"type":281,"tag":319,"props":15389,"children":15390},{"class":321,"line":1038},[15391,15395,15399],{"type":281,"tag":319,"props":15392,"children":15393},{"style":326},[15394],{"type":291,"value":928},{"type":281,"tag":319,"props":15396,"children":15397},{"style":332},[15398],{"type":291,"value":362},{"type":281,"tag":319,"props":15400,"children":15401},{"style":365},[15402],{"type":291,"value":937},{"type":281,"tag":319,"props":15404,"children":15405},{"class":321,"line":1048},[15406,15410,15414],{"type":281,"tag":319,"props":15407,"children":15408},{"style":326},[15409],{"type":291,"value":12872},{"type":281,"tag":319,"props":15411,"children":15412},{"style":332},[15413],{"type":291,"value":362},{"type":281,"tag":319,"props":15415,"children":15416},{"style":365},[15417],{"type":291,"value":14058},{"type":281,"tag":319,"props":15419,"children":15420},{"class":321,"line":1061},[15421,15425],{"type":281,"tag":319,"props":15422,"children":15423},{"style":326},[15424],{"type":291,"value":9689},{"type":281,"tag":319,"props":15426,"children":15427},{"style":332},[15428],{"type":291,"value":335},{"type":281,"tag":319,"props":15430,"children":15431},{"class":321,"line":1074},[15432,15436,15440],{"type":281,"tag":319,"props":15433,"children":15434},{"style":326},[15435],{"type":291,"value":12900},{"type":281,"tag":319,"props":15437,"children":15438},{"style":332},[15439],{"type":291,"value":362},{"type":281,"tag":319,"props":15441,"children":15442},{"style":7965},[15443],{"type":291,"value":12909},{"type":281,"tag":319,"props":15445,"children":15446},{"class":321,"line":1083},[15447],{"type":281,"tag":319,"props":15448,"children":15449},{"style":365},[15450],{"type":291,"value":12917},{"type":281,"tag":319,"props":15452,"children":15453},{"class":321,"line":1096},[15454],{"type":281,"tag":319,"props":15455,"children":15456},{"style":365},[15457],{"type":291,"value":14099},{"type":281,"tag":319,"props":15459,"children":15460},{"class":321,"line":1109},[15461],{"type":281,"tag":319,"props":15462,"children":15463},{"emptyLinePlaceholder":1042},[15464],{"type":291,"value":1045},{"type":281,"tag":319,"props":15466,"children":15467},{"class":321,"line":1122},[15468],{"type":281,"tag":319,"props":15469,"children":15470},{"style":365},[15471],{"type":291,"value":14116},{"type":281,"tag":319,"props":15473,"children":15474},{"class":321,"line":1130},[15475],{"type":281,"tag":319,"props":15476,"children":15477},{"emptyLinePlaceholder":1042},[15478],{"type":291,"value":1045},{"type":281,"tag":319,"props":15480,"children":15481},{"class":321,"line":1143},[15482],{"type":281,"tag":319,"props":15483,"children":15484},{"style":365},[15485],{"type":291,"value":14132},{"type":281,"tag":319,"props":15487,"children":15488},{"class":321,"line":1156},[15489],{"type":281,"tag":319,"props":15490,"children":15491},{"style":365},[15492],{"type":291,"value":14141},{"type":281,"tag":319,"props":15494,"children":15495},{"class":321,"line":1169},[15496],{"type":281,"tag":319,"props":15497,"children":15498},{"style":365},[15499],{"type":291,"value":14150},{"type":281,"tag":319,"props":15501,"children":15502},{"class":321,"line":1182},[15503],{"type":281,"tag":319,"props":15504,"children":15505},{"style":365},[15506],{"type":291,"value":14159},{"type":281,"tag":319,"props":15508,"children":15509},{"class":321,"line":1195},[15510],{"type":281,"tag":319,"props":15511,"children":15512},{"style":365},[15513],{"type":291,"value":14168},{"type":281,"tag":319,"props":15515,"children":15516},{"class":321,"line":2048},[15517],{"type":281,"tag":319,"props":15518,"children":15519},{"style":365},[15520],{"type":291,"value":6565},{"type":281,"tag":319,"props":15522,"children":15523},{"class":321,"line":2049},[15524],{"type":281,"tag":319,"props":15525,"children":15526},{"emptyLinePlaceholder":1042},[15527],{"type":291,"value":1045},{"type":281,"tag":319,"props":15529,"children":15530},{"class":321,"line":2050},[15531],{"type":281,"tag":319,"props":15532,"children":15533},{"style":365},[15534],{"type":291,"value":14192},{"type":281,"tag":319,"props":15536,"children":15537},{"class":321,"line":2051},[15538],{"type":281,"tag":319,"props":15539,"children":15540},{"emptyLinePlaceholder":1042},[15541],{"type":291,"value":1045},{"type":281,"tag":319,"props":15543,"children":15545},{"class":15544,"line":2052},[321,385],[15546],{"type":281,"tag":319,"props":15547,"children":15548},{"style":365},[15549],{"type":291,"value":15550},"        registry_external_url '\u003Chttps://gitlab.example.com:5050>'\n",{"type":281,"tag":319,"props":15552,"children":15553},{"class":321,"line":2053},[15554],{"type":281,"tag":319,"props":15555,"children":15556},{"style":365},[15557],{"type":291,"value":14695},{"type":281,"tag":319,"props":15559,"children":15560},{"class":321,"line":2054},[15561,15565],{"type":281,"tag":319,"props":15562,"children":15563},{"style":326},[15564],{"type":291,"value":12933},{"type":281,"tag":319,"props":15566,"children":15567},{"style":332},[15568],{"type":291,"value":335},{"type":281,"tag":319,"props":15570,"children":15571},{"class":321,"line":2055},[15572,15576],{"type":281,"tag":319,"props":15573,"children":15574},{"style":332},[15575],{"type":291,"value":391},{"type":281,"tag":319,"props":15577,"children":15578},{"style":365},[15579],{"type":291,"value":14216},{"type":281,"tag":319,"props":15581,"children":15582},{"class":321,"line":2579},[15583,15587],{"type":281,"tag":319,"props":15584,"children":15585},{"style":326},[15586],{"type":291,"value":1175},{"type":281,"tag":319,"props":15588,"children":15589},{"style":332},[15590],{"type":291,"value":335},{"type":281,"tag":319,"props":15592,"children":15593},{"class":321,"line":2056},[15594,15598],{"type":281,"tag":319,"props":15595,"children":15596},{"style":332},[15597],{"type":291,"value":391},{"type":281,"tag":319,"props":15599,"children":15600},{"style":365},[15601],{"type":291,"value":12996},{"type":281,"tag":319,"props":15603,"children":15604},{"class":321,"line":2605},[15605,15609],{"type":281,"tag":319,"props":15606,"children":15607},{"style":332},[15608],{"type":291,"value":391},{"type":281,"tag":319,"props":15610,"children":15611},{"style":365},[15612],{"type":291,"value":13008},{"type":281,"tag":319,"props":15614,"children":15615},{"class":321,"line":2613},[15616,15620],{"type":281,"tag":319,"props":15617,"children":15618},{"style":332},[15619],{"type":291,"value":391},{"type":281,"tag":319,"props":15621,"children":15622},{"style":365},[15623],{"type":291,"value":13020},{"type":281,"tag":319,"props":15625,"children":15626},{"class":321,"line":2626},[15627,15631,15635],{"type":281,"tag":319,"props":15628,"children":15629},{"style":326},[15630],{"type":291,"value":13028},{"type":281,"tag":319,"props":15632,"children":15633},{"style":332},[15634],{"type":291,"value":362},{"type":281,"tag":319,"props":15636,"children":15637},{"style":365},[15638],{"type":291,"value":13037},{"type":281,"tag":282,"props":15640,"children":15641},{},[15642],{"type":291,"value":13795},{"type":281,"tag":455,"props":15644,"children":15645},{},[15646,15650,15654],{"type":281,"tag":459,"props":15647,"children":15648},{},[15649],{"type":291,"value":14788},{"type":281,"tag":459,"props":15651,"children":15652},{},[15653],{"type":291,"value":14793},{"type":281,"tag":459,"props":15655,"children":15656},{},[15657],{"type":291,"value":15658},"instruct Traefik to route all traffic from port 5050 to port 5000 of the container",{"type":281,"tag":1477,"props":15660,"children":15661},{},[15662],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":15664},[15665,15666],{"id":12773,"depth":338,"text":12776},{"id":13045,"depth":338,"text":13048,"children":15667},[15668,15669,15670],{"id":13165,"depth":351,"text":13168},{"id":13415,"depth":351,"text":13418},{"id":14335,"depth":351,"text":14338},{"_path":111,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":112,"description":113,"author":86,"image":87,"releaseDate":114,"blogCategories":15672,"articleTags":15673,"tags":15674,"body":15675,"_type":20,"_id":118,"_source":22,"_file":119,"_stem":120,"_extension":25},[15],[92],[94],{"type":278,"children":15676,"toc":16937},[15677,15682,15699,15705,15726,15738,15744,15769,15853,15856,15882,15962,15967,15973,16005,16028,16034,16056,16148,16151,16189,16195,16207,16232,16261,16267,16296,16307,16338,16344,16349,16360,16370,16380,16386,16412,16477,16537,16554,16578,16621,16627,16639,16862,16868,16900,16928],{"type":281,"tag":1499,"props":15678,"children":15681},{"alt":15679,"aspect-ratio":11267,"height":1502,"object-fit":1503,"src":15680},"A woman with a prosthetic hand on her right arm is sitting at a laptop","/blog/digital-accessibility-with-prosthetic-hand.jpg",[],{"type":281,"tag":319,"props":15683,"children":15686},{"className":15684},[11364,15685],"text-caption",[15687],{"type":281,"tag":282,"props":15688,"children":15689},{},[15690],{"type":281,"tag":11370,"props":15691,"children":15692},{},[15693],{"type":281,"tag":286,"props":15694,"children":15696},{"href":15695},"https://www.pexels.com/photo/a-woman-using-a-laptop-5614124/",[15697],{"type":291,"value":15698},"Photo by Anna Shvets",{"type":281,"tag":530,"props":15700,"children":15702},{"id":15701},"accessibility-will-become-mandatory-what-the-accessibility-empowerment-act-means-for-digital-services-from-2025",[15703],{"type":291,"value":15704},"Accessibility will become mandatory: What the Accessibility Empowerment Act means for digital services from 2025",{"type":281,"tag":282,"props":15706,"children":15707},{},[15708,15710,15716,15718,15724],{"type":291,"value":15709},"From 28 June 2025, the German Accessibility Empowerment Act (BFSG) will come into effect\n",{"type":281,"tag":286,"props":15711,"children":15713},{"href":15712},"https://www.bildungsserver.de/onlineressource.html?onlineressourcen_id=65777#:~:text=Am%2022,Bundesfachstelle%20Barrierefreiheit%20bietet%20auf%20dieser",[15714],{"type":291,"value":15715},"bildungsserver.de",{"type":291,"value":15717},"\n. This law obliges private companies for the first time to offer certain digital products and services in an accessible format\n",{"type":281,"tag":286,"props":15719,"children":15721},{"href":15720},"https://www.visionbites.de/blog/barrierefreie-websites-bfsg-bitv-20-oder-wcag#:~:text=Ab%20dem%2028,W3C%C2%A0in%20den%C2%A0Konformit%C3%A4tsstufen%20A%20und%20AA",[15722],{"type":291,"value":15723},"visionbites.de",{"type":291,"value":15725},".\nBut who does this affect specifically, what does \"accessible\" mean in this context – and how can you implement this without the costs skyrocketing? In this blog article, we would like to shed some light on the new requirements.",{"type":281,"tag":319,"props":15727,"children":15729},{"className":15728},[11364],[15730],{"type":281,"tag":282,"props":15731,"children":15732},{},[15733],{"type":281,"tag":11370,"props":15734,"children":15735},{},[15736],{"type":291,"value":15737},"Reading duration: approx. 15 minutes",{"type":281,"tag":1248,"props":15739,"children":15741},{"id":15740},"who-does-the-law-affect-scope-of-application-from-july-2025",[15742],{"type":291,"value":15743},"Who does the law affect? – Scope of application from July 2025",{"type":281,"tag":282,"props":15745,"children":15746},{},[15747,15749,15753,15755,15761,15763,15766],{"type":291,"value":15748},"The BFSG implements the EU directive on accessibility requirements (European Accessibility Act, EAA) into German law. It comes into force on 28 June 2025\n",{"type":281,"tag":286,"props":15750,"children":15751},{"href":15712},[15752],{"type":291,"value":15715},{"type":291,"value":15754},"\n. From then on, the products and services mentioned therein must be provided barrier-free for consumers. However, not every web presence is automatically included! The law conclusively specifies the affected areas (§1 para. 2 and 3 BFSG)",{"type":281,"tag":286,"props":15756,"children":15758},{"href":15757},"https://www.bundesfachstelle-barrierefreiheit.de/SharedDocs/Downloads/DE/Externe-Veroeffentlichungen/bmas-leitlinien-bfsg.pdf?__blob=publicationFile#:~:text=des%20BFSG%20erf%C3%BCllen%20muss%2C%20findet,seine%20Produkte%20und%20Dienstleistungen%20freiwillig",[15759],{"type":291,"value":15760},"bundesfachstelle-barrierefreiheit.de",{"type":291,"value":15762},". From now on, the following digital services are subject to mandatory accessibility:\n",{"type":281,"tag":1314,"props":15764,"children":15765},{},[],{"type":281,"tag":1314,"props":15767,"children":15768},{},[],{"type":281,"tag":455,"props":15770,"children":15771},{},[15772,15804,15814,15824,15833,15843],{"type":281,"tag":459,"props":15773,"children":15774},{},[15775,15780,15782,15788,15790,15795,15797,15802],{"type":281,"tag":11280,"props":15776,"children":15777},{},[15778],{"type":291,"value":15779},"Electronic commerce",{"type":291,"value":15781}," – in other words, online services that facilitate the conclusion of consumer contracts, e.g., online shops ",{"type":281,"tag":286,"props":15783,"children":15785},{"href":15784},"https://www.hwk-dresden.de/recht/aktuelle-themen/detail/barrierefreiheitsstaerkungsgesetz-barrierefreiheit-von-online-shops.html#:~:text=Betreiber%20eines%20Online,Erschwernis%20die%20Onlineangebote%20nutzen%20k%C3%B6nnen",[15786],{"type":291,"value":15787},"hwk-dresden.de",{"type":291,"value":15789},". (",{"type":281,"tag":11280,"props":15791,"children":15792},{},[15793],{"type":291,"value":15794},"B2B shops",{"type":291,"value":15796},", which serve only business customers, are not covered by the mandatory requirement ",{"type":281,"tag":286,"props":15798,"children":15800},{"href":15799},"https://www.hwk-dresden.de/recht/aktuelle-themen/detail/barrierefreiheitsstaerkungsgesetz-barrierefreiheit-von-online-shops.html#:~:text=Ausnahmen%3A",[15801],{"type":291,"value":15787},{"type":291,"value":15803},".)",{"type":281,"tag":459,"props":15805,"children":15806},{},[15807,15812],{"type":281,"tag":11280,"props":15808,"children":15809},{},[15810],{"type":291,"value":15811},"Consumer banking services",{"type":291,"value":15813}," – in particular, online banking websites and banking apps.",{"type":281,"tag":459,"props":15815,"children":15816},{},[15817,15822],{"type":281,"tag":11280,"props":15818,"children":15819},{},[15820],{"type":291,"value":15821},"Telecommunication services",{"type":291,"value":15823}," – for example, phone and messaging apps.",{"type":281,"tag":459,"props":15825,"children":15826},{},[15827,15832],{"type":281,"tag":11280,"props":15828,"children":15829},{},[15830],{"type":291,"value":15831},"E-books and their respective distribution platforms",{"type":291,"value":564},{"type":281,"tag":459,"props":15834,"children":15835},{},[15836,15841],{"type":281,"tag":11280,"props":15837,"children":15838},{},[15839],{"type":291,"value":15840},"Passenger transport services",{"type":291,"value":15842}," – for instance, digital ticket machines in public transport.",{"type":281,"tag":459,"props":15844,"children":15845},{},[15846,15851],{"type":281,"tag":11280,"props":15847,"children":15848},{},[15849],{"type":291,"value":15850},"Mobile apps in passenger transport",{"type":291,"value":15852}," – such as apps from railway or airline companies.",{"type":281,"tag":1314,"props":15854,"children":15855},{},[],{"type":281,"tag":282,"props":15857,"children":15858},{},[15859,15861,15866,15868,15873,15875,15880],{"type":291,"value":15860},"Also, various ",{"type":281,"tag":11280,"props":15862,"children":15863},{},[15864],{"type":291,"value":15865},"products",{"type":291,"value":15867}," must be barrier-free from 2025, including computers, smartphones, ticket and cash machines, or smart TVs\n",{"type":281,"tag":286,"props":15869,"children":15871},{"href":15870},"https://www.bundesfachstelle-barrierefreiheit.de/DE/Fachwissen/Produkte-und-Dienstleistungen/Barrierefreiheitsstaerkungsgesetz/barrierefreiheitsstaerkungsgesetz_node.html",[15872],{"type":291,"value":15760},{"type":291,"value":15874},".\nFor most of our customers (SMEs with web applications), it is especially crucial to understand that ",{"type":281,"tag":11280,"props":15876,"children":15877},{},[15878],{"type":291,"value":15879},"your consumer-facing online service must be barrier-free by July 2025",{"type":291,"value":15881},", provided it falls into one of the above categories.",{"type":281,"tag":282,"props":15883,"children":15884},{},[15885,15887,15892,15894,15899,15901,15906,15908,15913,15918,15920,15925,15926,15931,15933,15938,15940,15945,15947,15952,15956,15961],{"type":291,"value":15886},"However, there is an ",{"type":281,"tag":11370,"props":15888,"children":15889},{},[15890],{"type":291,"value":15891},"exception",{"type":291,"value":15893}," for ",{"type":281,"tag":11280,"props":15895,"children":15896},{},[15897],{"type":291,"value":15898},"micro-enterprises",{"type":291,"value":15900},"! Companies with ",{"type":281,"tag":11280,"props":15902,"children":15903},{},[15904],{"type":291,"value":15905},"fewer than 10 employees and a maximum €2 million annual turnover",{"type":291,"value":15907}," are ",{"type":281,"tag":11280,"props":15909,"children":15910},{},[15911],{"type":291,"value":15912},"exempt from the BFSG requirements if they provide services",{"type":281,"tag":286,"props":15914,"children":15916},{"href":15915},"https://www.bundesfachstelle-barrierefreiheit.de/DE/Fachwissen/Produkte-und-Dienstleistungen/Barrierefreiheitsstaerkungsgesetz/barrierefreiheitsstaerkungsgesetz_node.html#:~:text=Unter%20das%20Barrierefreiheitsst%C3%A4rkungsgesetz%20fallen%20Hersteller%2C,fallen%20jedoch%20unter%20das%20BFSG",[15917],{"type":291,"value":15760},{"type":291,"value":15919},".\nA mini start-up that operates an online shop does not necessarily have to retrofit formally\n",{"type":281,"tag":286,"props":15921,"children":15923},{"href":15922},"https://www.hwk-dresden.de/recht/aktuelle-themen/detail/barrierefreiheitsstaerkungsgesetz-barrierefreiheit-von-online-shops.html#:~:text=Beim%20Angebot%20von%20Dienstleistungen%20im,h%C3%B6chstens%202%20Millionen%20Euro%20bel%C3%A4uft",[15924],{"type":291,"value":15787},{"type":291,"value":9457},{"type":281,"tag":11280,"props":15927,"children":15928},{},[15929],{"type":291,"value":15930},"Caution:",{"type":291,"value":15932}," This exception applies ",{"type":281,"tag":11280,"props":15934,"children":15935},{},[15936],{"type":291,"value":15937},"only to services",{"type":291,"value":15939},"! Micro-enterprises that ",{"type":281,"tag":11280,"props":15941,"children":15942},{},[15943],{"type":291,"value":15944},"introduce products",{"type":291,"value":15946}," (e.g., hardware such as special reading devices) onto the market, ",{"type":281,"tag":11280,"props":15948,"children":15949},{},[15950],{"type":291,"value":15951},"still fall under the BFSG",{"type":281,"tag":286,"props":15953,"children":15954},{"href":15915},[15955],{"type":291,"value":15760},{"type":281,"tag":286,"props":15957,"children":15959},{"href":15958},"https://www.hwk-dresden.de/recht/aktuelle-themen/detail/barrierefreiheitsstaerkungsgesetz-barrierefreiheit-von-online-shops.html#:~:text=bel%C3%A4uft",[15960],{"type":291,"value":15787},{"type":291,"value":564},{"type":281,"tag":282,"props":15963,"children":15964},{},[15965],{"type":291,"value":15966},"And let's be honest – even if you are narrowly exempt from the requirement, it still pays off to implement accessibility voluntarily to rule out excluding potential customers and to be prepared for future requirements.",{"type":281,"tag":12690,"props":15968,"children":15970},{"id":15969},"what-exactly-does-barrier-free-mean",[15971],{"type":291,"value":15972},"What exactly does \"barrier-free\" mean?",{"type":281,"tag":282,"props":15974,"children":15975},{},[15976,15978,15983,15985,15989,15991,15996,15998,16003],{"type":291,"value":15977},"According to the common definition, offers are barrier-free if they are findable, accessible, and usable for people with disabilities in the usual way, without particular difficulty, and basically without the help of others\n",{"type":281,"tag":286,"props":15979,"children":15981},{"href":15980},"https://www.hwk-dresden.de/recht/aktuelle-themen/detail/barrierefreiheitsstaerkungsgesetz-barrierefreiheit-von-online-shops.html#:~:text=Barrierefreiheit%20wird%20gew%C3%A4hrleistet%2C%20wenn%20Produkte,auffindbar%2C%20zug%C3%A4nglich%20und%20nutzbar%20sind",[15982],{"type":291,"value":15787},{"type":291,"value":15984},".\nIn the web area, this specifically means: for example, a website must also be operable via a screen reader (reading software) or solely with the keyboard; there must be no hurdles for visually impaired, hearing-impaired, motor or cognitively challenged people. Technically, the requirements in the ",{"type":281,"tag":11370,"props":15986,"children":15987},{},[15988],{"type":291,"value":12734},{"type":291,"value":15990}," are based on the European ",{"type":281,"tag":11370,"props":15992,"children":15993},{},[15994],{"type":291,"value":15995},"Standard EN 301 549",{"type":291,"value":15997},", which in turn refers to the ",{"type":281,"tag":11370,"props":15999,"children":16000},{},[16001],{"type":291,"value":16002},"Web Content Accessibility Guidelines (WCAG) 2.1",{"type":291,"value":16004}," at level AA.",{"type":281,"tag":282,"props":16006,"children":16007},{},[16008,16010,16015,16017,16021,16023,16027],{"type":291,"value":16009},"This means, if you fulfill the success criteria of WCAG 2.1 AA, you are safe. Public bodies are already familiar with these standards from the ",{"type":281,"tag":11370,"props":16011,"children":16012},{},[16013],{"type":291,"value":16014},"BITV 2.0 (Barrierefreie-Informationstechnik-Verordnung)",{"type":291,"value":16016},", which has been applicable to public authority websites since 2018 – there, additional content in easy language and sign language is also required.\nFor private providers, the ",{"type":281,"tag":11370,"props":16018,"children":16019},{},[16020],{"type":291,"value":12734},{"type":291,"value":16022}," essentially calls for ",{"type":281,"tag":11280,"props":16024,"children":16025},{},[16026],{"type":291,"value":11421},{"type":291,"value":564},{"type":281,"tag":530,"props":16029,"children":16031},{"id":16030},"what-deadlines-and-consequences-apply-transition-periods-and-penalties",[16032],{"type":291,"value":16033},"What deadlines and consequences apply? - Transition periods and penalties",{"type":281,"tag":282,"props":16035,"children":16036},{},[16037,16042,16044,16049,16050,16053],{"type":281,"tag":11280,"props":16038,"children":16039},{},[16040],{"type":291,"value":16041},"Key date 28.06.2025:",{"type":291,"value":16043}," From this date, new products and services must be compliant. However, the law provides for a few transition periods. It is important to know that ",{"type":281,"tag":11280,"props":16045,"children":16046},{},[16047],{"type":291,"value":16048},"existing contracts and systems are given partial extensions",{"type":291,"value":335},{"type":281,"tag":1314,"props":16051,"children":16052},{},[],{"type":281,"tag":1314,"props":16054,"children":16055},{},[],{"type":281,"tag":455,"props":16057,"children":16058},{},[16059,16108,16130],{"type":281,"tag":459,"props":16060,"children":16061},{},[16062,16067,16069,16074,16076,16081,16083,16086,16092,16095,16100,16102,16107],{"type":281,"tag":11280,"props":16063,"children":16064},{},[16065],{"type":291,"value":16066},"Ongoing services:",{"type":291,"value":16068}," If a long-term contract was concluded ",{"type":281,"tag":11280,"props":16070,"children":16071},{},[16072],{"type":291,"value":16073},"before 28.06.2025",{"type":291,"value":16075}," and it is continued without changes, the provider has until ",{"type":281,"tag":11280,"props":16077,"children":16078},{},[16079],{"type":291,"value":16080},"27.06.2030",{"type":291,"value":16082}," to make the service accessible",{"type":281,"tag":1314,"props":16084,"children":16085},{},[],{"type":281,"tag":286,"props":16087,"children":16089},{"href":16088},"https://www.bfsg-barrierefreiheitsstaerkungsgesetz.de/#:~:text=Laut%20BMAS%20gilt%20die%20%C3%9Cbergangsfrist,und%20nur%20in%20zwei%20F%C3%A4llen",[16090],{"type":291,"value":16091},"bfsg-barrierefreiheitsstaerkungsgesetz.de",{"type":281,"tag":1314,"props":16093,"children":16094},{},[],{"type":281,"tag":11370,"props":16096,"children":16097},{},[16098],{"type":291,"value":16099},"Example:",{"type":291,"value":16101}," An online banking system that has been in operation for years and is used by existing customers should be converted by 2030 at the latest – ",{"type":281,"tag":11280,"props":16103,"children":16104},{},[16105],{"type":291,"value":16106},"but new offers must be accessible immediately from 2025",{"type":291,"value":564},{"type":281,"tag":459,"props":16109,"children":16110},{},[16111,16116,16118,16123,16125,16129],{"type":281,"tag":11280,"props":16112,"children":16113},{},[16114],{"type":291,"value":16115},"Older technology in use:",{"type":291,"value":16117}," If a service uses a product that was already ",{"type":281,"tag":11280,"props":16119,"children":16120},{},[16121],{"type":291,"value":16122},"in use before June 2025",{"type":291,"value":16124},"\n(e.g., an existing self-service terminal), the deadline until 2030 also applies\n",{"type":281,"tag":286,"props":16126,"children":16127},{"href":16088},[16128],{"type":291,"value":16091},{"type":291,"value":564},{"type":281,"tag":459,"props":16131,"children":16132},{},[16133,16138,16140,16143],{"type":281,"tag":11280,"props":16134,"children":16135},{},[16136],{"type":291,"value":16137},"Self-Service Terminals:",{"type":291,"value":16139}," The law allows 15\nyears transition time for ATMs, ticket machines & similar that already exist. These may continue to be used until 2040 before they must be replaced or retrofitted",{"type":281,"tag":1314,"props":16141,"children":16142},{},[],{"type":281,"tag":286,"props":16144,"children":16146},{"href":16145},"https://www.bundesfachstelle-barrierefreiheit.de/DE/Fachwissen/Produkte-und-Dienstleistungen/Barrierefreiheitsstaerkungsgesetz/barrierefreiheitsstaerkungsgesetz_node.html#:~:text=F%C3%BCr%20einige%20Produkte%20und%20Dienstleistungen,eine%20%C3%9Cbergangsfrist%20von%2015%20Jahren",[16147],{"type":291,"value":15760},{"type":281,"tag":1314,"props":16149,"children":16150},{},[],{"type":281,"tag":282,"props":16152,"children":16153},{},[16154,16159,16161,16166,16168,16173,16175,16180,16182,16187],{"type":281,"tag":11280,"props":16155,"children":16156},{},[16157],{"type":291,"value":16158},"Important:",{"type":291,"value":16160}," However, as soon as a provider ",{"type":281,"tag":11280,"props":16162,"children":16163},{},[16164],{"type":291,"value":16165},"significantly revises an existing service",{"type":291,"value":16167}," or closes a ",{"type":281,"tag":11280,"props":16169,"children":16170},{},[16171],{"type":291,"value":16172},"new contract",{"type":291,"value":16174},"\nwith a consumer ",{"type":281,"tag":11280,"props":16176,"children":16177},{},[16178],{"type":291,"value":16179},"after June 2025",{"type":291,"value":16181},", the current parts must be accessible – so you can't\ndemand another 5 years extension for updates\n",{"type":281,"tag":286,"props":16183,"children":16185},{"href":16184},"https://www.bfsg-barrierefreiheitsstaerkungsgesetz.de/#:~:text=match%20at%20L720%20gr%C3%B6%C3%9Feren%20Updates,sie%20m%C3%BCssen%20sofort%20barrierefrei%20sein",[16186],{"type":291,"value":16091},{"type":291,"value":16188},".\nThe transition periods are intended as a grace period for old stocks, not as a loophole for prolongation.",{"type":281,"tag":1248,"props":16190,"children":16192},{"id":16191},"control-and-sanctions",[16193],{"type":291,"value":16194},"Control and Sanctions",{"type":281,"tag":282,"props":16196,"children":16197},{},[16198,16200,16205],{"type":291,"value":16199},"Compliance is checked by market supervision authorities. In the event of violations, there are first warnings to improve and finally severe measures. In extreme cases, the authority can order that a non-accessible online service is taken off the market or shut down\n",{"type":281,"tag":286,"props":16201,"children":16203},{"href":16202},"https://www.bundesfachstelle-barrierefreiheit.de/SharedDocs/Downloads/DE/Externe-Veroeffentlichungen/bmas-leitlinien-bfsg.pdf?__blob=publicationFile#:~:text=Kommt%20der%20Dienstleistungserbringer%20dieser%20Aufforderung,so%20ergreift%20die%20Markt%C3%BCberwachungsbeh%C3%B6rde%20die",[16204],{"type":291,"value":15760},{"type":291,"value":16206},"!",{"type":281,"tag":282,"props":16208,"children":16209},{},[16210,16212,16216,16218,16223,16225,16230],{"type":291,"value":16211},"Additionally, fines can be levied – the ",{"type":281,"tag":11370,"props":16213,"children":16214},{},[16215],{"type":291,"value":12734},{"type":291,"value":16217}," proposes amounts ",{"type":281,"tag":11280,"props":16219,"children":16220},{},[16221],{"type":291,"value":16222},"up to 100,000 Euros",{"type":291,"value":16224}," depending on the violation\n",{"type":281,"tag":286,"props":16226,"children":16228},{"href":16227},"https://www.bundesfachstelle-barrierefreiheit.de/SharedDocs/Downloads/DE/Externe-Veroeffentlichungen/bmas-leitlinien-bfsg.pdf?__blob=publicationFile#:~:text=Bu%C3%9Fgeld%20von%20bis%20zu%20100,innen%20und%20Verb%C3%A4nde",[16229],{"type":291,"value":15760},{"type":291,"value":16231},".\nAlso, consumers and associations have rights - they can criticize deficiencies and (similar to AGG violations) exert legal pressure if necessary. Therefore, the issue should be taken seriously. Those who continue as before from 2025 risk damage to their image, complaints, and in the worst case loss of sales.",{"type":281,"tag":282,"props":16233,"children":16234},{},[16235,16237,16242,16244,16247,16252,16254,16259],{"type":291,"value":16236},"In addition to the duty of accessibility, the law also requires companies to produce bureaucratic proofs. For each product or service, a declaration of conformity or technical documentation must be created, describing how the requirements are met\n",{"type":281,"tag":286,"props":16238,"children":16240},{"href":16239},"https://www.bfsg-barrierefreiheitsstaerkungsgesetz.de/#:~:text=F%C3%BCr%20jedes%20Produkt%20und%20jede,wie%20die%20Barrierefreiheitsanforderungen%20erf%C3%BCllt%20werden",[16241],{"type":291,"value":16091},{"type":291,"value":16243},".\nService providers must also easily provide information (e.g. on the website or in terms and conditions) and indicate which market surveillance authority is responsible",{"type":281,"tag":1314,"props":16245,"children":16246},{},[],{"type":281,"tag":286,"props":16248,"children":16250},{"href":16249},"https://www.bfsg-barrierefreiheitsstaerkungsgesetz.de/#:~:text=Dienstleister%20m%C3%BCssen%20Informationen%20%C3%BCber%20ihre,werden%20und%20folgende%20Elemente%20enthalten",[16251],{"type":291,"value":16091},{"type":291,"value":16253},".\nIn practice, this should run analogously to the official accessibility statement which is already known from public websites – a section ",{"type":281,"tag":11280,"props":16255,"children":16256},{},[16257],{"type":291,"value":16258},"\"Accessibility Statement\"",{"type":291,"value":16260}," with information about the implementation status, contact options for feedback and a reference to the enforcement office.",{"type":281,"tag":530,"props":16262,"children":16264},{"id":16263},"plan-for-accessibility-early-vs-implement-it-later-the-cost-comparison",[16265],{"type":291,"value":16266},"Plan for accessibility early vs. implement it later - the cost comparison",{"type":281,"tag":282,"props":16268,"children":16269},{},[16270,16272,16277,16279,16284,16286,16289,16295],{"type":291,"value":16271},"A frequently heard concern is: ",{"type":281,"tag":11370,"props":16273,"children":16274},{},[16275],{"type":291,"value":16276},"\"Will it not become incredibly expensive?\"",{"type":291,"value":16278},"\nThe good news is, if you consider accessibility from the start, the additional effort is significantly reduced.\nA study on Barrier-free Building found that a building planned to be barrier-free from the beginning only causes about 1% additional costs\n",{"type":281,"tag":286,"props":16280,"children":16282},{"href":16281},"https://www.bundesfachstelle-barrierefreiheit.de/SharedDocs/Kurzmeldungen/DE/barrierefreies-bauen-neubau-verursacht-kaum-mehrkosten.html#:~:text=Die%20Studie%20von%20Terrogon%20und,durch%20einen%20Umbau%20zu%20realisieren",[16283],{"type":291,"value":15760},{"type":291,"value":16285},"\n– and the same is true for software projects. Designing control functions to be barrier-free from the start is basically no more complex than developing them with barriers",{"type":281,"tag":1314,"props":16287,"children":16288},{},[],{"type":281,"tag":286,"props":16290,"children":16292},{"href":16291},"https://www.aktion-mensch.de/inklusion/barrierefreiheit/barrierefreie-website/kosten-barrierefreie-website#:~:text=Denken%20Sie%20Barrierefreiheit%20von%20Anfang,mit",[16293],{"type":291,"value":16294},"aktion-mensch.de",{"type":291,"value":564},{"type":281,"tag":282,"props":16297,"children":16298},{},[16299],{"type":281,"tag":11370,"props":16300,"children":16301},{},[16302],{"type":281,"tag":11280,"props":16303,"children":16304},{},[16305],{"type":291,"value":16306},"Whether a developer codes a contact form to be accessible or with unnecessary barriers hardly makes a difference, as long as the end goal is known!",{"type":281,"tag":282,"props":16308,"children":16309},{},[16310,16312,16317,16318,16323,16324,16329,16331,16336],{"type":291,"value":16311},"The right mindset in the team is key. If ",{"type":281,"tag":11280,"props":16313,"children":16314},{},[16315],{"type":291,"value":16316},"UX designers",{"type":291,"value":9822},{"type":281,"tag":11280,"props":16319,"children":16320},{},[16321],{"type":291,"value":16322},"developers",{"type":291,"value":12526},{"type":281,"tag":11280,"props":16325,"children":16326},{},[16327],{"type":291,"value":16328},"editors",{"type":291,"value":16330}," are trained and know from the start what matters, ",{"type":281,"tag":11370,"props":16332,"children":16333},{},[16334],{"type":291,"value":16335},"barrier-free websites",{"type":291,"value":16337}," will almost develop themselves. Many measures don't cost extra. For example, using well-planned heading structures and alternative texts from the start only requires a bit of attention but no additional budget!",{"type":281,"tag":1248,"props":16339,"children":16341},{"id":16340},"accessibility-usually-becomes-expensive-when-it-has-to-be-added-afterwards",[16342],{"type":291,"value":16343},"Accessibility usually becomes expensive when it has to be added afterwards.",{"type":281,"tag":282,"props":16345,"children":16346},{},[16347],{"type":291,"value":16348},"Suddenly, you discover that adjustments are needed in multiple places: images without alt text, poor color combinations in the design, interactive components that only work with a mouse, videos without subtitles, PDF documents without tags, etc. Each of these barriers requires analysis, design changes, further development, and testing – in short: additional project iterations which could have been avoided. The later in the development process these changes are made, the higher the cost. Experiences in IT (also from our own projects) show that fixing mistakes later on is multiple times more expensive than preventing them. It's the same with accessibility: \"Shift Left\" is the motto – start early in the process.",{"type":281,"tag":282,"props":16350,"children":16351},{},[16352],{"type":281,"tag":11370,"props":16353,"children":16354},{},[16355],{"type":281,"tag":11280,"props":16356,"children":16357},{},[16358],{"type":291,"value":16359},"If accessibility is an integral part of the project, the additional effort remains nominal –\nbut maintaining and retrofitting afterward can become quite expensive.",{"type":281,"tag":282,"props":16361,"children":16362},{},[16363,16368],{"type":281,"tag":11280,"props":16364,"children":16365},{},[16366],{"type":291,"value":16367},"An example from practice:",{"type":291,"value":16369}," A medium-sized company had its existing online shop checked for accessibility.\nMore than 50 individual problems were found, from missing form labels to unusable dropdown menus. The fixes required several developer sprints and sometimes major frontend restructuring – the cost: high four-digit figures. If these standards had been complied with from the start, almost none of these points would have arisen.\nAdditionally, there were opportunity costs, i.e., other features could not be developed during the revision.",{"type":281,"tag":282,"props":16371,"children":16372},{},[16373,16378],{"type":281,"tag":11280,"props":16374,"children":16375},{},[16376],{"type":291,"value":16377},"Our tip:",{"type":291,"value":16379}," Plan for accessibility from the beginning in new projects! The costs are manageable and\ncontribute to a better user experience for everyone!",{"type":281,"tag":530,"props":16381,"children":16383},{"id":16382},"how-to-make-it-barrier-free-tests-and-support-for-companies",[16384],{"type":291,"value":16385},"How to make it barrier-free: Tests and Support for Companies",{"type":281,"tag":282,"props":16387,"children":16388},{},[16389,16391,16396,16398,16403,16405,16410],{"type":291,"value":16390},"If you're now thinking ",{"type":281,"tag":11370,"props":16392,"children":16393},{},[16394],{"type":291,"value":16395},"“All well and good, but how do I actually determine if my website is accessible – and who will help me?”",{"type":291,"value":16397}," - don't worry, you don't have to reinvent the wheel. There are tried and tested ",{"type":281,"tag":11280,"props":16399,"children":16400},{},[16401],{"type":291,"value":16402},"testing procedures",{"type":291,"value":16404}," and many ",{"type":281,"tag":11280,"props":16406,"children":16407},{},[16408],{"type":291,"value":16409},"experts",{"type":291,"value":16411},", who assist companies on the path to accessibility.",{"type":281,"tag":282,"props":16413,"children":16414},{},[16415,16420,16422,16427,16429,16434,16436,16441,16443,16448,16450,16455,16457,16462,16463,16468,16470,16475],{"type":281,"tag":11280,"props":16416,"children":16417},{},[16418],{"type":291,"value":16419},"1. Self-check with tools:",{"type":291,"value":16421}," A good first step is a simple self-test. There are ",{"type":281,"tag":11280,"props":16423,"children":16424},{},[16425],{"type":291,"value":16426},"free testing tools",{"type":291,"value":16428}," available, with which you can identify typical problems. Popular ones are, for example, the ",{"type":281,"tag":11280,"props":16430,"children":16431},{},[16432],{"type":291,"value":16433},"WAVE Accessibility Checker",{"type":291,"value":16435}," (browser extension) or ",{"type":281,"tag":11280,"props":16437,"children":16438},{},[16439],{"type":291,"value":16440},"axe DevTools",{"type":291,"value":16442},", as well as ",{"type":281,"tag":11280,"props":16444,"children":16445},{},[16446],{"type":291,"value":16447},"Google Lighthouse",{"type":291,"value":16449}," (integrated in the Chrome browser). These tools analyze the website code and report, for example, missing alt texts, insufficient contrasts or forms without labels. It's important to know, however, that while automated tests find many ",{"type":281,"tag":11280,"props":16451,"children":16452},{},[16453],{"type":291,"value":16454},"technical",{"type":291,"value":16456}," barriers, they don't find everything and not everything they find is meaningful. Some criteria - such as ",{"type":281,"tag":11370,"props":16458,"children":16459},{},[16460],{"type":291,"value":16461},"whether alt texts make logical sense",{"type":291,"value":10825},{"type":281,"tag":11370,"props":16464,"children":16465},{},[16466],{"type":291,"value":16467},"whether the operation sequence is logical",{"type":291,"value":16469}," - can ",{"type":281,"tag":11280,"props":16471,"children":16472},{},[16473],{"type":291,"value":16474},"only be assessed by human testers",{"type":291,"value":16476},". Nevertheless, such a tool check is worth it. Within a few minutes, you can get a rough overview of quite obvious problem areas.",{"type":281,"tag":282,"props":16478,"children":16479},{},[16480,16485,16487,16492,16494,16502,16504,16508,16510,16514,16516,16521,16523,16528,16530,16535],{"type":281,"tag":11280,"props":16481,"children":16482},{},[16483],{"type":291,"value":16484},"2. Expert Audit (BITV-Test):",{"type":291,"value":16486}," For a reliable result, a ",{"type":281,"tag":11280,"props":16488,"children":16489},{},[16490],{"type":291,"value":16491},"manual inspection report",{"type":291,"value":16493}," by specialists is recommended. In Germany, the ",{"type":281,"tag":11370,"props":16495,"children":16496},{},[16497],{"type":281,"tag":11280,"props":16498,"children":16499},{},[16500],{"type":291,"value":16501},"BITV-Test",{"type":291,"value":16503}," has been established as the standard procedure. This test currently includes around 60 test steps, which are adapted to the ",{"type":281,"tag":11370,"props":16505,"children":16506},{},[16507],{"type":291,"value":11421},{"type":291,"value":16509}," and the legal requirements (",{"type":281,"tag":11370,"props":16511,"children":16512},{},[16513],{"type":291,"value":11795},{"type":291,"value":16515},"). It is carried out by trained auditors – many of them offer this service. The result is a detailed report that shows the strengths and weaknesses of the website and provides a percentage rating. For small websites, the effort is often in the range of a few person-days. According to ",{"type":281,"tag":11370,"props":16517,"children":16518},{},[16519],{"type":291,"value":16520},"Aktion Mensch",{"type":291,"value":16522},", the cost for a complete expert analysis varies between ",{"type":281,"tag":11280,"props":16524,"children":16525},{},[16526],{"type":291,"value":16527},"2,500 and 10,000 Euros",{"type":291,"value":16529},", depending on the volume (from simple page to complex online store)\n",{"type":281,"tag":286,"props":16531,"children":16533},{"href":16532},"https://www.aktion-mensch.de/inklusion/barrierefreiheit/barrierefreie-website/kosten-barrierefreie-website#:~:text=Mehr%20Budget%20brauchen%20Sie%20f%C3%BCr,000%20Euro%20rechnen",[16534],{"type":291,"value":16294},{"type":291,"value":16536},".\nThis is money well spent as you receive a clear to-do list to become legally compliant.",{"type":281,"tag":282,"props":16538,"children":16539},{},[16540,16545,16547,16552],{"type":281,"tag":11280,"props":16541,"children":16542},{},[16543],{"type":291,"value":16544},"3. User Feedback:",{"type":291,"value":16546}," Nothing replaces the practical test with real users. Ideally, a barrier-free site should be tried out by people with different disabilities – e.g. a blind user with a screen reader, someone with visual impairment and magnification software, someone with a motor impairment only using a keyboard, etc. These tests can be organized through specialized service providers or you can ask volunteers from your own environment. The findings are incredibly valuable. For instance, you can see where operation is difficult or confusing. Often this also reveals a general benefit for all (keyword ",{"type":281,"tag":11370,"props":16548,"children":16549},{},[16550],{"type":291,"value":16551},"Usability",{"type":291,"value":16553},"). For example, if a senior with tremor cannot tap the small dropdown, it is probably not optimally solved for many others as well – here, a simplified UI can make a huge difference.",{"type":281,"tag":282,"props":16555,"children":16556},{},[16557,16562,16564,16569,16571,16576],{"type":281,"tag":11280,"props":16558,"children":16559},{},[16560],{"type":291,"value":16561},"4. Support from agencies and consultants:",{"type":291,"value":16563}," If the know-how is lacking in-house, do not hesitate to engage ",{"type":281,"tag":11280,"props":16565,"children":16566},{},[16567],{"type":291,"value":16568},"external professionals",{"type":291,"value":16570},". There are consulting firms and agencies (like ours) with expertise in the field or even a focus on digital accessibility. Look for ",{"type":281,"tag":11280,"props":16572,"children":16573},{},[16574],{"type":291,"value":16575},"experience and qualification",{"type":291,"value":16577}," when choosing. Good service providers will prioritize with you what needs to be done, and they can also train your developers to ensure accessibility is sustainably anchored in the process.",{"type":281,"tag":282,"props":16579,"children":16580},{},[16581,16585,16587,16592,16594,16599,16601,16606,16608,16613,16615,16620],{"type":281,"tag":11280,"props":16582,"children":16583},{},[16584],{"type":291,"value":16377},{"type":291,"value":16586}," Start with a ",{"type":281,"tag":11280,"props":16588,"children":16589},{},[16590],{"type":291,"value":16591},"simple self-test",{"type":291,"value":16593}," to get a feel. Then, if necessary, get offers for a professional audit. The ",{"type":281,"tag":11280,"props":16595,"children":16596},{},[16597],{"type":291,"value":16598},"Knappschaft-Bahn-See",{"type":291,"value":16600}," or the ",{"type":281,"tag":11370,"props":16602,"children":16603},{},[16604],{"type":291,"value":16605},"Federal Specialist Agency for Accessibility",{"type":291,"value":16607}," (a governmental agency, supported by KBS), offers a lot of ",{"type":281,"tag":11280,"props":16609,"children":16610},{},[16611],{"type":291,"value":16612},"information and webinars",{"type":291,"value":16614},", which especially make it easier for e-commerce companies to get started\n",{"type":281,"tag":286,"props":16616,"children":16618},{"href":16617},"https://www.bundesfachstelle-barrierefreiheit.de/DE/Fachwissen/Produkte-und-Dienstleistungen/Barrierefreiheitsstaerkungsgesetz/barrierefreiheitsstaerkungsgesetz_node.html#:~:text=Die%20Bundesfachstelle%20Barrierefreiheit%20hat%20speziell,Reihe%20BFSG%202025",[16619],{"type":291,"value":15760},{"type":291,"value":564},{"type":281,"tag":530,"props":16622,"children":16624},{"id":16623},"misunderstandings-special-cases-and-myths-about-the-bfsg",[16625],{"type":291,"value":16626},"Misunderstandings, special cases and “myths” about the BFSG",{"type":281,"tag":282,"props":16628,"children":16629},{},[16630,16632,16637],{"type":291,"value":16631},"Several ",{"type":281,"tag":11280,"props":16633,"children":16634},{},[16635],{"type":291,"value":16636},"theories and uncertainties",{"type":291,"value":16638}," are circulating ahead of the coming into force that we would like to address here:",{"type":281,"tag":455,"props":16640,"children":16641},{},[16642,16733,16809],{"type":281,"tag":459,"props":16643,"children":16644},{},[16645,16646,16651,16653,16658,16660,16664,16666,16671,16673,16678,16680,16684,16686,16691,16693,16698,16700,16704,16706,16711,16713,16718,16720,16724,16726,16731],{"type":291,"value":5665},{"type":281,"tag":11280,"props":16647,"children":16648},{},[16649],{"type":291,"value":16650},"By 2025, all websites have to be accessible.",{"type":291,"value":16652},"\" – ",{"type":281,"tag":11370,"props":16654,"children":16655},{},[16656],{"type":291,"value":16657},"Not exactly.",{"type":291,"value":16659}," It is true that the ",{"type":281,"tag":11370,"props":16661,"children":16662},{},[16663],{"type":291,"value":12734},{"type":291,"value":16665}," will cover many private\nweb offers, but only ",{"type":281,"tag":11280,"props":16667,"children":16668},{},[16669],{"type":291,"value":16670},"certain categories",{"type":291,"value":16672},". A purely informational company website without an\nonline shop, for instance, that does not conclude contracts with consumers, is not ",{"type":281,"tag":11280,"props":16674,"children":16675},{},[16676],{"type":291,"value":16677},"directly covered",{"type":291,"value":16679}," by the law\n",{"type":281,"tag":286,"props":16681,"children":16682},{"href":15757},[16683],{"type":291,"value":15760},{"type":291,"value":16685},".\nBut that doesn't mean you should ignore it! Accessibility can bring competitive advantages and the legislature may ",{"type":281,"tag":11280,"props":16687,"children":16688},{},[16689],{"type":291,"value":16690},"expand",{"type":291,"value":16692}," its scope in the future.\nFor public websites of authorities, there has been an obligation (",{"type":281,"tag":11370,"props":16694,"children":16695},{},[16696],{"type":291,"value":16697},"BITV 2.0",{"type":291,"value":16699},") for years - the ",{"type":281,"tag":11370,"props":16701,"children":16702},{},[16703],{"type":291,"value":12734},{"type":291,"value":16705}," now closes\nthe big gap in the ",{"type":281,"tag":11280,"props":16707,"children":16708},{},[16709],{"type":291,"value":16710},"private sector",{"type":291,"value":16712}," for consumer offers. ",{"type":281,"tag":11280,"props":16714,"children":16715},{},[16716],{"type":291,"value":16717},"Our advice:",{"type":291,"value":16719}," If your website is not currently covered\nby ",{"type":281,"tag":11370,"props":16721,"children":16722},{},[16723],{"type":291,"value":12734},{"type":291,"value":16725},", take this opportunity to voluntarily implement accessibility. This will improve your image and\nprepare you in case ",{"type":281,"tag":11280,"props":16727,"children":16728},{},[16729],{"type":291,"value":16730},"all websites",{"type":291,"value":16732}," should be covered soon.",{"type":281,"tag":459,"props":16734,"children":16735},{},[16736,16737,16742,16743,16748,16750,16755,16757,16762,16766,16768,16777,16779,16783,16785,16790,16792,16797,16801,16803,16807],{"type":291,"value":5665},{"type":281,"tag":11280,"props":16738,"children":16739},{},[16740],{"type":291,"value":16741},"Small businesses are exempted – this will not affect us.",{"type":291,"value":16652},{"type":281,"tag":11370,"props":16744,"children":16745},{},[16746],{"type":291,"value":16747},"Beware:",{"type":291,"value":16749}," The ",{"type":281,"tag":11280,"props":16751,"children":16752},{},[16753],{"type":291,"value":16754},"micro-enterprise rule",{"type":291,"value":16756},"\n(less than 10 employees, \u003C2 Mio € turnover) applies ",{"type":281,"tag":11370,"props":16758,"children":16759},{},[16760],{"type":291,"value":16761},"only to service providers",{"type":281,"tag":286,"props":16763,"children":16764},{"href":15915},[16765],{"type":291,"value":15760},{"type":291,"value":16767},".\nAs soon as your company exceeds this threshold - as many small medium-sized companies do - you ",{"type":281,"tag":11280,"props":16769,"children":16770},{},[16771,16773],{"type":291,"value":16772},"must\ncomply with the ",{"type":281,"tag":11370,"props":16774,"children":16775},{},[16776],{"type":291,"value":12734},{"type":291,"value":16778}," if you operate relevant offers. An online retailer with 15 employees, for example, is\ndefinitely obligated. The ",{"type":281,"tag":11370,"props":16780,"children":16781},{},[16782],{"type":291,"value":12734},{"type":291,"value":16784}," also applies if you formally qualify as a micro-enterprise, but have a\n",{"type":281,"tag":11280,"props":16786,"children":16787},{},[16788],{"type":291,"value":16789},"physical sales channel",{"type":291,"value":16791}," (product) in the BFSG area, then the exception ",{"type":281,"tag":11280,"props":16793,"children":16794},{},[16795],{"type":291,"value":16796},"does not apply",{"type":281,"tag":286,"props":16798,"children":16799},{"href":15958},[16800],{"type":291,"value":15787},{"type":291,"value":16802},".\nSo check accurately if you are really exempted. In most cases,\nmore ",{"type":281,"tag":11280,"props":16804,"children":16805},{},[16806],{"type":291,"value":15898},{"type":291,"value":16808}," like one-man online shops are exempted. For growth-oriented start-ups and SMEs, this\nissue is indeed relevant.",{"type":281,"tag":459,"props":16810,"children":16811},{},[16812,16813,16818,16820,16825,16827,16832,16834,16839,16841,16846,16848,16853,16855,16860],{"type":291,"value":5665},{"type":281,"tag":11280,"props":16814,"children":16815},{},[16816],{"type":291,"value":16817},"We would like to, but it's not economically viable.",{"type":291,"value":16819},"\" – The law includes a clause on\n",{"type":281,"tag":11280,"props":16821,"children":16822},{},[16823],{"type":291,"value":16824},"disproportionate burden",{"type":291,"value":16826},"! If meeting the requirements poses an ",{"type":281,"tag":11370,"props":16828,"children":16829},{},[16830],{"type":291,"value":16831},"unbearable",{"type":291,"value":16833}," financial risk,\nyou can refer to this in exceptional cases\n",{"type":281,"tag":286,"props":16835,"children":16837},{"href":16836},"https://www.bundesfachstelle-barrierefreiheit.de/SharedDocs/Downloads/DE/Externe-Veroeffentlichungen/bmas-leitlinien-bfsg.pdf?__blob=publicationFile#:~:text=Einhaltung%20der%20Barrierefreiheitsanforderungen%20eine%20unverh%C3%A4ltnism%C3%A4%C3%9Fige,oder%20mehrere%20der%20Barrierefreiheitsanforderungen%20dieses",[16838],{"type":291,"value":15760},{"type":291,"value":16840},".\nBut be careful – the hurdles are high. You need to prepare a ",{"type":281,"tag":11280,"props":16842,"children":16843},{},[16844],{"type":291,"value":16845},"detailed documentation",{"type":291,"value":16847}," according to certain criteria\nand review it regularly (at least every 5 years). In addition, you need to inform the market surveillance authority and provide all facts upon request.\nFor the vast majority of companies, however, accessibility is likely to be ",{"type":281,"tag":11280,"props":16849,"children":16850},{},[16851],{"type":291,"value":16852},"reasonable",{"type":291,"value":16854},", as it also opens up\n",{"type":281,"tag":11280,"props":16856,"children":16857},{},[16858],{"type":291,"value":16859},"additional customer groups",{"type":291,"value":16861}," in the long term.",{"type":281,"tag":530,"props":16863,"children":16865},{"id":16864},"conclusion-understand-accessibility-as-an-opportunity",[16866],{"type":291,"value":16867},"Conclusion: Understand accessibility as an opportunity",{"type":281,"tag":282,"props":16869,"children":16870},{},[16871,16873,16877,16879,16884,16886,16891,16893,16898],{"type":291,"value":16872},"Instead of seeing the ",{"type":281,"tag":11370,"props":16874,"children":16875},{},[16876],{"type":291,"value":12734},{"type":291,"value":16878}," only as a burdensome obligation, it is worth recognizing the ",{"type":281,"tag":11280,"props":16880,"children":16881},{},[16882],{"type":291,"value":16883},"potentials",{"type":291,"value":16885},": About 10\nmillion people in Germany live with a recognized disability – a huge market segment. This includes many\nolder people with dwindling sensory abilities, temporarily restricted persons (broken arm, etc.) and users with\nsituational handicaps (blinding sunlight on the mobile phone, loud surroundings, …). ",{"type":281,"tag":11280,"props":16887,"children":16888},{},[16889],{"type":291,"value":16890},"An accessible offer reaches\nmore customers and is often more comfortable for all users.",{"type":291,"value":16892}," Many accessibility principles are simply ",{"type":281,"tag":11370,"props":16894,"children":16895},{},[16896],{"type":291,"value":16897},"best\npractices",{"type":291,"value":16899}," for good web design (clear structure, meaningful links, sufficient contrast, etc.). Companies that lead the way\nhere, can profile themselves with an inclusive image and simultaneously minimize legal risks.",{"type":281,"tag":282,"props":16901,"children":16902},{},[16903,16904,16912,16914,16919,16921,16926],{"type":291,"value":10817},{"type":281,"tag":11280,"props":16905,"children":16906},{},[16907],{"type":281,"tag":11370,"props":16908,"children":16909},{},[16910],{"type":291,"value":16911},"Accessibility Strengthening Act",{"type":291,"value":16913}," may initially appear to be another compliance hurdle. However, with the right\npartner and approach, it can be managed – without your budget exploding or your team getting desperate. ",{"type":281,"tag":11280,"props":16915,"children":16916},{},[16917],{"type":291,"value":16918},"We\nare happy to support",{"type":291,"value":16920}," you in setting the course early so that your web project is not only legally compliant,\nbut provides a real added value for ",{"type":281,"tag":11370,"props":16922,"children":16923},{},[16924],{"type":291,"value":16925},"all",{"type":291,"value":16927}," users!",{"type":281,"tag":282,"props":16929,"children":16930},{},[16931,16935],{"type":281,"tag":11280,"props":16932,"children":16933},{},[16934],{"type":291,"value":12038},{"type":291,"value":16936}," This article was also generated with the support of AI (model: GPT-4).",{"title":8,"searchDepth":338,"depth":338,"links":16938},[16939,16942,16945,16948,16949,16950],{"id":15701,"depth":338,"text":15704,"children":16940},[16941],{"id":15740,"depth":351,"text":15743},{"id":16030,"depth":338,"text":16033,"children":16943},[16944],{"id":16191,"depth":351,"text":16194},{"id":16263,"depth":338,"text":16266,"children":16946},[16947],{"id":16340,"depth":351,"text":16343},{"id":16382,"depth":338,"text":16385},{"id":16623,"depth":338,"text":16626},{"id":16864,"depth":338,"text":16867},{"_path":122,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":123,"description":124,"author":86,"image":12,"releaseDate":125,"blogCategories":16952,"articleTags":16953,"tags":16954,"body":16955,"_type":20,"_id":129,"_source":22,"_file":130,"_stem":131,"_extension":25},[90],[16],[19],{"type":278,"children":16956,"toc":18183},[16957,16963,16979,16985,17031,17095,17107,17113,17123,17164,17173,17205,17244,17253,17286,17305,17348,17354,17363,17395,17440,17465,17475,17490,17496,17505,17534,17655,17659,17703,17709,17718,17770,17801,17825,17856,17874,17880,17889,17920,17939,17975,17994,18020,18032,18038,18047,18073,18129,18135,18163,18175],{"type":281,"tag":1499,"props":16958,"children":16962},{"alt":16959,"aspect-ratio":16960,"height":1502,"object-fit":1503,"src":16961},"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":281,"tag":319,"props":16964,"children":16966},{"className":16965},[11364,15685],[16967],{"type":281,"tag":282,"props":16968,"children":16969},{},[16970],{"type":281,"tag":11370,"props":16971,"children":16972},{},[16973],{"type":281,"tag":286,"props":16974,"children":16976},{"href":16975},"https://www.pexels.com/photo/person-holding-a-sticker-11035393/",[16977],{"type":291,"value":16978},"Photo by RealToughCandy.com",{"type":281,"tag":530,"props":16980,"children":16982},{"id":16981},"why-developing-a-web-application-is-only-the-beginning",[16983],{"type":291,"value":16984},"Why developing a (web) application is only the beginning",{"type":281,"tag":282,"props":16986,"children":16987},{},[16988,16990,16995,16997,17002,17004,17008,17010,17015,17017,17022,17024,17029],{"type":291,"value":16989},"Web applications are mostly developed and tested in a ",{"type":281,"tag":11370,"props":16991,"children":16992},{},[16993],{"type":291,"value":16994},"Dev",{"type":291,"value":16996}," environment (Development environment) - however the\nactual endurance test takes place on the ",{"type":281,"tag":11370,"props":16998,"children":16999},{},[17000],{"type":291,"value":17001},"Prod",{"type":291,"value":17003}," systems (Production environment). Here, ",{"type":281,"tag":11280,"props":17005,"children":17006},{},[17007],{"type":291,"value":16},{"type":291,"value":17009}," (short for\n",{"type":281,"tag":11370,"props":17011,"children":17012},{},[17013],{"type":291,"value":17014},"Development Operations",{"type":291,"value":17016},", representing the close integration between development and IT operations) plays a key role.\nEspecially with web applications on ",{"type":281,"tag":11280,"props":17018,"children":17019},{},[17020],{"type":291,"value":17021},"Linux servers",{"type":291,"value":17023}," with complex ",{"type":281,"tag":11280,"props":17025,"children":17026},{},[17027],{"type":291,"value":17028},"network infrastructures",{"type":291,"value":17030},", 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":281,"tag":282,"props":17032,"children":17033},{},[17034,17036,17041,17043,17048,17049,17054,17056,17065,17066,17075,17077,17086,17088,17093],{"type":291,"value":17035},"We will shed light on why development environments reach their limits, why genuine load tests and ",{"type":281,"tag":11370,"props":17037,"children":17038},{},[17039],{"type":291,"value":17040},"Edge Cases",{"type":291,"value":17042}," are\ndifficult to simulate, and why work begins properly only after the launch (namely under ",{"type":281,"tag":11370,"props":17044,"children":17045},{},[17046],{"type":291,"value":17047},"monitoring",{"type":291,"value":9323},{"type":281,"tag":11370,"props":17050,"children":17051},{},[17052],{"type":291,"value":17053},"continuous\nimprovement",{"type":291,"value":17055},"). We will also explore the tools that are indispensable in our daily work, from\n",{"type":281,"tag":286,"props":17057,"children":17059},{"href":17058},"https://sentry.io/",[17060],{"type":281,"tag":11280,"props":17061,"children":17062},{},[17063],{"type":291,"value":17064},"Sentry",{"type":291,"value":9822},{"type":281,"tag":286,"props":17067,"children":17069},{"href":17068},"https://grafana.com/",[17070],{"type":281,"tag":11280,"props":17071,"children":17072},{},[17073],{"type":291,"value":17074},"Grafana",{"type":291,"value":17076},", to\n",{"type":281,"tag":286,"props":17078,"children":17080},{"href":17079},"https://www.zabbix.com/",[17081],{"type":281,"tag":11280,"props":17082,"children":17083},{},[17084],{"type":291,"value":17085},"Zabbix",{"type":291,"value":17087},", and how ",{"type":281,"tag":11280,"props":17089,"children":17090},{},[17091],{"type":291,"value":17092},"CI/CD pipelines",{"type":291,"value":17094}," help even less experienced developers to deploy\nsafely.",{"type":281,"tag":319,"props":17096,"children":17098},{"className":17097},[11364],[17099],{"type":281,"tag":282,"props":17100,"children":17101},{},[17102],{"type":281,"tag":11370,"props":17103,"children":17104},{},[17105],{"type":291,"value":17106},"Reading duration: approx. 20 minutes",{"type":281,"tag":530,"props":17108,"children":17110},{"id":17109},"development-environment-vs-reality-limited-performance-and-unknown-edge-cases",[17111],{"type":291,"value":17112},"Development environment vs. reality: Limited performance and unknown edge cases",{"type":281,"tag":282,"props":17114,"children":17115},{},[17116,17121],{"type":281,"tag":11280,"props":17117,"children":17118},{},[17119],{"type":291,"value":17120},"Thesis:",{"type":291,"value":17122}," Software projects and web applications are built in development environments that are limited in performance\nand test data.",{"type":281,"tag":282,"props":17124,"children":17125},{},[17126,17128,17133,17135,17140,17142,17147,17149,17154,17156,17162],{"type":291,"value":17127},"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":281,"tag":11280,"props":17129,"children":17130},{},[17131],{"type":291,"value":17132},"Dev environment",{"type":291,"value":17134}," is typically ",{"type":281,"tag":11280,"props":17136,"children":17137},{},[17138],{"type":291,"value":17139},"less powerful",{"type":291,"value":17141}," 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":281,"tag":11280,"props":17143,"children":17144},{},[17145],{"type":291,"value":17146},"staging",{"type":291,"value":17148}," environment can try to mimic the production environment\nbut it has its ",{"type":281,"tag":11280,"props":17150,"children":17151},{},[17152],{"type":291,"value":17153},"limits",{"type":291,"value":17155},": 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":281,"tag":286,"props":17157,"children":17159},{"href":17158},"https://www.browserstack.com/guide/testing-in-production#:~:text=1.%20Real,only%20surface%20under%20specific%20conditions",[17160],{"type":291,"value":17161},"browserstack.com",{"type":291,"value":17163},"\n. In other words: Everything runs \"smoothly\" in the test environment, but reality introduces completely different\nfactors.",{"type":281,"tag":282,"props":17165,"children":17166},{},[17167,17171],{"type":281,"tag":11280,"props":17168,"children":17169},{},[17170],{"type":291,"value":17120},{"type":291,"value":17172}," Developers and clients often lack a complete overview of realistic use cases, edge cases, and peak loads.",{"type":281,"tag":282,"props":17174,"children":17175},{},[17176,17178,17183,17185,17190,17192,17196,17198,17203],{"type":291,"value":17177},"Development teams and even clients know the ",{"type":281,"tag":11370,"props":17179,"children":17180},{},[17181],{"type":291,"value":17182},"major use cases",{"type":291,"value":17184}," of their software, but ",{"type":281,"tag":11280,"props":17186,"children":17187},{},[17188],{"type":291,"value":17189},"real users",{"type":291,"value":17191},"\noften push applications to their limits. Suddenly they use features in combinations that nobody had thought of,\nor input unexpected data. Such ",{"type":281,"tag":11280,"props":17193,"children":17194},{},[17195],{"type":291,"value":17040},{"type":291,"value":17197}," (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":281,"tag":11370,"props":17199,"children":17200},{},[17201],{"type":291,"value":17202},"emoji",{"type":291,"value":17204}," 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":281,"tag":282,"props":17206,"children":17207},{},[17208,17210,17215,17217,17222,17224,17229,17231,17236,17238,17242],{"type":291,"value":17209},"In addition, clients might be familiar with their business processes, but ",{"type":281,"tag":11280,"props":17211,"children":17212},{},[17213],{"type":291,"value":17214},"peak loads",{"type":291,"value":17216}," due to marketing actions or\ncompletely atypical\nusage times (e.g., at 3 a.m. on weekends) are easily underestimated. The ",{"type":281,"tag":11280,"props":17218,"children":17219},{},[17220],{"type":291,"value":17221},"critical view",{"type":291,"value":17223}," here:\nModern approaches aim to close this gap by advocating that development and production environments should be as\nsimilar as possible (",{"type":281,"tag":11370,"props":17225,"children":17226},{},[17227],{"type":291,"value":17228},"dev/prod parity",{"type":291,"value":17230},") in order to minimize later surprises.\n",{"type":281,"tag":11280,"props":17232,"children":17233},{},[17234],{"type":291,"value":17235},"Containerization",{"type":291,"value":17237}," (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":281,"tag":11280,"props":17239,"children":17240},{},[17241],{"type":291,"value":16925},{"type":291,"value":17243}," real conditions.",{"type":281,"tag":282,"props":17245,"children":17246},{},[17247,17251],{"type":281,"tag":11280,"props":17248,"children":17249},{},[17250],{"type":291,"value":17120},{"type":291,"value":17252}," Behavior under prolonged load, external crawlers, penetration tests, or spam-bots are difficult to simulate.",{"type":281,"tag":282,"props":17254,"children":17255},{},[17256,17258,17263,17265,17270,17272,17277,17279,17284],{"type":291,"value":17257},"Performance tests are good practice, but ",{"type":281,"tag":11280,"props":17259,"children":17260},{},[17261],{"type":291,"value":17262},"constant load 24/7",{"type":291,"value":17264}," 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":281,"tag":11280,"props":17266,"children":17267},{},[17268],{"type":291,"value":17269},"malicious attacks",{"type":291,"value":17271}," are a topic. External ",{"type":281,"tag":11280,"props":17273,"children":17274},{},[17275],{"type":291,"value":17276},"crawlers",{"type":291,"value":17278}," (e.g. by Google, Bing, or others) might massively call up pages\nor ",{"type":281,"tag":11280,"props":17280,"children":17281},{},[17282],{"type":291,"value":17283},"spam bots",{"type":291,"value":17285}," 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":281,"tag":282,"props":17287,"children":17288},{},[17289,17291,17296,17298,17303],{"type":291,"value":17290},"The developer and DevOps community are consistent on this: it is ",{"type":281,"tag":11280,"props":17292,"children":17293},{},[17294],{"type":291,"value":17295},"incredibly difficult to truly simulate the production\nload",{"type":291,"value":17297},". Even with test environments that resemble the prod environment, unforeseen effects can occur. An interesting\napproach is therefore almost counterintuitive: sometimes, purposefully ",{"type":281,"tag":11280,"props":17299,"children":17300},{},[17301],{"type":291,"value":17302},"undersized test environments are used",{"type":291,"value":17304}," 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":281,"tag":282,"props":17306,"children":17307},{},[17308,17309,17314,17316,17321,17323,17328,17330,17338,17340,17346],{"type":291,"value":10817},{"type":281,"tag":11280,"props":17310,"children":17311},{},[17312],{"type":291,"value":17313},"overriding opinion",{"type":291,"value":17315}," in the tech community, however, is that ",{"type":281,"tag":11280,"props":17317,"children":17318},{},[17319],{"type":291,"value":17320},"nothing measures up to real production tests",{"type":291,"value":17322},".\nBig players like Netflix even propagate ",{"type":281,"tag":11370,"props":17324,"children":17325},{},[17326],{"type":291,"value":17327},"chaos engineering",{"type":291,"value":17329},", 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":281,"tag":11370,"props":17331,"children":17332},{},[17333],{"type":281,"tag":11280,"props":17334,"children":17335},{},[17336],{"type":291,"value":17337},"in production",{"type":291,"value":17339}," can one work with factors such as state data, real inputs, and\nthe behavior of external systems“\n",{"type":281,"tag":286,"props":17341,"children":17343},{"href":17342},"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",[17344],{"type":291,"value":17345},"techtarget.com",{"type":291,"value":17347},"\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":281,"tag":530,"props":17349,"children":17351},{"id":17350},"after-the-launch-is-before-the-launch-analysis-and-optimization-during-operation",[17352],{"type":291,"value":17353},"After the launch is before the launch: Analysis and optimization during operation",{"type":281,"tag":282,"props":17355,"children":17356},{},[17357,17361],{"type":281,"tag":11280,"props":17358,"children":17359},{},[17360],{"type":291,"value":17120},{"type":291,"value":17362}," Further analysis and optimization after the launch is essential.",{"type":281,"tag":282,"props":17364,"children":17365},{},[17366,17368,17373,17375,17380,17382,17387,17393],{"type":291,"value":17367},"In the past, a software project was considered finished after the go-live - today we know that ",{"type":281,"tag":11280,"props":17369,"children":17370},{},[17371],{"type":291,"value":17372},"Continuous Improvement",{"type":291,"value":17374},"\nis a critical part of successful software. It's precisely ",{"type":281,"tag":11280,"props":17376,"children":17377},{},[17378],{"type":291,"value":17379},"after the launch",{"type":291,"value":17381}," that the phase begins in which real use\ndata is evaluated, bottlenecks are identified, and optimizations are made. As one expert article emphasizes: ",{"type":281,"tag":11370,"props":17383,"children":17384},{},[17385],{"type":291,"value":17386},"\"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":281,"tag":286,"props":17388,"children":17390},{"href":17389},"https://www.topdevelopers.co/blog/post-launch-support-in-software-development/#:~:text=Even%20with%20rigorous%20pre,a%20large%20number%20of%20users",[17391],{"type":291,"value":17392},"topdevelopers.co",{"type":291,"value":17394},"\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":281,"tag":282,"props":17396,"children":17397},{},[17398,17403,17405,17410,17412,17417,17419,17424,17426,17431,17433,17438],{"type":281,"tag":11280,"props":17399,"children":17400},{},[17401],{"type":291,"value":17402},"Critical Perspective:",{"type":291,"value":17404}," 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":281,"tag":11280,"props":17406,"children":17407},{},[17408],{"type":291,"value":17409},"stabilize and speed up",{"type":291,"value":17411}," a (web)\napplication. Studies show that ",{"type":281,"tag":11370,"props":17413,"children":17414},{},[17415],{"type":291,"value":17416},"continuous maintenance",{"type":291,"value":17418}," can significantly increase ",{"type":281,"tag":11280,"props":17420,"children":17421},{},[17422],{"type":291,"value":17423},"user satisfaction and retention",{"type":291,"value":17425},".\nThis includes regular ",{"type":281,"tag":11280,"props":17427,"children":17428},{},[17429],{"type":291,"value":17430},"bug fixes",{"type":291,"value":17432},", performance tuning (e.g., adjusting caching strategies, optimizing database\nindexes), and ",{"type":281,"tag":11280,"props":17434,"children":17435},{},[17436],{"type":291,"value":17437},"security patches",{"type":291,"value":17439},". Security vulnerabilities that only emerge gradually must be immediately sealed off\nto prevent damage.",{"type":281,"tag":282,"props":17441,"children":17442},{},[17443,17445,17450,17452,17457,17459,17464],{"type":291,"value":17444},"Another aspect is the ",{"type":281,"tag":11280,"props":17446,"children":17447},{},[17448],{"type":291,"value":17449},"feedback loop",{"type":291,"value":17451},": 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":281,"tag":11370,"props":17453,"children":17454},{},[17455],{"type":291,"value":17456},"continuous deployment",{"type":291,"value":17458}," 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":281,"tag":11370,"props":17460,"children":17461},{},[17462],{"type":291,"value":17463},"\"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":291,"value":564},{"type":281,"tag":282,"props":17466,"children":17467},{},[17468,17470],{"type":291,"value":17469},"Current practice in successful companies clearly shows: after the launch is before the launch. ",{"type":281,"tag":11280,"props":17471,"children":17472},{},[17473],{"type":291,"value":17474},"Stagnation is dangerous",{"type":281,"tag":455,"props":17476,"children":17477},{},[17478],{"type":281,"tag":459,"props":17479,"children":17480},{},[17481,17483,17488],{"type":291,"value":17482},"anyone who does not invest in ",{"type":281,"tag":11280,"props":17484,"children":17485},{},[17486],{"type":291,"value":17487},"monitoring, troubleshooting, and optimization",{"type":291,"value":17489}," 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":281,"tag":530,"props":17491,"children":17493},{"id":17492},"monitoring-and-logging-observation-is-essential",[17494],{"type":291,"value":17495},"Monitoring and Logging: Observation is essential",{"type":281,"tag":282,"props":17497,"children":17498},{},[17499,17503],{"type":281,"tag":11280,"props":17500,"children":17501},{},[17502],{"type":291,"value":17120},{"type":291,"value":17504}," Monitoring tools like Sentry or Grafana are essential for logging and error analysis.",{"type":281,"tag":282,"props":17506,"children":17507},{},[17508,17510,17515,17517,17524,17525,17532],{"type":291,"value":17509},"To quickly identify problems in operation, ",{"type":281,"tag":11280,"props":17511,"children":17512},{},[17513],{"type":291,"value":17514},"monitoring and logging tools",{"type":291,"value":17516}," are absolutely crucial. Two prominent\nexamples are ",{"type":281,"tag":286,"props":17518,"children":17519},{"href":17058},[17520],{"type":281,"tag":11280,"props":17521,"children":17522},{},[17523],{"type":291,"value":17064},{"type":291,"value":9323},{"type":281,"tag":286,"props":17526,"children":17527},{"href":17068},[17528],{"type":281,"tag":11280,"props":17529,"children":17530},{},[17531],{"type":291,"value":17074},{"type":291,"value":17533}," (often in combination with\ntime-series databases like Prometheus or log databases like ElasticSearch/Loki).",{"type":281,"tag":455,"props":17535,"children":17536},{},[17537,17588],{"type":281,"tag":459,"props":17538,"children":17539},{},[17540,17547,17549,17554,17556,17561,17563,17572,17574,17579,17581,17586],{"type":281,"tag":286,"props":17541,"children":17542},{"href":17058},[17543],{"type":281,"tag":11280,"props":17544,"children":17545},{},[17546],{"type":291,"value":17064},{"type":291,"value":17548}," is a specialized tool for ",{"type":281,"tag":11280,"props":17550,"children":17551},{},[17552],{"type":291,"value":17553},"error tracking",{"type":291,"value":17555},". 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":281,"tag":11280,"props":17557,"children":17558},{},[17559],{"type":291,"value":17560},"industrial standard",{"type":291,"value":17562}," when it comes to crash reporting\n",{"type":281,"tag":286,"props":17564,"children":17566},{"href":17565},"https://medium.com/@AndrzejSala/efficient-error-tracking-with-sentry-e975c186947c#:~:text=Sentry%20is%20a%20crash,an%20industry%20standard%20by%20TechRadar",[17567,17569],{"type":291,"value":17568},"medium.com",{"type":281,"tag":1314,"props":17570,"children":17571},{},[],{"type":291,"value":17573},".\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":281,"tag":11280,"props":17575,"children":17576},{},[17577],{"type":291,"value":17578},"immediately",{"type":291,"value":17580}," when an error happens – and can proactively\nrespond, ",{"type":281,"tag":11280,"props":17582,"children":17583},{},[17584],{"type":291,"value":17585},"before",{"type":291,"value":17587}," all users are affected.",{"type":281,"tag":459,"props":17589,"children":17590},{},[17591,17598,17600,17605,17607,17612,17614,17619,17621,17626,17628,17633,17635,17640,17642,17647,17649,17654],{"type":281,"tag":286,"props":17592,"children":17593},{"href":17068},[17594],{"type":281,"tag":11280,"props":17595,"children":17596},{},[17597],{"type":291,"value":17074},{"type":291,"value":17599},", on the other hand, addresses ",{"type":281,"tag":11280,"props":17601,"children":17602},{},[17603],{"type":291,"value":17604},"performance monitoring and visualization",{"type":291,"value":17606}," 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":281,"tag":11280,"props":17608,"children":17609},{},[17610],{"type":291,"value":17611},"Prometheus",{"type":291,"value":17613}," (for\nmetric collection) or ",{"type":281,"tag":11280,"props":17615,"children":17616},{},[17617],{"type":291,"value":17618},"Loki",{"type":291,"value":17620}," (for log collection), a powerful ",{"type":281,"tag":11280,"props":17622,"children":17623},{},[17624],{"type":291,"value":17625},"monitoring cockpit",{"type":291,"value":17627}," is created. You want to be able\nto see ",{"type":281,"tag":11370,"props":17629,"children":17630},{},[17631],{"type":291,"value":17632},"at a glance",{"type":291,"value":17634}," whether all systems are green, where potential bottlenecks may be, or if unusual spikes occur.\nSpecifically, this means: Grafana & Co. help to recognize ",{"type":281,"tag":11280,"props":17636,"children":17637},{},[17638],{"type":291,"value":17639},"trends",{"type":291,"value":17641}," (e.g., steadily increasing memory load), track\n",{"type":281,"tag":11280,"props":17643,"children":17644},{},[17645],{"type":291,"value":17646},"anomalies",{"type":291,"value":17648}," (e.g., sudden traffic increase at midnight), and in the event of an error, quickly identify the ",{"type":281,"tag":11280,"props":17650,"children":17651},{},[17652],{"type":291,"value":17653},"cause",{"type":291,"value":564},{"type":281,"tag":17656,"props":17657,"children":17658},"icons-dev-ops",{},[],{"type":281,"tag":282,"props":17660,"children":17661},{},[17662,17666,17668,17673,17675,17680,17682,17687,17689,17694,17696,17701],{"type":281,"tag":11280,"props":17663,"children":17664},{},[17665],{"type":291,"value":17402},{"type":291,"value":17667}," 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":281,"tag":11280,"props":17669,"children":17670},{},[17671],{"type":291,"value":17672},"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":291,"value":17674},". 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":281,"tag":11280,"props":17676,"children":17677},{},[17678],{"type":291,"value":17679},"flood of data",{"type":291,"value":17681},". 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":281,"tag":11370,"props":17683,"children":17684},{},[17685],{"type":291,"value":17686},"alert fatigue",{"type":291,"value":17688}," – too many false alarms. Here, ",{"type":281,"tag":11280,"props":17690,"children":17691},{},[17692],{"type":291,"value":17693},"quality over quantity",{"type":291,"value":17695}," is key. Better a few,\nbut meaningful metrics and alerts. We strongly advise all our customers: ",{"type":281,"tag":11370,"props":17697,"children":17698},{},[17699],{"type":291,"value":17700},"the investment in monitoring and logging tools\nis essential",{"type":291,"value":17702}," in order to remain capable of action in the event of an error!",{"type":281,"tag":530,"props":17704,"children":17706},{"id":17705},"automatic-alerts-zabbix-and-co-as-the-guardians-of-the-systems",[17707],{"type":291,"value":17708},"Automatic Alerts: Zabbix and Co. as the Guardians of the Systems",{"type":281,"tag":282,"props":17710,"children":17711},{},[17712,17716],{"type":281,"tag":11280,"props":17713,"children":17714},{},[17715],{"type":291,"value":17120},{"type":291,"value":17717}," Monitoring tools like Zabbix are necessary for alerts during critical system conditions.",{"type":281,"tag":282,"props":17719,"children":17720},{},[17721,17723,17728,17730,17734,17735,17740,17741,17746,17748,17755,17757,17762,17763,17768],{"type":291,"value":17722},"In addition to just observing metrics, of course, we want to be ",{"type":281,"tag":11280,"props":17724,"children":17725},{},[17726],{"type":291,"value":17727},"automatically alerted",{"type":291,"value":17729}," when something goes awry. This\nis where system monitoring tools like ",{"type":281,"tag":11280,"props":17731,"children":17732},{},[17733],{"type":291,"value":17085},{"type":291,"value":9822},{"type":281,"tag":11280,"props":17736,"children":17737},{},[17738],{"type":291,"value":17739},"Nagios",{"type":291,"value":9822},{"type":281,"tag":11280,"props":17742,"children":17743},{},[17744],{"type":291,"value":17745},"Icinga",{"type":291,"value":17747},", etc., come into play. Let's stick with\n",{"type":281,"tag":286,"props":17749,"children":17750},{"href":17079},[17751],{"type":281,"tag":11280,"props":17752,"children":17753},{},[17754],{"type":291,"value":17085},{"type":291,"value":17756}," as an example: Zabbix is an open-source monitoring system that offers predefined\n",{"type":281,"tag":11280,"props":17758,"children":17759},{},[17760],{"type":291,"value":17761},"triggers",{"type":291,"value":9323},{"type":281,"tag":11280,"props":17764,"children":17765},{},[17766],{"type":291,"value":17767},"notifications",{"type":291,"value":17769},". 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":281,"tag":282,"props":17771,"children":17772},{},[17773,17775,17779,17781,17786,17788,17792,17794,17799],{"type":291,"value":17774},"Why do we need this, didn't we just praise Grafana & Co.? The difference: ",{"type":281,"tag":11280,"props":17776,"children":17777},{},[17778],{"type":291,"value":17074},{"type":291,"value":17780}," is great for visualization and\nanalysis, but ",{"type":281,"tag":11280,"props":17782,"children":17783},{},[17784],{"type":291,"value":17785},"active alerting",{"type":291,"value":17787}," is often taken over by a dedicated tool like Zabbix (or Grafana is combined with an\nalert manager). ",{"type":281,"tag":11280,"props":17789,"children":17790},{},[17791],{"type":291,"value":17085},{"type":291,"value":17793}," and similar tools are essentially the ",{"type":281,"tag":11280,"props":17795,"children":17796},{},[17797],{"type":291,"value":17798},"night watchmen",{"type":291,"value":17800}," who tirelessly monitor for defined\nconditions.",{"type":281,"tag":282,"props":17802,"children":17803},{},[17804,17806,17811,17817,17819,17823],{"type":291,"value":17805},"The importance of such alerts cannot be overstated. A fitting quote from a Linux Journal article: ",{"type":281,"tag":11370,"props":17807,"children":17808},{},[17809],{"type":291,"value":17810},"\"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":281,"tag":286,"props":17812,"children":17814},{"href":17813},"https://www.linuxjournal.com/content/how-monitor-your-system-zabbix#:~:text=Alerts%20and%20triggers%20are%20the,that%20could%20impact%20system%20performance",[17815],{"type":291,"value":17816},"linuxjournal.com",{"type":291,"value":17818},"\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":281,"tag":11280,"props":17820,"children":17821},{},[17822],{"type":291,"value":17578},{"type":291,"value":17824}," knows, for example,\nif the web server has failed or if the response times are critically high.",{"type":281,"tag":282,"props":17826,"children":17827},{},[17828,17833,17835,17840,17842,17847,17849,17854],{"type":281,"tag":11280,"props":17829,"children":17830},{},[17831],{"type":291,"value":17832},"Practical View:",{"type":291,"value":17834}," 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":281,"tag":11370,"props":17836,"children":17837},{},[17838],{"type":291,"value":17839},"false positives",{"type":291,"value":17841},"), will quickly be ignored. The trick is to define ",{"type":281,"tag":11280,"props":17843,"children":17844},{},[17845],{"type":291,"value":17846},"meaningful threshold values",{"type":291,"value":17848},"\nand send ",{"type":281,"tag":11280,"props":17850,"children":17851},{},[17852],{"type":291,"value":17853},"context-rich alerts",{"type":291,"value":17855}," (e.g., directly with an indication of which component is affected, attach logs, etc.).",{"type":281,"tag":282,"props":17857,"children":17858},{},[17859,17866,17868,17873],{"type":281,"tag":286,"props":17860,"children":17861},{"href":17079},[17862],{"type":281,"tag":11280,"props":17863,"children":17864},{},[17865],{"type":291,"value":17085},{"type":291,"value":17867}," has proven itself in many of our projects and is often referred to internally as\nan ",{"type":281,"tag":11280,"props":17869,"children":17870},{},[17871],{"type":291,"value":17872},"indispensable tool",{"type":291,"value":564},{"type":281,"tag":530,"props":17875,"children":17877},{"id":17876},"cicd-pipelines-standardized-deployments-also-for-beginners",[17878],{"type":291,"value":17879},"CI/CD Pipelines: Standardized Deployments - Also for Beginners",{"type":281,"tag":282,"props":17881,"children":17882},{},[17883,17887],{"type":281,"tag":11280,"props":17884,"children":17885},{},[17886],{"type":291,"value":17120},{"type":291,"value":17888}," CI/CD Pipelines enable standardized, safe deployments even for less experienced developers.",{"type":281,"tag":282,"props":17890,"children":17891},{},[17892,17894,17898,17900,17905,17906,17911,17913,17918],{"type":291,"value":17893},"The terms ",{"type":281,"tag":11280,"props":17895,"children":17896},{},[17897],{"type":291,"value":1578},{"type":291,"value":17899}," stand for ",{"type":281,"tag":11370,"props":17901,"children":17902},{},[17903],{"type":291,"value":17904},"Continuous Integration",{"type":291,"value":9323},{"type":281,"tag":11370,"props":17907,"children":17908},{},[17909],{"type":291,"value":17910},"Continuous Delivery/Deployment",{"type":291,"value":17912},". A ",{"type":281,"tag":11280,"props":17914,"children":17915},{},[17916],{"type":291,"value":17917},"CI/CD pipeline",{"type":291,"value":17919}," 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":281,"tag":282,"props":17921,"children":17922},{},[17923,17925,17930,17932,17937],{"type":291,"value":17924},"In traditional development workflows, the ",{"type":281,"tag":11280,"props":17926,"children":17927},{},[17928],{"type":291,"value":17929},"deployment",{"type":291,"value":17931}," 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":281,"tag":11280,"props":17933,"children":17934},{},[17935],{"type":291,"value":17936},"standardized, repeatable operation",{"type":291,"value":17938}," - 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":281,"tag":282,"props":17940,"children":17941},{},[17942,17947,17949,17954,17955,17960,17962,17966,17968,17973],{"type":281,"tag":11280,"props":17943,"children":17944},{},[17945],{"type":291,"value":17946},"Safety and quality",{"type":291,"value":17948}," are not neglected - on the contrary. Particularly less experienced developers benefit from the\nfact that the pipeline carries out automated ",{"type":281,"tag":11280,"props":17950,"children":17951},{},[17952],{"type":291,"value":17953},"tests",{"type":291,"value":9323},{"type":281,"tag":11280,"props":17956,"children":17957},{},[17958],{"type":291,"value":17959},"code checks",{"type":291,"value":17961}," ",{"type":281,"tag":11370,"props":17963,"children":17964},{},[17965],{"type":291,"value":17585},{"type":291,"value":17967}," 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":281,"tag":11280,"props":17969,"children":17970},{},[17971],{"type":291,"value":17972},"the same way",{"type":291,"value":17974}," - 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":281,"tag":282,"props":17976,"children":17977},{},[17978,17980,17985,17987,17992],{"type":291,"value":17979},"Of course, setting up a CI/CD pipeline initially requires ",{"type":281,"tag":11280,"props":17981,"children":17982},{},[17983],{"type":291,"value":17984},"know-how and effort",{"type":291,"value":17986},". 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":281,"tag":11280,"props":17988,"children":17989},{},[17990],{"type":291,"value":17991},"Upon critical examination",{"type":291,"value":17993},", 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":281,"tag":282,"props":17995,"children":17996},{},[17997,17999,18004,18006,18011,18013,18018],{"type":291,"value":17998},"It's important that CI/CD brings not only technical but also ",{"type":281,"tag":11280,"props":18000,"children":18001},{},[18002],{"type":291,"value":18003},"cultural changes",{"type":291,"value":18005},". Deployments become smaller but more\nfrequent. This reduces risk and the impact of errors. Teams get used to deployments being ",{"type":281,"tag":11370,"props":18007,"children":18008},{},[18009],{"type":291,"value":18010},"routine",{"type":291,"value":18012}," and not \"major\noperation days\". Especially in ",{"type":281,"tag":11280,"props":18014,"children":18015},{},[18016],{"type":291,"value":18017},"Agile Development",{"type":291,"value":18019},", CI/CD is virtually the backbone to enable fast iterations.",{"type":281,"tag":282,"props":18021,"children":18022},{},[18023,18025,18030],{"type":291,"value":18024},"In summary: CI/CD pipelines are a game-changer that enables even less experienced developers to deliver ",{"type":281,"tag":11280,"props":18026,"children":18027},{},[18028],{"type":291,"value":18029},"at the push of\na button",{"type":291,"value":18031}," – reliably and repeatably.",{"type":281,"tag":530,"props":18033,"children":18035},{"id":18034},"experience-counts-live-data-specific-errors-and-the-role-of-devops-experts",[18036],{"type":291,"value":18037},"Experience Counts: Live Data, Specific Errors, and the Role of DevOps Experts",{"type":281,"tag":282,"props":18039,"children":18040},{},[18041,18045],{"type":281,"tag":11280,"props":18042,"children":18043},{},[18044],{"type":291,"value":17120},{"type":291,"value":18046}," Certain errors and performance problems only manifest with live data and require experienced DevOps\nspecialists.",{"type":281,"tag":282,"props":18048,"children":18049},{},[18050,18052,18057,18059,18064,18066,18071],{"type":291,"value":18051},"Despite all automation and testing, the ",{"type":281,"tag":11280,"props":18053,"children":18054},{},[18055],{"type":291,"value":18056},"experience",{"type":291,"value":18058}," in dealing with production systems is irreplaceable. There are\nerror patterns that only occur with real ",{"type":281,"tag":11280,"props":18060,"children":18061},{},[18062],{"type":291,"value":18063},"live data and loads",{"type":291,"value":18065}," - 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":281,"tag":11280,"props":18067,"children":18068},{},[18069],{"type":291,"value":18070},"memory leak",{"type":291,"value":18072}," 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":281,"tag":282,"props":18074,"children":18075},{},[18076,18078,18083,18085,18091,18092,18098,18100,18106,18108,18113,18115,18120,18122,18127],{"type":291,"value":18077},"A DevOps engineer with a lot of operational experience usually has a repertoire of ",{"type":281,"tag":11280,"props":18079,"children":18080},{},[18081],{"type":291,"value":18082},"diagnostic techniques",{"type":291,"value":18084},". For\nexample, experienced people know how to debug on Linux with tools like ",{"type":281,"tag":315,"props":18086,"children":18088},{"className":18087},[],[18089],{"type":291,"value":18090},"htop",{"type":291,"value":9822},{"type":281,"tag":315,"props":18093,"children":18095},{"className":18094},[],[18096],{"type":291,"value":18097},"iotop",{"type":291,"value":18099},", or ",{"type":281,"tag":315,"props":18101,"children":18103},{"className":18102},[],[18104],{"type":291,"value":18105},"strace",{"type":291,"value":18107},", which less routine\ndevelopers may never have needed. Experienced DevOps also know ",{"type":281,"tag":11280,"props":18109,"children":18110},{},[18111],{"type":291,"value":18112},"duration load phenomena",{"type":291,"value":18114}," (keywords: ",{"type":281,"tag":11370,"props":18116,"children":18117},{},[18118],{"type":291,"value":18119},"floating-point\nprecision bugs",{"type":291,"value":18121},", memory-induced rounding errors, etc.) from practice. A drastic but real scenario: A memory error occurs\n",{"type":281,"tag":11370,"props":18123,"children":18124},{},[18125],{"type":291,"value":18126},"only",{"type":291,"value":18128}," 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":281,"tag":530,"props":18130,"children":18132},{"id":18131},"conclusion",[18133],{"type":291,"value":18134},"Conclusion",{"type":281,"tag":282,"props":18136,"children":18137},{},[18138,18140,18145,18147,18152,18154,18161],{"type":291,"value":18139},"For (web) applications in productive use, ",{"type":281,"tag":11280,"props":18141,"children":18142},{},[18143],{"type":291,"value":18144},"DevOps is not a luxury, but a necessity",{"type":291,"value":18146},". 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":281,"tag":11280,"props":18148,"children":18149},{},[18150],{"type":291,"value":18151},"time and resources",{"type":291,"value":18153}," even after the launch to analyze data and implement improvements. Tools like\n",{"type":281,"tag":286,"props":18155,"children":18156},{"href":17058},[18157],{"type":281,"tag":11280,"props":18158,"children":18159},{},[18160],{"type":291,"value":17064},{"type":291,"value":18162},", 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":281,"tag":282,"props":18164,"children":18165},{},[18166,18168,18173],{"type":291,"value":18167},"In the end, it shows: ",{"type":281,"tag":11280,"props":18169,"children":18170},{},[18171],{"type":291,"value":18172},"People",{"type":291,"value":18174}," make the difference. Experienced DevOps specialists can solve tricky live problems and\nbuild a bridge between developers and operations.",{"type":281,"tag":282,"props":18176,"children":18177},{},[18178,18182],{"type":281,"tag":11280,"props":18179,"children":18180},{},[18181],{"type":291,"value":12038},{"type":291,"value":16936},{"title":8,"searchDepth":338,"depth":338,"links":18184},[18185,18186,18187,18188,18189,18190,18191,18192],{"id":16981,"depth":338,"text":16984},{"id":17109,"depth":338,"text":17112},{"id":17350,"depth":338,"text":17353},{"id":17492,"depth":338,"text":17495},{"id":17705,"depth":338,"text":17708},{"id":17876,"depth":338,"text":17879},{"id":18034,"depth":338,"text":18037},{"id":18131,"depth":338,"text":18134},{"_path":133,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":134,"description":135,"author":136,"image":137,"releaseDate":138,"blogCategories":18194,"articleTags":18195,"tags":18196,"body":18197,"_type":20,"_id":145,"_source":22,"_file":146,"_stem":147,"_extension":25},[15,16],[141,33],[143,144],{"type":278,"children":18198,"toc":18260},[18199,18205,18226,18231,18236,18242,18255],{"type":281,"tag":530,"props":18200,"children":18202},{"id":18201},"what-is-this",[18203],{"type":291,"value":18204},"What is this?",{"type":281,"tag":282,"props":18206,"children":18207},{},[18208,18210,18216,18218,18224],{"type":291,"value":18209},"This wrapper serves as a simple and cost-effective bridge that translates calls from the\n",{"type":281,"tag":286,"props":18211,"children":18213},{"href":18212},"https://docs.developer.amazonservices.com/en_US/dev_guide/index.html",[18214],{"type":291,"value":18215},"Amazon Marketplace Web Service (MWS)",{"type":291,"value":18217},"\nAPI to ",{"type":281,"tag":286,"props":18219,"children":18221},{"href":18220},"https://developer-docs.amazon.com/sp-api",[18222],{"type":291,"value":18223},"Selling Partner (SP) API",{"type":291,"value":18225}," calls. It was specifically developed for customers with outdated systems and limited\nbudgets, for whom a complete redevelopment of the Amazon interface would be economically unfeasible.\nThe wrapper allows these customers to continue their business even after the MWS interface is discontinued.",{"type":281,"tag":282,"props":18227,"children":18228},{},[18229],{"type":291,"value":18230},"Technically, the project is based on a Docker container that functions as a web server. This server receives MWS API calls,\ntranslates them into SP API calls, and converts the responses from the SP API back into the format of the MWS API.",{"type":281,"tag":282,"props":18232,"children":18233},{},[18234],{"type":291,"value":18235},"The idea for this wrapper originated from a proof of concept, with the aim to verify whether the interfaces are\nsufficiently similar to enable a direct translation. Despite concerns that the devil might be in the details,\nthe calls proved to be relatively simple to translate. It was only necessary to adjust some feed names\nand occasionally make two API calls to gather all the necessary information.\nOverall, the project has been surprisingly trouble-free.",{"type":281,"tag":530,"props":18237,"children":18239},{"id":18238},"download",[18240],{"type":291,"value":18241},"Download",{"type":281,"tag":282,"props":18243,"children":18244},{},[18245,18247,18253],{"type":291,"value":18246},"Interested? The project has been published as open-source on GitHub:\n",{"type":281,"tag":286,"props":18248,"children":18250},{"href":18249},"https://github.com/bhelm/Amazon-MWS-SP-Wrapper",[18251],{"type":291,"value":18252},"Amazon-MWS-SP-API-Wrapper",{"type":291,"value":18254},". This offer is aimed at developers\nwho also see the wrapper approach as the most efficient solution and want to contribute to the open-source community.",{"type":281,"tag":282,"props":18256,"children":18257},{},[18258],{"type":291,"value":18259},"If you need support integrating it into your application or if adjustments or extensions to the wrapper\nare necessary, we are happy to help. Since the wrapper is currently used by only a limited number of customers,\nit covers only part of the possible API calls and parameters and is by no means a \"complete solution\".",{"title":8,"searchDepth":338,"depth":338,"links":18261},[18262,18263],{"id":18201,"depth":338,"text":18204},{"id":18238,"depth":338,"text":18241},{"_path":149,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":150,"description":151,"author":136,"image":152,"releaseDate":153,"blogCategories":18265,"articleTags":18266,"tags":18267,"body":18268,"_type":20,"_id":158,"_source":22,"_file":159,"_stem":160,"_extension":25},[15,16],[156],[19],{"type":278,"children":18269,"toc":18819},[18270,18276,18281,18286,18302,18315,18321,18348,18365,18371,18376,18389,18402,18433,18468,18489,18544,18561,18587,18630,18659,18709,18728,18741,18783,18795,18815],{"type":281,"tag":530,"props":18271,"children":18273},{"id":18272},"how-to-resolve-selected-domains-over-vpn-on-linux",[18274],{"type":291,"value":18275},"How to resolve selected domains over VPN on Linux",{"type":281,"tag":282,"props":18277,"children":18278},{},[18279],{"type":291,"value":18280},"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":281,"tag":282,"props":18282,"children":18283},{},[18284],{"type":291,"value":18285},"For example, with Openvpn the option",{"type":281,"tag":301,"props":18287,"children":18291},{"className":18288,"code":18289,"language":18290,"meta":8,"style":8},"language-apache shiki shiki-themes github-dark github-dark monokai","pull-filter ignore redirect-gateway\n","apache",[18292],{"type":281,"tag":315,"props":18293,"children":18294},{"__ignoreMap":8},[18295],{"type":281,"tag":319,"props":18296,"children":18297},{"class":321,"line":322},[18298],{"type":281,"tag":319,"props":18299,"children":18300},{"style":332},[18301],{"type":291,"value":18289},{"type":281,"tag":282,"props":18303,"children":18304},{},[18305,18307,18313],{"type":291,"value":18306},"can be used to tell the ",{"type":281,"tag":315,"props":18308,"children":18310},{"className":18309},[],[18311],{"type":291,"value":18312},"openvpn-client",{"type":291,"value":18314}," to ignore all \"route all\" requests from the server.",{"type":281,"tag":530,"props":18316,"children":18318},{"id":18317},"fritzbox-example",[18319],{"type":291,"value":18320},"FRITZ!Box example",{"type":281,"tag":282,"props":18322,"children":18323},{},[18324,18326,18331,18333,18339,18341,18347],{"type":291,"value":18325},"Recently I had to use a VPN-Connection to a ",{"type":281,"tag":11280,"props":18327,"children":18328},{},[18329],{"type":291,"value":18330},"FRITZ!Box",{"type":291,"value":18332},". 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":281,"tag":315,"props":18334,"children":18336},{"className":18335},[],[18337],{"type":291,"value":18338}," workstation",{"type":291,"value":18340}," you can reach it using the \"workstation.fritz.box\" dns name. The fritz-box itself is also available on the\ndns name ",{"type":281,"tag":315,"props":18342,"children":18344},{"className":18343},[],[18345],{"type":291,"value":18346},"fritz.box",{"type":291,"value":564},{"type":281,"tag":282,"props":18349,"children":18350},{},[18351,18353,18358,18360,18364],{"type":291,"value":18352},"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":281,"tag":315,"props":18354,"children":18356},{"className":18355},[],[18357],{"type":291,"value":18346},{"type":291,"value":18359}," suffix to resolve over the ",{"type":281,"tag":11280,"props":18361,"children":18362},{},[18363],{"type":291,"value":18330},{"type":291,"value":564},{"type":281,"tag":530,"props":18366,"children":18368},{"id":18367},"solution-using-a-local-dns-server-dnsmasq",[18369],{"type":291,"value":18370},"Solution using a local DNS server - dnsmasq",{"type":281,"tag":282,"props":18372,"children":18373},{},[18374],{"type":291,"value":18375},"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":281,"tag":282,"props":18377,"children":18378},{},[18379,18381,18387],{"type":291,"value":18380},"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":281,"tag":315,"props":18382,"children":18384},{"className":18383},[],[18385],{"type":291,"value":18386},".1",{"type":291,"value":18388}," at the end. You can watch the VPN logs closely to learn which DNS server gets pushed on connect.",{"type":281,"tag":282,"props":18390,"children":18391},{},[18392,18394,18400],{"type":291,"value":18393},"There is a tool called ",{"type":281,"tag":315,"props":18395,"children":18397},{"className":18396},[],[18398],{"type":291,"value":18399},"dig",{"type":291,"value":18401}," which can do dns queries over specified dns servers, for example",{"type":281,"tag":301,"props":18403,"children":18407},{"className":18404,"code":18405,"language":18406,"meta":8,"style":8},"language-bash shiki shiki-themes github-dark github-dark monokai","dig @192.168.1.1 a fritz.box\n","bash",[18408],{"type":281,"tag":315,"props":18409,"children":18410},{"__ignoreMap":8},[18411],{"type":281,"tag":319,"props":18412,"children":18413},{"class":321,"line":322},[18414,18418,18423,18428],{"type":281,"tag":319,"props":18415,"children":18416},{"style":1607},[18417],{"type":291,"value":18399},{"type":281,"tag":319,"props":18419,"children":18420},{"style":365},[18421],{"type":291,"value":18422}," @192.168.1.1",{"type":281,"tag":319,"props":18424,"children":18425},{"style":365},[18426],{"type":291,"value":18427}," a",{"type":281,"tag":319,"props":18429,"children":18430},{"style":365},[18431],{"type":291,"value":18432}," fritz.box\n",{"type":281,"tag":282,"props":18434,"children":18435},{},[18436,18438,18444,18446,18451,18453,18459,18461,18467],{"type":291,"value":18437},"will ask the dns server ",{"type":281,"tag":315,"props":18439,"children":18441},{"className":18440},[],[18442],{"type":291,"value":18443},"192.168.1.1",{"type":291,"value":18445}," for the ip of ",{"type":281,"tag":315,"props":18447,"children":18449},{"className":18448},[],[18450],{"type":291,"value":18346},{"type":291,"value":18452},". ",{"type":281,"tag":315,"props":18454,"children":18456},{"className":18455},[],[18457],{"type":291,"value":18458},"Dig",{"type":291,"value":18460}," 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":281,"tag":315,"props":18462,"children":18464},{"className":18463},[],[18465],{"type":291,"value":18466},"dnsutils",{"type":291,"value":564},{"type":281,"tag":282,"props":18469,"children":18470},{},[18471,18473,18479,18481,18487],{"type":291,"value":18472},"First install ",{"type":281,"tag":315,"props":18474,"children":18476},{"className":18475},[],[18477],{"type":291,"value":18478},"dnsmasq",{"type":291,"value":18480}," on your Linux and edit its configuration (usually lives in ",{"type":281,"tag":315,"props":18482,"children":18484},{"className":18483},[],[18485],{"type":291,"value":18486},"/etc/dnsmasq.conf",{"type":291,"value":18488},"). Add these lines\nhere:",{"type":281,"tag":301,"props":18490,"children":18492},{"className":18288,"code":18491,"language":18290,"meta":8,"style":8},"resolv-file=/etc/resolv.dnsmasq.conf\nserver=/fritz.box/192.168.1.1\n",[18493],{"type":281,"tag":315,"props":18494,"children":18495},{"__ignoreMap":8},[18496,18504],{"type":281,"tag":319,"props":18497,"children":18498},{"class":321,"line":322},[18499],{"type":281,"tag":319,"props":18500,"children":18501},{"style":332},[18502],{"type":291,"value":18503},"resolv-file=/etc/resolv.dnsmasq.conf\n",{"type":281,"tag":319,"props":18505,"children":18506},{"class":321,"line":338},[18507,18512,18517,18521,18526,18530,18535,18539],{"type":281,"tag":319,"props":18508,"children":18509},{"style":332},[18510],{"type":291,"value":18511},"server=/fritz.box/",{"type":281,"tag":319,"props":18513,"children":18514},{"style":1622},[18515],{"type":291,"value":18516},"192",{"type":281,"tag":319,"props":18518,"children":18519},{"style":332},[18520],{"type":291,"value":564},{"type":281,"tag":319,"props":18522,"children":18523},{"style":1622},[18524],{"type":291,"value":18525},"168",{"type":281,"tag":319,"props":18527,"children":18528},{"style":332},[18529],{"type":291,"value":564},{"type":281,"tag":319,"props":18531,"children":18532},{"style":1622},[18533],{"type":291,"value":18534},"1",{"type":281,"tag":319,"props":18536,"children":18537},{"style":332},[18538],{"type":291,"value":564},{"type":281,"tag":319,"props":18540,"children":18541},{"style":1622},[18542],{"type":291,"value":18543},"1\n",{"type":281,"tag":282,"props":18545,"children":18546},{},[18547,18552,18554,18559],{"type":281,"tag":315,"props":18548,"children":18550},{"className":18549},[],[18551],{"type":291,"value":18346},{"type":291,"value":18553}," is the domain you want to resolve over the VPN-Dns-server, ",{"type":281,"tag":315,"props":18555,"children":18557},{"className":18556},[],[18558],{"type":291,"value":18443},{"type":291,"value":18560}," in this example.",{"type":281,"tag":282,"props":18562,"children":18563},{},[18564,18565,18570,18572,18577,18579,18585],{"type":291,"value":10817},{"type":281,"tag":11280,"props":18566,"children":18567},{},[18568],{"type":291,"value":18569},"Resolv-File",{"type":291,"value":18571}," will tell ",{"type":281,"tag":315,"props":18573,"children":18575},{"className":18574},[],[18576],{"type":291,"value":18478},{"type":291,"value":18578}," how it should resolve its dns queries in case there are no other rules, so let's\ncreate\na ",{"type":281,"tag":315,"props":18580,"children":18582},{"className":18581},[],[18583],{"type":291,"value":18584},"/etc/resolv.dnsmasq.conf",{"type":291,"value":18586},"\nwith content",{"type":281,"tag":301,"props":18588,"children":18590},{"className":18288,"code":18589,"language":18290,"meta":8,"style":8},"nameserver 1.1.1.1\n",[18591],{"type":281,"tag":315,"props":18592,"children":18593},{"__ignoreMap":8},[18594],{"type":281,"tag":319,"props":18595,"children":18596},{"class":321,"line":322},[18597,18602,18606,18610,18614,18618,18622,18626],{"type":281,"tag":319,"props":18598,"children":18599},{"style":332},[18600],{"type":291,"value":18601},"nameserver ",{"type":281,"tag":319,"props":18603,"children":18604},{"style":1622},[18605],{"type":291,"value":18534},{"type":281,"tag":319,"props":18607,"children":18608},{"style":332},[18609],{"type":291,"value":564},{"type":281,"tag":319,"props":18611,"children":18612},{"style":1622},[18613],{"type":291,"value":18534},{"type":281,"tag":319,"props":18615,"children":18616},{"style":332},[18617],{"type":291,"value":564},{"type":281,"tag":319,"props":18619,"children":18620},{"style":1622},[18621],{"type":291,"value":18534},{"type":281,"tag":319,"props":18623,"children":18624},{"style":332},[18625],{"type":291,"value":564},{"type":281,"tag":319,"props":18627,"children":18628},{"style":1622},[18629],{"type":291,"value":18543},{"type":281,"tag":282,"props":18631,"children":18632},{},[18633,18635,18641,18643,18649,18651,18657],{"type":291,"value":18634},"If you use a static network configuration, you now can just edit it to use ",{"type":281,"tag":315,"props":18636,"children":18638},{"className":18637},[],[18639],{"type":291,"value":18640},"127.0.0.1",{"type":291,"value":18642}," 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":281,"tag":315,"props":18644,"children":18646},{"className":18645},[],[18647],{"type":291,"value":18648},"dhclient",{"type":291,"value":18650},". In that case edit ",{"type":281,"tag":315,"props":18652,"children":18654},{"className":18653},[],[18655],{"type":291,"value":18656},"/etc/dhcp/dhclient.conf",{"type":291,"value":18658}," and add:",{"type":281,"tag":301,"props":18660,"children":18662},{"className":18288,"code":18661,"language":18290,"meta":8,"style":8},"prepend domain-name-servers 127.0.0.1;\n",[18663],{"type":281,"tag":315,"props":18664,"children":18665},{"__ignoreMap":8},[18666],{"type":281,"tag":319,"props":18667,"children":18668},{"class":321,"line":322},[18669,18674,18679,18683,18688,18692,18696,18700,18704],{"type":281,"tag":319,"props":18670,"children":18671},{"style":332},[18672],{"type":291,"value":18673},"prepend domain-name-servers ",{"type":281,"tag":319,"props":18675,"children":18676},{"style":1622},[18677],{"type":291,"value":18678},"127",{"type":281,"tag":319,"props":18680,"children":18681},{"style":332},[18682],{"type":291,"value":564},{"type":281,"tag":319,"props":18684,"children":18685},{"style":1622},[18686],{"type":291,"value":18687},"0",{"type":281,"tag":319,"props":18689,"children":18690},{"style":332},[18691],{"type":291,"value":564},{"type":281,"tag":319,"props":18693,"children":18694},{"style":1622},[18695],{"type":291,"value":18687},{"type":281,"tag":319,"props":18697,"children":18698},{"style":332},[18699],{"type":291,"value":564},{"type":281,"tag":319,"props":18701,"children":18702},{"style":1622},[18703],{"type":291,"value":18534},{"type":281,"tag":319,"props":18705,"children":18706},{"style":332},[18707],{"type":291,"value":18708},";\n",{"type":281,"tag":282,"props":18710,"children":18711},{},[18712,18714,18719,18721,18726],{"type":291,"value":18713},"That's it. All you have to do now is to restart ",{"type":281,"tag":315,"props":18715,"children":18717},{"className":18716},[],[18718],{"type":291,"value":18478},{"type":291,"value":18720}," so it reloads its config and reconnect/restart ",{"type":281,"tag":315,"props":18722,"children":18724},{"className":18723},[],[18725],{"type":291,"value":18648},{"type":291,"value":18727},"\n(disconnecting and reconnecting the network may work, reboot the machine when in doubt).",{"type":281,"tag":282,"props":18729,"children":18730},{},[18731,18733,18739],{"type":291,"value":18732},"Now you can check if the file ",{"type":281,"tag":315,"props":18734,"children":18736},{"className":18735},[],[18737],{"type":291,"value":18738},"/etc/resolv.conf",{"type":291,"value":18740}," has",{"type":281,"tag":301,"props":18742,"children":18744},{"className":18288,"code":18743,"language":18290,"meta":8,"style":8},"nameserver 127.0.0.1\n",[18745],{"type":281,"tag":315,"props":18746,"children":18747},{"__ignoreMap":8},[18748],{"type":281,"tag":319,"props":18749,"children":18750},{"class":321,"line":322},[18751,18755,18759,18763,18767,18771,18775,18779],{"type":281,"tag":319,"props":18752,"children":18753},{"style":332},[18754],{"type":291,"value":18601},{"type":281,"tag":319,"props":18756,"children":18757},{"style":1622},[18758],{"type":291,"value":18678},{"type":281,"tag":319,"props":18760,"children":18761},{"style":332},[18762],{"type":291,"value":564},{"type":281,"tag":319,"props":18764,"children":18765},{"style":1622},[18766],{"type":291,"value":18687},{"type":281,"tag":319,"props":18768,"children":18769},{"style":332},[18770],{"type":291,"value":564},{"type":281,"tag":319,"props":18772,"children":18773},{"style":1622},[18774],{"type":291,"value":18687},{"type":281,"tag":319,"props":18776,"children":18777},{"style":332},[18778],{"type":291,"value":564},{"type":281,"tag":319,"props":18780,"children":18781},{"style":1622},[18782],{"type":291,"value":18543},{"type":281,"tag":282,"props":18784,"children":18785},{},[18786,18788,18793],{"type":291,"value":18787},"as first nameserver. If it has, the selected domain (",{"type":281,"tag":315,"props":18789,"children":18791},{"className":18790},[],[18792],{"type":291,"value":18346},{"type":291,"value":18794}," in my example) should now resolve.",{"type":281,"tag":282,"props":18796,"children":18797},{},[18798,18800,18805,18807,18813],{"type":291,"value":18799},"On ",{"type":281,"tag":315,"props":18801,"children":18803},{"className":18802},[],[18804],{"type":291,"value":18478},{"type":291,"value":18806},", you can add multiple ",{"type":281,"tag":315,"props":18808,"children":18810},{"className":18809},[],[18811],{"type":291,"value":18812},"server=",{"type":291,"value":18814}," lines, which comes in handy if you have multiple domains that need to be\nresolved over different DNS servers.",{"type":281,"tag":1477,"props":18816,"children":18817},{},[18818],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":18820},[18821,18822,18823],{"id":18272,"depth":338,"text":18275},{"id":18317,"depth":338,"text":18320},{"id":18367,"depth":338,"text":18370},{"_path":162,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":163,"description":164,"author":136,"image":165,"releaseDate":166,"blogCategories":18825,"articleTags":18826,"tags":18827,"body":18828,"_type":20,"_id":170,"_source":22,"_file":171,"_stem":172,"_extension":25},[34,16],[156],[36],{"type":278,"children":18829,"toc":19321},[18830,18836,18841,18852,18857,18863,18868,18887,18896,18901,18906,19224,19229,19234,19239,19244,19255,19305,19311,19317],{"type":281,"tag":530,"props":18831,"children":18833},{"id":18832},"shopware-5-parallel-thumbnail-generation-after-moving-a-shopware-5-system-to-another-server",[18834],{"type":291,"value":18835},"Shopware 5 - parallel thumbnail generation after moving a Shopware 5 system to another server",{"type":281,"tag":282,"props":18837,"children":18838},{},[18839],{"type":291,"value":18840},"We had a customer with 400k images and 1600k thumbnails that needed to move from an old hdd based server to a new ssd based one. The problem was that the old server was so slow that it already needed two days to count through all images, not speaking about coping them.",{"type":281,"tag":282,"props":18842,"children":18843},{},[18844,18846],{"type":291,"value":18845},"So we decided to copy only the original images and regenerate the Thumbnails. For copying the original images, I created a small console command that exports all paths of the original images that we need to copy: ",{"type":281,"tag":286,"props":18847,"children":18849},{"href":18848},"https://gist.github.com/bhelm/2d30f0cebcf4a7d8ea41c532ec67cd62",[18850],{"type":291,"value":18851},"ExportImagesCommand.php",{"type":281,"tag":282,"props":18853,"children":18854},{},[18855],{"type":291,"value":18856},"This filelist can be used with tar -T or rsync --files-from= options that tells these tools to only process the listed files. for the initial copy process, tar is highly recommended, as it just picks up the files listed without doing any \"calculation\" as rsync does.",{"type":281,"tag":530,"props":18858,"children":18860},{"id":18859},"sw5-default-thumbnail-generation-would-have-taken-80-hours",[18861],{"type":291,"value":18862},"SW5 default thumbnail generation would have taken 80 hours",{"type":281,"tag":282,"props":18864,"children":18865},{},[18866],{"type":291,"value":18867},"... and would only use half of a core.",{"type":281,"tag":282,"props":18869,"children":18870},{},[18871,18873,18878,18880,18885],{"type":291,"value":18872},"I was curious if I can speed up this generation process. The server itself has 32 cores available, so I copied the ",{"type":281,"tag":11370,"props":18874,"children":18875},{},[18876],{"type":291,"value":18877},"generate thumbnail",{"type":291,"value":18879}," command from sw5 and modified it to work in batches with an ",{"type":281,"tag":11370,"props":18881,"children":18882},{},[18883],{"type":291,"value":18884},"--batch",{"type":291,"value":18886}," parameter:",{"type":281,"tag":282,"props":18888,"children":18889},{},[18890],{"type":281,"tag":286,"props":18891,"children":18893},{"href":18892},"https://gist.github.com/bhelm/2015d3829d4a3f24f9760f6e4e1aac1f",[18894],{"type":291,"value":18895},"ParallelThumbnailGenerateCommand.php",{"type":281,"tag":282,"props":18897,"children":18898},{},[18899],{"type":291,"value":18900},"To make it work, I just modified the Shopware core at engine/Shopware/Models/Media/Repository.php",{"type":281,"tag":282,"props":18902,"children":18903},{},[18904],{"type":291,"value":18905},"I just changed the getAlbumMediaQuery function to:",{"type":281,"tag":301,"props":18907,"children":18911},{"className":18908,"code":18909,"language":18910,"meta":8,"style":8},"language-cpp shiki shiki-themes github-dark github-dark monokai","public function getAlbumMediaQuery($albumId, $filter = null, $orderBy = null, $offset = null, $limit = null, $validTypes = null, $batch = null)\n{\n$builder = $this->getAlbumMediaQueryBuilder($albumId, $filter, $orderBy, $validTypes);\nif (is_numeric($batch)) {\n$builder->andWhere('MOD(media.id, 1000) = ?3');\n$builder->setParameter(3, $batch);\n}\n\n    if ($limit !== null) {\n        $builder->setFirstResult($offset)\n                ->setMaxResults($limit);\n    }\n\n    return $builder->getQuery();\n}\n","cpp",[18912],{"type":281,"tag":315,"props":18913,"children":18914},{"__ignoreMap":8},[18915,18988,18995,19033,19054,19082,19108,19115,19122,19144,19162,19180,19187,19194,19217],{"type":281,"tag":319,"props":18916,"children":18917},{"class":321,"line":322},[18918,18923,18928,18933,18938,18943,18947,18952,18956,18961,18965,18970,18974,18979,18983],{"type":281,"tag":319,"props":18919,"children":18920},{"style":332},[18921],{"type":291,"value":18922},"public function ",{"type":281,"tag":319,"props":18924,"children":18925},{"style":1607},[18926],{"type":291,"value":18927},"getAlbumMediaQuery",{"type":281,"tag":319,"props":18929,"children":18930},{"style":332},[18931],{"type":291,"value":18932},"($albumId, $filter ",{"type":281,"tag":319,"props":18934,"children":18935},{"style":7965},[18936],{"type":291,"value":18937},"=",{"type":281,"tag":319,"props":18939,"children":18940},{"style":332},[18941],{"type":291,"value":18942}," null, $orderBy ",{"type":281,"tag":319,"props":18944,"children":18945},{"style":7965},[18946],{"type":291,"value":18937},{"type":281,"tag":319,"props":18948,"children":18949},{"style":332},[18950],{"type":291,"value":18951}," null, $offset ",{"type":281,"tag":319,"props":18953,"children":18954},{"style":7965},[18955],{"type":291,"value":18937},{"type":281,"tag":319,"props":18957,"children":18958},{"style":332},[18959],{"type":291,"value":18960}," null, $limit ",{"type":281,"tag":319,"props":18962,"children":18963},{"style":7965},[18964],{"type":291,"value":18937},{"type":281,"tag":319,"props":18966,"children":18967},{"style":332},[18968],{"type":291,"value":18969}," null, $validTypes ",{"type":281,"tag":319,"props":18971,"children":18972},{"style":7965},[18973],{"type":291,"value":18937},{"type":281,"tag":319,"props":18975,"children":18976},{"style":332},[18977],{"type":291,"value":18978}," null, $batch ",{"type":281,"tag":319,"props":18980,"children":18981},{"style":7965},[18982],{"type":291,"value":18937},{"type":281,"tag":319,"props":18984,"children":18985},{"style":332},[18986],{"type":291,"value":18987}," null)\n",{"type":281,"tag":319,"props":18989,"children":18990},{"class":321,"line":338},[18991],{"type":281,"tag":319,"props":18992,"children":18993},{"style":332},[18994],{"type":291,"value":5052},{"type":281,"tag":319,"props":18996,"children":18997},{"class":321,"line":351},[18998,19003,19007,19012,19018,19023,19028],{"type":281,"tag":319,"props":18999,"children":19000},{"style":332},[19001],{"type":291,"value":19002},"$builder ",{"type":281,"tag":319,"props":19004,"children":19005},{"style":7965},[19006],{"type":291,"value":18937},{"type":281,"tag":319,"props":19008,"children":19009},{"style":332},[19010],{"type":291,"value":19011}," $",{"type":281,"tag":319,"props":19013,"children":19015},{"style":19014},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-sepia:#FD971F",[19016],{"type":291,"value":19017},"this",{"type":281,"tag":319,"props":19019,"children":19020},{"style":332},[19021],{"type":291,"value":19022},"->",{"type":281,"tag":319,"props":19024,"children":19025},{"style":1607},[19026],{"type":291,"value":19027},"getAlbumMediaQueryBuilder",{"type":281,"tag":319,"props":19029,"children":19030},{"style":332},[19031],{"type":291,"value":19032},"($albumId, $filter, $orderBy, $validTypes);\n",{"type":281,"tag":319,"props":19034,"children":19035},{"class":321,"line":371},[19036,19040,19044,19049],{"type":281,"tag":319,"props":19037,"children":19038},{"style":7965},[19039],{"type":291,"value":1895},{"type":281,"tag":319,"props":19041,"children":19042},{"style":332},[19043],{"type":291,"value":12351},{"type":281,"tag":319,"props":19045,"children":19046},{"style":1607},[19047],{"type":291,"value":19048},"is_numeric",{"type":281,"tag":319,"props":19050,"children":19051},{"style":332},[19052],{"type":291,"value":19053},"($batch)) {\n",{"type":281,"tag":319,"props":19055,"children":19056},{"class":321,"line":306},[19057,19062,19067,19072,19077],{"type":281,"tag":319,"props":19058,"children":19059},{"style":332},[19060],{"type":291,"value":19061},"$builder->",{"type":281,"tag":319,"props":19063,"children":19064},{"style":1607},[19065],{"type":291,"value":19066},"andWhere",{"type":281,"tag":319,"props":19068,"children":19069},{"style":332},[19070],{"type":291,"value":19071},"(",{"type":281,"tag":319,"props":19073,"children":19074},{"style":365},[19075],{"type":291,"value":19076},"'MOD(media.id, 1000) = ?3'",{"type":281,"tag":319,"props":19078,"children":19079},{"style":332},[19080],{"type":291,"value":19081},");\n",{"type":281,"tag":319,"props":19083,"children":19084},{"class":321,"line":307},[19085,19089,19094,19098,19103],{"type":281,"tag":319,"props":19086,"children":19087},{"style":332},[19088],{"type":291,"value":19061},{"type":281,"tag":319,"props":19090,"children":19091},{"style":1607},[19092],{"type":291,"value":19093},"setParameter",{"type":281,"tag":319,"props":19095,"children":19096},{"style":332},[19097],{"type":291,"value":19071},{"type":281,"tag":319,"props":19099,"children":19100},{"style":1622},[19101],{"type":291,"value":19102},"3",{"type":281,"tag":319,"props":19104,"children":19105},{"style":332},[19106],{"type":291,"value":19107},", $batch);\n",{"type":281,"tag":319,"props":19109,"children":19110},{"class":321,"line":308},[19111],{"type":281,"tag":319,"props":19112,"children":19113},{"style":332},[19114],{"type":291,"value":6041},{"type":281,"tag":319,"props":19116,"children":19117},{"class":321,"line":309},[19118],{"type":281,"tag":319,"props":19119,"children":19120},{"emptyLinePlaceholder":1042},[19121],{"type":291,"value":1045},{"type":281,"tag":319,"props":19123,"children":19124},{"class":321,"line":310},[19125,19129,19134,19139],{"type":281,"tag":319,"props":19126,"children":19127},{"style":7965},[19128],{"type":291,"value":8536},{"type":281,"tag":319,"props":19130,"children":19131},{"style":332},[19132],{"type":291,"value":19133}," ($limit ",{"type":281,"tag":319,"props":19135,"children":19136},{"style":7965},[19137],{"type":291,"value":19138},"!==",{"type":281,"tag":319,"props":19140,"children":19141},{"style":332},[19142],{"type":291,"value":19143}," null) {\n",{"type":281,"tag":319,"props":19145,"children":19146},{"class":321,"line":973},[19147,19152,19157],{"type":281,"tag":319,"props":19148,"children":19149},{"style":332},[19150],{"type":291,"value":19151},"        $builder->",{"type":281,"tag":319,"props":19153,"children":19154},{"style":1607},[19155],{"type":291,"value":19156},"setFirstResult",{"type":281,"tag":319,"props":19158,"children":19159},{"style":332},[19160],{"type":291,"value":19161},"($offset)\n",{"type":281,"tag":319,"props":19163,"children":19164},{"class":321,"line":986},[19165,19170,19175],{"type":281,"tag":319,"props":19166,"children":19167},{"style":7965},[19168],{"type":291,"value":19169},"                ->",{"type":281,"tag":319,"props":19171,"children":19172},{"style":1607},[19173],{"type":291,"value":19174},"setMaxResults",{"type":281,"tag":319,"props":19176,"children":19177},{"style":332},[19178],{"type":291,"value":19179},"($limit);\n",{"type":281,"tag":319,"props":19181,"children":19182},{"class":321,"line":999},[19183],{"type":281,"tag":319,"props":19184,"children":19185},{"style":332},[19186],{"type":291,"value":5614},{"type":281,"tag":319,"props":19188,"children":19189},{"class":321,"line":1012},[19190],{"type":281,"tag":319,"props":19191,"children":19192},{"emptyLinePlaceholder":1042},[19193],{"type":291,"value":1045},{"type":281,"tag":319,"props":19195,"children":19196},{"class":321,"line":1025},[19197,19202,19207,19212],{"type":281,"tag":319,"props":19198,"children":19199},{"style":7965},[19200],{"type":291,"value":19201},"    return",{"type":281,"tag":319,"props":19203,"children":19204},{"style":332},[19205],{"type":291,"value":19206}," $builder->",{"type":281,"tag":319,"props":19208,"children":19209},{"style":1607},[19210],{"type":291,"value":19211},"getQuery",{"type":281,"tag":319,"props":19213,"children":19214},{"style":332},[19215],{"type":291,"value":19216},"();\n",{"type":281,"tag":319,"props":19218,"children":19219},{"class":321,"line":1038},[19220],{"type":281,"tag":319,"props":19221,"children":19222},{"style":332},[19223],{"type":291,"value":6041},{"type":281,"tag":282,"props":19225,"children":19226},{},[19227],{"type":291,"value":19228},"It is an optional parameter and won’t break anything. If you do a Shopware update, this would be gone, but as I was in the quest to speed up things for a one-time task, I just modified it in the core instead of finding a long-term solution.",{"type":281,"tag":282,"props":19230,"children":19231},{},[19232],{"type":291,"value":19233},"What this function does is calculating a modulo of 1000 on the media id and compares it with the batch id. So we basically have 1000 batches to process until all work is done.",{"type":281,"tag":282,"props":19235,"children":19236},{},[19237],{"type":291,"value":19238},"Now we only need to start all 1000 batches in a parallel manner. For doing so, I used the very helpful tool parallel - which is available in Linux:",{"type":281,"tag":282,"props":19240,"children":19241},{},[19242],{"type":291,"value":19243},"It starts 64 batches in parallel and continues its work until all 1000 batches are finished.",{"type":281,"tag":282,"props":19245,"children":19246},{},[19247,19249,19253],{"type":291,"value":19248},"And this is how it looks at ",{"type":281,"tag":11370,"props":19250,"children":19251},{},[19252],{"type":291,"value":18090},{"type":291,"value":19254},":",{"type":281,"tag":301,"props":19256,"children":19258},{"className":18404,"code":19257,"language":18406,"meta":8,"style":8},"parallel -j 64 ./bin/console my:image:generate:thumbnails --batch ::: {0..999}\n",[19259],{"type":281,"tag":315,"props":19260,"children":19261},{"__ignoreMap":8},[19262],{"type":281,"tag":319,"props":19263,"children":19264},{"class":321,"line":322},[19265,19270,19275,19280,19285,19290,19295,19300],{"type":281,"tag":319,"props":19266,"children":19267},{"style":1607},[19268],{"type":291,"value":19269},"parallel",{"type":281,"tag":319,"props":19271,"children":19272},{"style":1622},[19273],{"type":291,"value":19274}," -j",{"type":281,"tag":319,"props":19276,"children":19277},{"style":1622},[19278],{"type":291,"value":19279}," 64",{"type":281,"tag":319,"props":19281,"children":19282},{"style":365},[19283],{"type":291,"value":19284}," ./bin/console",{"type":281,"tag":319,"props":19286,"children":19287},{"style":365},[19288],{"type":291,"value":19289}," my:image:generate:thumbnails",{"type":281,"tag":319,"props":19291,"children":19292},{"style":1622},[19293],{"type":291,"value":19294}," --batch",{"type":281,"tag":319,"props":19296,"children":19297},{"style":365},[19298],{"type":291,"value":19299}," :::",{"type":281,"tag":319,"props":19301,"children":19302},{"style":365},[19303],{"type":291,"value":19304}," {0..999}\n",{"type":281,"tag":1499,"props":19306,"children":19310},{"alt":18090,"aspect-ratio":19307,"height":1502,"object-fit":19308,"src":19309},"2","contain","/blog/htop.png",[],{"type":281,"tag":530,"props":19312,"children":19314},{"id":19313},"finally-all-the-work-is-now-finished-in-35-hours-instead-of-80",[19315],{"type":291,"value":19316},"Finally, all the work is now finished in 3.5 hours instead of 80.",{"type":281,"tag":1477,"props":19318,"children":19319},{},[19320],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":19322},[19323,19324,19325],{"id":18832,"depth":338,"text":18835},{"id":18859,"depth":338,"text":18862},{"id":19313,"depth":338,"text":19316},{"_path":174,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":175,"description":176,"author":136,"image":177,"releaseDate":178,"blogCategories":19327,"tags":19328,"body":19329,"_type":20,"_id":181,"_source":22,"_file":182,"_stem":183,"_extension":25},[15,104],[19],{"type":278,"children":19330,"toc":19786},[19331,19337,19349,19355,19360,19366,19371,19409,19415,19420,19426,19438,19556,19574,19580,19736,19741,19747,19776,19782],{"type":281,"tag":530,"props":19332,"children":19334},{"id":19333},"what-is-btrfs-fragmentation",[19335],{"type":291,"value":19336},"What is BTRFS fragmentation?",{"type":281,"tag":282,"props":19338,"children":19339},{},[19340,19342,19347],{"type":291,"value":19341},"Most of the best BTRFS features are powered by the ",{"type":281,"tag":11370,"props":19343,"children":19344},{},[19345],{"type":291,"value":19346},"copy-on-write technology",{"type":291,"value":19348},". 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":281,"tag":530,"props":19350,"children":19352},{"id":19351},"btrfs-fragmentation-can-hurt-the-performance-of-your-system",[19353],{"type":291,"value":19354},"BTRFS fragmentation can hurt the performance of your System",{"type":281,"tag":282,"props":19356,"children":19357},{},[19358],{"type":291,"value":19359},"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":281,"tag":530,"props":19361,"children":19363},{"id":19362},"btrfs-fragmentation-can-block-huge-amounts-of-disk-space",[19364],{"type":291,"value":19365},"BTRFS fragmentation can block huge amounts of disk space",{"type":281,"tag":282,"props":19367,"children":19368},{},[19369],{"type":291,"value":19370},"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":281,"tag":282,"props":19372,"children":19373},{},[19374,19376,19381,19382,19387,19388,19393,19395,19400,19402,19407],{"type":291,"value":19375},"If you see your btrfs filesystem using ",{"type":281,"tag":11280,"props":19377,"children":19378},{},[19379],{"type":291,"value":19380},"80GB",{"type":291,"value":6302},{"type":281,"tag":11370,"props":19383,"children":19384},{},[19385],{"type":291,"value":19386},"df",{"type":291,"value":9323},{"type":281,"tag":11370,"props":19389,"children":19390},{},[19391],{"type":291,"value":19392},"btrfs fi show",{"type":291,"value":19394}," while ",{"type":281,"tag":11370,"props":19396,"children":19397},{},[19398],{"type":291,"value":19399},"du -hsx",{"type":291,"value":19401}," only shows ",{"type":281,"tag":11280,"props":19403,"children":19404},{},[19405],{"type":291,"value":19406},"54GB",{"type":291,"value":19408}," 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":281,"tag":530,"props":19410,"children":19412},{"id":19411},"btrfs-filesystem-defrag",[19413],{"type":291,"value":19414},"BTRFS filesystem defrag",{"type":281,"tag":282,"props":19416,"children":19417},{},[19418],{"type":291,"value":19419},"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":281,"tag":530,"props":19421,"children":19423},{"id":19422},"find-the-most-fragmented-files-on-your-system",[19424],{"type":291,"value":19425},"Find the most fragmented files on your System",{"type":281,"tag":282,"props":19427,"children":19428},{},[19429,19431,19436],{"type":291,"value":19430},"There is a linux-tool called ",{"type":281,"tag":11370,"props":19432,"children":19433},{},[19434],{"type":291,"value":19435},"filefrag",{"type":291,"value":19437}," 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":281,"tag":301,"props":19439,"children":19441},{"className":18404,"code":19440,"language":18406,"meta":8,"style":8},"find / -xdev -type f| xargs filefrag 2>/dev/null | sed 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/' | awk -F ' ' '$1 > 500' | sort -n -r\n",[19442],{"type":281,"tag":315,"props":19443,"children":19444},{"__ignoreMap":8},[19445],{"type":281,"tag":319,"props":19446,"children":19447},{"class":321,"line":322},[19448,19453,19458,19463,19468,19473,19478,19483,19488,19493,19498,19503,19508,19513,19517,19522,19527,19532,19537,19541,19546,19551],{"type":281,"tag":319,"props":19449,"children":19450},{"style":1607},[19451],{"type":291,"value":19452},"find",{"type":281,"tag":319,"props":19454,"children":19455},{"style":365},[19456],{"type":291,"value":19457}," /",{"type":281,"tag":319,"props":19459,"children":19460},{"style":1622},[19461],{"type":291,"value":19462}," -xdev",{"type":281,"tag":319,"props":19464,"children":19465},{"style":1622},[19466],{"type":291,"value":19467}," -type",{"type":281,"tag":319,"props":19469,"children":19470},{"style":365},[19471],{"type":291,"value":19472}," f",{"type":281,"tag":319,"props":19474,"children":19475},{"style":7965},[19476],{"type":291,"value":19477},"|",{"type":281,"tag":319,"props":19479,"children":19480},{"style":1607},[19481],{"type":291,"value":19482}," xargs",{"type":281,"tag":319,"props":19484,"children":19485},{"style":365},[19486],{"type":291,"value":19487}," filefrag",{"type":281,"tag":319,"props":19489,"children":19490},{"style":7965},[19491],{"type":291,"value":19492}," 2>",{"type":281,"tag":319,"props":19494,"children":19495},{"style":365},[19496],{"type":291,"value":19497},"/dev/null",{"type":281,"tag":319,"props":19499,"children":19500},{"style":7965},[19501],{"type":291,"value":19502}," |",{"type":281,"tag":319,"props":19504,"children":19505},{"style":1607},[19506],{"type":291,"value":19507}," sed",{"type":281,"tag":319,"props":19509,"children":19510},{"style":365},[19511],{"type":291,"value":19512}," 's/^\\(.*\\): \\([0-9]\\+\\) extent.*/\\2 \\1/'",{"type":281,"tag":319,"props":19514,"children":19515},{"style":7965},[19516],{"type":291,"value":19502},{"type":281,"tag":319,"props":19518,"children":19519},{"style":1607},[19520],{"type":291,"value":19521}," awk",{"type":281,"tag":319,"props":19523,"children":19524},{"style":1622},[19525],{"type":291,"value":19526}," -F",{"type":281,"tag":319,"props":19528,"children":19529},{"style":365},[19530],{"type":291,"value":19531}," ' '",{"type":281,"tag":319,"props":19533,"children":19534},{"style":365},[19535],{"type":291,"value":19536}," '$1 > 500'",{"type":281,"tag":319,"props":19538,"children":19539},{"style":7965},[19540],{"type":291,"value":19502},{"type":281,"tag":319,"props":19542,"children":19543},{"style":1607},[19544],{"type":291,"value":19545}," sort",{"type":281,"tag":319,"props":19547,"children":19548},{"style":1622},[19549],{"type":291,"value":19550}," -n",{"type":281,"tag":319,"props":19552,"children":19553},{"style":1622},[19554],{"type":291,"value":19555}," -r\n",{"type":281,"tag":282,"props":19557,"children":19558},{},[19559,19561,19566,19568,19572],{"type":291,"value":19560},"You should review this list. If there is something with 10k+ extends, it is a candidate to be flagged as ",{"type":281,"tag":11370,"props":19562,"children":19563},{},[19564],{"type":291,"value":19565},"nodatacow",{"type":291,"value":19567},". 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":281,"tag":11370,"props":19569,"children":19570},{},[19571],{"type":291,"value":19565},{"type":291,"value":19573},", 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":281,"tag":530,"props":19575,"children":19577},{"id":19576},"if-everything-is-fine-you-can-go-ahead-and-defrag-all-files-on-that-list",[19578],{"type":291,"value":19579},"If everything is fine, you can go ahead and defrag all files on that list",{"type":281,"tag":301,"props":19581,"children":19583},{"className":18404,"code":19582,"language":18406,"meta":8,"style":8},"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",[19584],{"type":281,"tag":315,"props":19585,"children":19586},{"__ignoreMap":8},[19587,19647],{"type":281,"tag":319,"props":19588,"children":19589},{"class":321,"line":322},[19590,19594,19598,19602,19606,19610,19614,19618,19622,19626,19630,19634,19638,19642],{"type":281,"tag":319,"props":19591,"children":19592},{"style":1607},[19593],{"type":291,"value":19452},{"type":281,"tag":319,"props":19595,"children":19596},{"style":365},[19597],{"type":291,"value":19457},{"type":281,"tag":319,"props":19599,"children":19600},{"style":1622},[19601],{"type":291,"value":19462},{"type":281,"tag":319,"props":19603,"children":19604},{"style":1622},[19605],{"type":291,"value":19467},{"type":281,"tag":319,"props":19607,"children":19608},{"style":365},[19609],{"type":291,"value":19472},{"type":281,"tag":319,"props":19611,"children":19612},{"style":7965},[19613],{"type":291,"value":19477},{"type":281,"tag":319,"props":19615,"children":19616},{"style":1607},[19617],{"type":291,"value":19482},{"type":281,"tag":319,"props":19619,"children":19620},{"style":365},[19621],{"type":291,"value":19487},{"type":281,"tag":319,"props":19623,"children":19624},{"style":7965},[19625],{"type":291,"value":19492},{"type":281,"tag":319,"props":19627,"children":19628},{"style":365},[19629],{"type":291,"value":19497},{"type":281,"tag":319,"props":19631,"children":19632},{"style":7965},[19633],{"type":291,"value":19502},{"type":281,"tag":319,"props":19635,"children":19636},{"style":1607},[19637],{"type":291,"value":19507},{"type":281,"tag":319,"props":19639,"children":19640},{"style":365},[19641],{"type":291,"value":19512},{"type":281,"tag":319,"props":19643,"children":19644},{"style":7965},[19645],{"type":291,"value":19646}," |\n",{"type":281,"tag":319,"props":19648,"children":19649},{"class":321,"line":338},[19650,19655,19659,19663,19667,19671,19676,19681,19685,19690,19694,19698,19702,19706,19711,19716,19721,19726,19731],{"type":281,"tag":319,"props":19651,"children":19652},{"style":1607},[19653],{"type":291,"value":19654},"awk",{"type":281,"tag":319,"props":19656,"children":19657},{"style":1622},[19658],{"type":291,"value":19526},{"type":281,"tag":319,"props":19660,"children":19661},{"style":365},[19662],{"type":291,"value":19531},{"type":281,"tag":319,"props":19664,"children":19665},{"style":365},[19666],{"type":291,"value":19536},{"type":281,"tag":319,"props":19668,"children":19669},{"style":7965},[19670],{"type":291,"value":19502},{"type":281,"tag":319,"props":19672,"children":19673},{"style":1607},[19674],{"type":291,"value":19675}," cut",{"type":281,"tag":319,"props":19677,"children":19678},{"style":1622},[19679],{"type":291,"value":19680}," -d",{"type":281,"tag":319,"props":19682,"children":19683},{"style":365},[19684],{"type":291,"value":19531},{"type":281,"tag":319,"props":19686,"children":19687},{"style":1622},[19688],{"type":291,"value":19689}," -f2",{"type":281,"tag":319,"props":19691,"children":19692},{"style":7965},[19693],{"type":291,"value":19492},{"type":281,"tag":319,"props":19695,"children":19696},{"style":365},[19697],{"type":291,"value":19497},{"type":281,"tag":319,"props":19699,"children":19700},{"style":7965},[19701],{"type":291,"value":19502},{"type":281,"tag":319,"props":19703,"children":19704},{"style":1607},[19705],{"type":291,"value":19482},{"type":281,"tag":319,"props":19707,"children":19708},{"style":1622},[19709],{"type":291,"value":19710}," -r",{"type":281,"tag":319,"props":19712,"children":19713},{"style":365},[19714],{"type":291,"value":19715}," btrfs",{"type":281,"tag":319,"props":19717,"children":19718},{"style":365},[19719],{"type":291,"value":19720}," fi",{"type":281,"tag":319,"props":19722,"children":19723},{"style":365},[19724],{"type":291,"value":19725}," defrag",{"type":281,"tag":319,"props":19727,"children":19728},{"style":1622},[19729],{"type":291,"value":19730}," -f",{"type":281,"tag":319,"props":19732,"children":19733},{"style":1622},[19734],{"type":291,"value":19735}," -v\n",{"type":281,"tag":282,"props":19737,"children":19738},{},[19739],{"type":291,"value":19740},"This will print out all filenames that are processed.",{"type":281,"tag":530,"props":19742,"children":19744},{"id":19743},"a-short-explanation-of-the-command",[19745],{"type":291,"value":19746},"A short explanation of the command",{"type":281,"tag":282,"props":19748,"children":19749},{},[19750,19754,19756,19760,19762,19767,19769,19774],{"type":281,"tag":11370,"props":19751,"children":19752},{},[19753],{"type":291,"value":19452},{"type":291,"value":19755}," gets all files on the specified path (/) without descending into other mounted filesystems (-xdev). Then ",{"type":281,"tag":11370,"props":19757,"children":19758},{},[19759],{"type":291,"value":19435},{"type":291,"value":19761}," determines the fragmentation, the ",{"type":281,"tag":11370,"props":19763,"children":19764},{},[19765],{"type":291,"value":19766},"sed",{"type":291,"value":19768}," 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":281,"tag":11370,"props":19770,"children":19771},{},[19772],{"type":291,"value":19773},"defrag",{"type":291,"value":19775}," 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":281,"tag":530,"props":19777,"children":19779},{"id":19778},"have-fun",[19780],{"type":291,"value":19781},"Have fun!",{"type":281,"tag":1477,"props":19783,"children":19784},{},[19785],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":19787},[19788,19789,19790,19791,19792,19793,19794,19795],{"id":19333,"depth":338,"text":19336},{"id":19351,"depth":338,"text":19354},{"id":19362,"depth":338,"text":19365},{"id":19411,"depth":338,"text":19414},{"id":19422,"depth":338,"text":19425},{"id":19576,"depth":338,"text":19579},{"id":19743,"depth":338,"text":19746},{"id":19778,"depth":338,"text":19781},{"_path":185,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":186,"description":187,"author":136,"image":188,"releaseDate":189,"blogCategories":19797,"tags":19798,"body":19799,"_type":20,"_id":192,"_source":22,"_file":193,"_stem":194,"_extension":25},[15,104],[19],{"type":278,"children":19800,"toc":20022},[19801,19806,19811,19831,19836,19887,19892,20013,20018],{"type":281,"tag":282,"props":19802,"children":19803},{},[19804],{"type":291,"value":19805},"Most Sysadmins know how to set up a basic chroot on a mounted filesystem (mount-binding dev, proc and sys) but this does not work in any case; for a complete chroot setup you would aso need dev/pts dev/shm, run, tmp, a working resolve.conf and more. After you have set it up, and you want to bring it down, you have to do a lot of typing again. But wait! There is a better solution.",{"type":281,"tag":282,"props":19807,"children":19808},{},[19809],{"type":291,"value":19810},"There is a script called arch-chroot shipped with the Archlinux distribution, but it is not limited to be run with Archlinux. It works on any linux distri!",{"type":281,"tag":282,"props":19812,"children":19813},{},[19814,19816,19822,19824,19830],{"type":291,"value":19815},"For your convenience, I have ",{"type":281,"tag":286,"props":19817,"children":19819},{"href":19818},"https://gist.github.com/bhelm/65283c37a0cb585089041214002df4f7",[19820],{"type":291,"value":19821},"created a gist",{"type":291,"value":19823}," for you. You can also use the Direct ",{"type":281,"tag":286,"props":19825,"children":19827},{"href":19826},"https://gist.githubusercontent.com/bhelm/65283c37a0cb585089041214002df4f7/raw/536099a5f969a6888c85e48a487ec19870c596a2/arch-chroot.sh",[19828],{"type":291,"value":19829},"download link for wget",{"type":291,"value":564},{"type":281,"tag":282,"props":19832,"children":19833},{},[19834],{"type":291,"value":19835},"you can install it like this:",{"type":281,"tag":301,"props":19837,"children":19839},{"className":18404,"code":19838,"language":18406,"meta":8,"style":8},"wget https://gist.githubusercontent.com/bhelm/65283c37a0cb585089041214002df4f7/raw/536099a5f969a6888c85e48a487ec19870c596a2/arch-chroot.sh\nchmod +x arch-chroot.sh\n./arch-chroot.sh -h\n",[19840],{"type":281,"tag":315,"props":19841,"children":19842},{"__ignoreMap":8},[19843,19856,19874],{"type":281,"tag":319,"props":19844,"children":19845},{"class":321,"line":322},[19846,19851],{"type":281,"tag":319,"props":19847,"children":19848},{"style":1607},[19849],{"type":291,"value":19850},"wget",{"type":281,"tag":319,"props":19852,"children":19853},{"style":365},[19854],{"type":291,"value":19855}," https://gist.githubusercontent.com/bhelm/65283c37a0cb585089041214002df4f7/raw/536099a5f969a6888c85e48a487ec19870c596a2/arch-chroot.sh\n",{"type":281,"tag":319,"props":19857,"children":19858},{"class":321,"line":338},[19859,19864,19869],{"type":281,"tag":319,"props":19860,"children":19861},{"style":1607},[19862],{"type":291,"value":19863},"chmod",{"type":281,"tag":319,"props":19865,"children":19866},{"style":365},[19867],{"type":291,"value":19868}," +x",{"type":281,"tag":319,"props":19870,"children":19871},{"style":365},[19872],{"type":291,"value":19873}," arch-chroot.sh\n",{"type":281,"tag":319,"props":19875,"children":19876},{"class":321,"line":351},[19877,19882],{"type":281,"tag":319,"props":19878,"children":19879},{"style":1607},[19880],{"type":291,"value":19881},"./arch-chroot.sh",{"type":281,"tag":319,"props":19883,"children":19884},{"style":1622},[19885],{"type":291,"value":19886}," -h\n",{"type":281,"tag":282,"props":19888,"children":19889},{},[19890],{"type":291,"value":19891},"Using this script, I was able to install grub without getting errors like:",{"type":281,"tag":301,"props":19893,"children":19895},{"className":18404,"code":19894,"language":18406,"meta":8,"style":8},"grub-install: error: cannot find a device for /boot/grub (is /dev mounted?).\ngrub-probe: error: cannot find a device for / (is /dev mounted?).\n",[19896],{"type":281,"tag":315,"props":19897,"children":19898},{"__ignoreMap":8},[19899,19961],{"type":281,"tag":319,"props":19900,"children":19901},{"class":321,"line":322},[19902,19907,19912,19917,19922,19926,19931,19936,19941,19946,19951,19956],{"type":281,"tag":319,"props":19903,"children":19904},{"style":1607},[19905],{"type":291,"value":19906},"grub-install:",{"type":281,"tag":319,"props":19908,"children":19909},{"style":365},[19910],{"type":291,"value":19911}," error:",{"type":281,"tag":319,"props":19913,"children":19914},{"style":365},[19915],{"type":291,"value":19916}," cannot",{"type":281,"tag":319,"props":19918,"children":19919},{"style":365},[19920],{"type":291,"value":19921}," find",{"type":281,"tag":319,"props":19923,"children":19924},{"style":365},[19925],{"type":291,"value":18427},{"type":281,"tag":319,"props":19927,"children":19928},{"style":365},[19929],{"type":291,"value":19930}," device",{"type":281,"tag":319,"props":19932,"children":19933},{"style":365},[19934],{"type":291,"value":19935}," for",{"type":281,"tag":319,"props":19937,"children":19938},{"style":365},[19939],{"type":291,"value":19940}," /boot/grub",{"type":281,"tag":319,"props":19942,"children":19943},{"style":332},[19944],{"type":291,"value":19945}," (is ",{"type":281,"tag":319,"props":19947,"children":19948},{"style":365},[19949],{"type":291,"value":19950},"/dev",{"type":281,"tag":319,"props":19952,"children":19953},{"style":365},[19954],{"type":291,"value":19955}," mounted?",{"type":281,"tag":319,"props":19957,"children":19958},{"style":332},[19959],{"type":291,"value":19960},").\n",{"type":281,"tag":319,"props":19962,"children":19963},{"class":321,"line":338},[19964,19969,19973,19977,19981,19985,19989,19993,19997,20001,20005,20009],{"type":281,"tag":319,"props":19965,"children":19966},{"style":1607},[19967],{"type":291,"value":19968},"grub-probe:",{"type":281,"tag":319,"props":19970,"children":19971},{"style":365},[19972],{"type":291,"value":19911},{"type":281,"tag":319,"props":19974,"children":19975},{"style":365},[19976],{"type":291,"value":19916},{"type":281,"tag":319,"props":19978,"children":19979},{"style":365},[19980],{"type":291,"value":19921},{"type":281,"tag":319,"props":19982,"children":19983},{"style":365},[19984],{"type":291,"value":18427},{"type":281,"tag":319,"props":19986,"children":19987},{"style":365},[19988],{"type":291,"value":19930},{"type":281,"tag":319,"props":19990,"children":19991},{"style":365},[19992],{"type":291,"value":19935},{"type":281,"tag":319,"props":19994,"children":19995},{"style":365},[19996],{"type":291,"value":19457},{"type":281,"tag":319,"props":19998,"children":19999},{"style":332},[20000],{"type":291,"value":19945},{"type":281,"tag":319,"props":20002,"children":20003},{"style":365},[20004],{"type":291,"value":19950},{"type":281,"tag":319,"props":20006,"children":20007},{"style":365},[20008],{"type":291,"value":19955},{"type":281,"tag":319,"props":20010,"children":20011},{"style":332},[20012],{"type":291,"value":19960},{"type":281,"tag":282,"props":20014,"children":20015},{},[20016],{"type":291,"value":20017},"If you are looking for a perfect rescue system, i recommend the archlinux install image; it contains the arch-chroot script, all low level tools needed to format hard drives and even supports mounting of ntfs read-write and accessing samba shares.",{"type":281,"tag":1477,"props":20019,"children":20020},{},[20021],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":20023},[],{"_path":196,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":197,"description":198,"author":136,"image":199,"releaseDate":200,"blogCategories":20025,"articleTags":20026,"tags":20027,"body":20028,"_type":20,"_id":205,"_source":22,"_file":206,"_stem":207,"_extension":25},[15,104],[203],[19],{"type":278,"children":20029,"toc":20539},[20030,20036,20041,20046,20430,20435,20440,20448,20453,20535],{"type":281,"tag":530,"props":20031,"children":20033},{"id":20032},"investigation-in-performance",[20034],{"type":291,"value":20035},"Investigation in Performance",{"type":281,"tag":282,"props":20037,"children":20038},{},[20039],{"type":291,"value":20040},"When it comes to buying an NVME SSD for a software developer workstation, you are faced with a choice: buy one cheap or buy one expensive. So far, I've chosen the more expensive ones because they promised better performance and longer life - I can now see how wrong I was.",{"type":281,"tag":282,"props":20042,"children":20043},{},[20044],{"type":291,"value":20045},"It all started when one employee said his NVME SSD was slower than his Sata SSD. This can't be true, as the Sata SSD is limited to 600MB/s and 3 years old, while his new NVME SSD is supposed to read and write 3000MB/s. And yet it is true. I have done some dirty benchmarks and the results are impressive. I call the benchmark dirty because clearly different PCs are used; different CPUs, sightly different operating system versions, different MySQL versions and configurations. But the differences in the results cannot be explained my that in my opinion. There is something wrong with the Samsung NVME SSDs.",{"type":281,"tag":20047,"props":20048,"children":20049},"table",{},[20050,20088],{"type":281,"tag":20051,"props":20052,"children":20053},"thead",{},[20054],{"type":281,"tag":20055,"props":20056,"children":20057},"tr",{},[20058,20064,20068,20073,20078,20083],{"type":281,"tag":20059,"props":20060,"children":20061},"th",{},[20062],{"type":291,"value":20063},"User",{"type":281,"tag":20059,"props":20065,"children":20066},{},[20067],{"type":291,"value":203},{"type":281,"tag":20059,"props":20069,"children":20070},{},[20071],{"type":291,"value":20072},"Note",{"type":281,"tag":20059,"props":20074,"children":20075},{},[20076],{"type":291,"value":20077},"Allocation",{"type":281,"tag":20059,"props":20079,"children":20080},{},[20081],{"type":291,"value":20082},"TPS",{"type":281,"tag":20059,"props":20084,"children":20085},{},[20086],{"type":291,"value":20087},"QPS",{"type":281,"tag":20089,"props":20090,"children":20091},"tbody",{},[20092,20124,20154,20185,20214,20246,20278,20309,20341,20371,20401],{"type":281,"tag":20055,"props":20093,"children":20094},{},[20095,20101,20106,20109,20114,20119],{"type":281,"tag":20096,"props":20097,"children":20098},"td",{},[20099],{"type":291,"value":20100},"Markus",{"type":281,"tag":20096,"props":20102,"children":20103},{},[20104],{"type":291,"value":20105},"Curical CT1000P1SSD8",{"type":281,"tag":20096,"props":20107,"children":20108},{},[],{"type":281,"tag":20096,"props":20110,"children":20111},{},[20112],{"type":291,"value":20113},"1,00 %",{"type":281,"tag":20096,"props":20115,"children":20116},{},[20117],{"type":291,"value":20118},"304",{"type":281,"tag":20096,"props":20120,"children":20121},{},[20122],{"type":291,"value":20123},"6091",{"type":281,"tag":20055,"props":20125,"children":20126},{},[20127,20132,20136,20139,20144,20149],{"type":281,"tag":20096,"props":20128,"children":20129},{},[20130],{"type":291,"value":20131},"Robert",{"type":281,"tag":20096,"props":20133,"children":20134},{},[20135],{"type":291,"value":20105},{"type":281,"tag":20096,"props":20137,"children":20138},{},[],{"type":281,"tag":20096,"props":20140,"children":20141},{},[20142],{"type":291,"value":20143},"4,00 %",{"type":281,"tag":20096,"props":20145,"children":20146},{},[20147],{"type":291,"value":20148},"412",{"type":281,"tag":20096,"props":20150,"children":20151},{},[20152],{"type":291,"value":20153},"8241",{"type":281,"tag":20055,"props":20155,"children":20156},{},[20157,20162,20167,20170,20175,20180],{"type":281,"tag":20096,"props":20158,"children":20159},{},[20160],{"type":291,"value":20161},"Reiner",{"type":281,"tag":20096,"props":20163,"children":20164},{},[20165],{"type":291,"value":20166},"Samsung SSD 970 PRO 512GB",{"type":281,"tag":20096,"props":20168,"children":20169},{},[],{"type":281,"tag":20096,"props":20171,"children":20172},{},[20173],{"type":291,"value":20174},"66,00 %",{"type":281,"tag":20096,"props":20176,"children":20177},{},[20178],{"type":291,"value":20179},"160",{"type":281,"tag":20096,"props":20181,"children":20182},{},[20183],{"type":291,"value":20184},"3214",{"type":281,"tag":20055,"props":20186,"children":20187},{},[20188,20192,20196,20199,20204,20209],{"type":281,"tag":20096,"props":20189,"children":20190},{},[20191],{"type":291,"value":20100},{"type":281,"tag":20096,"props":20193,"children":20194},{},[20195],{"type":291,"value":20166},{"type":281,"tag":20096,"props":20197,"children":20198},{},[],{"type":281,"tag":20096,"props":20200,"children":20201},{},[20202],{"type":291,"value":20203},"14,00 %",{"type":281,"tag":20096,"props":20205,"children":20206},{},[20207],{"type":291,"value":20208},"120",{"type":281,"tag":20096,"props":20210,"children":20211},{},[20212],{"type":291,"value":20213},"2414",{"type":281,"tag":20055,"props":20215,"children":20216},{},[20217,20222,20226,20231,20236,20241],{"type":281,"tag":20096,"props":20218,"children":20219},{},[20220],{"type":291,"value":20221},"Bernd",{"type":281,"tag":20096,"props":20223,"children":20224},{},[20225],{"type":291,"value":20166},{"type":281,"tag":20096,"props":20227,"children":20228},{},[20229],{"type":291,"value":20230},"crypt",{"type":281,"tag":20096,"props":20232,"children":20233},{},[20234],{"type":291,"value":20235},"80,00 %",{"type":281,"tag":20096,"props":20237,"children":20238},{},[20239],{"type":291,"value":20240},"148",{"type":281,"tag":20096,"props":20242,"children":20243},{},[20244],{"type":291,"value":20245},"2976",{"type":281,"tag":20055,"props":20247,"children":20248},{},[20249,20254,20259,20263,20268,20273],{"type":281,"tag":20096,"props":20250,"children":20251},{},[20252],{"type":291,"value":20253},"Daniel",{"type":281,"tag":20096,"props":20255,"children":20256},{},[20257],{"type":291,"value":20258},"Samsung SSD 960 PRO 512GB",{"type":281,"tag":20096,"props":20260,"children":20261},{},[20262],{"type":291,"value":20230},{"type":281,"tag":20096,"props":20264,"children":20265},{},[20266],{"type":291,"value":20267},"46,00 %",{"type":281,"tag":20096,"props":20269,"children":20270},{},[20271],{"type":291,"value":20272},"30",{"type":281,"tag":20096,"props":20274,"children":20275},{},[20276],{"type":291,"value":20277},"614",{"type":281,"tag":20055,"props":20279,"children":20280},{},[20281,20285,20290,20295,20300,20304],{"type":281,"tag":20096,"props":20282,"children":20283},{},[20284],{"type":291,"value":20161},{"type":281,"tag":20096,"props":20286,"children":20287},{},[20288],{"type":291,"value":20289},"Samsung SSD 850 PRO 128GB",{"type":281,"tag":20096,"props":20291,"children":20292},{},[20293],{"type":291,"value":20294},"sata",{"type":281,"tag":20096,"props":20296,"children":20297},{},[20298],{"type":291,"value":20299},"37,00 %",{"type":281,"tag":20096,"props":20301,"children":20302},{},[20303],{"type":291,"value":20208},{"type":281,"tag":20096,"props":20305,"children":20306},{},[20307],{"type":291,"value":20308},"2437",{"type":281,"tag":20055,"props":20310,"children":20311},{},[20312,20316,20321,20326,20331,20336],{"type":281,"tag":20096,"props":20313,"children":20314},{},[20315],{"type":291,"value":20253},{"type":281,"tag":20096,"props":20317,"children":20318},{},[20319],{"type":291,"value":20320},"Samsung SSD 860 PRO 512GB",{"type":281,"tag":20096,"props":20322,"children":20323},{},[20324],{"type":291,"value":20325},"SATA",{"type":281,"tag":20096,"props":20327,"children":20328},{},[20329],{"type":291,"value":20330},"87,00 %",{"type":281,"tag":20096,"props":20332,"children":20333},{},[20334],{"type":291,"value":20335},"185",{"type":281,"tag":20096,"props":20337,"children":20338},{},[20339],{"type":291,"value":20340},"3700",{"type":281,"tag":20055,"props":20342,"children":20343},{},[20344,20349,20354,20357,20361,20366],{"type":281,"tag":20096,"props":20345,"children":20346},{},[20347],{"type":291,"value":20348},"Daneil",{"type":281,"tag":20096,"props":20350,"children":20351},{},[20352],{"type":291,"value":20353},"Samsung SSD 970 EVO Plus 1TB",{"type":281,"tag":20096,"props":20355,"children":20356},{},[],{"type":281,"tag":20096,"props":20358,"children":20359},{},[20360],{"type":291,"value":20113},{"type":281,"tag":20096,"props":20362,"children":20363},{},[20364],{"type":291,"value":20365},"480",{"type":281,"tag":20096,"props":20367,"children":20368},{},[20369],{"type":291,"value":20370},"9614",{"type":281,"tag":20055,"props":20372,"children":20373},{},[20374,20378,20383,20386,20391,20396],{"type":281,"tag":20096,"props":20375,"children":20376},{},[20377],{"type":291,"value":20221},{"type":281,"tag":20096,"props":20379,"children":20380},{},[20381],{"type":291,"value":20382},"Sabrent Rocket Q 2TB",{"type":281,"tag":20096,"props":20384,"children":20385},{},[],{"type":281,"tag":20096,"props":20387,"children":20388},{},[20389],{"type":291,"value":20390},"26,00 %",{"type":281,"tag":20096,"props":20392,"children":20393},{},[20394],{"type":291,"value":20395},"237",{"type":281,"tag":20096,"props":20397,"children":20398},{},[20399],{"type":291,"value":20400},"4749",{"type":281,"tag":20055,"props":20402,"children":20403},{},[20404,20409,20414,20417,20421,20425],{"type":281,"tag":20096,"props":20405,"children":20406},{},[20407],{"type":291,"value":20408},"Marcel",{"type":281,"tag":20096,"props":20410,"children":20411},{},[20412],{"type":291,"value":20413},"Patriot Scorch M2 256GB",{"type":281,"tag":20096,"props":20415,"children":20416},{},[],{"type":281,"tag":20096,"props":20418,"children":20419},{},[20420],{"type":291,"value":20113},{"type":281,"tag":20096,"props":20422,"children":20423},{},[20424],{"type":291,"value":20208},{"type":281,"tag":20096,"props":20426,"children":20427},{},[20428],{"type":291,"value":20429},"2440",{"type":281,"tag":282,"props":20431,"children":20432},{},[20433],{"type":291,"value":20434},"As you can see, the Curical P1 SSD is 2x, partially 3x faster than the Samsung Pro SSDs - even though the Curical costs only a third. You can also see that the 860 Pro Sata SSD from Daniel is faster than all Samsung NVME Pro SSDs. If you look for the phenomena on google, you will find other people who have observed the same problem. The Samsung PRO NVME SSDs seem to have a problem with frequent fsync calls.I have used sysbench 1.0.18 with the oltp_read_write benchmark on all machines. They all use BTRFS as filesystem and the MySQL filesystem was mounted with nodatacow, which improves performance. In the table, TPS stands for transactions per second and QPS for queries per second - both values were read from the sysbench statistics.",{"type":281,"tag":282,"props":20436,"children":20437},{},[20438],{"type":291,"value":20439},"Since our database performance is very important to our software developers, I will avoid the Samsung pro NVME SSDs in the future and give other manufacturers a chance. The SSD is still fine for Gaming, Movie editing and stuff, just not for requent fsyncs.",{"type":281,"tag":282,"props":20441,"children":20442},{},[20443],{"type":281,"tag":11280,"props":20444,"children":20445},{},[20446],{"type":291,"value":20447},"Edit: looks like the 970 EVO Plus SSD is not affected by this problem.",{"type":281,"tag":282,"props":20449,"children":20450},{},[20451],{"type":291,"value":20452},"sysbench commands used:",{"type":281,"tag":301,"props":20454,"children":20456},{"className":18404,"code":20455,"language":18406,"meta":8,"style":8},"sysbench oltp_read_write --table-size=2500000 --mysql-user=root --db-driver=mysql --mysql-password=  prepare\nsysbench oltp_read_write --table-size=2500000 --mysql-user=root --db-driver=mysql --mysql-password=  --time=120 run\n",[20457],{"type":281,"tag":315,"props":20458,"children":20459},{"__ignoreMap":8},[20460,20498],{"type":281,"tag":319,"props":20461,"children":20462},{"class":321,"line":322},[20463,20468,20473,20478,20483,20488,20493],{"type":281,"tag":319,"props":20464,"children":20465},{"style":1607},[20466],{"type":291,"value":20467},"sysbench",{"type":281,"tag":319,"props":20469,"children":20470},{"style":365},[20471],{"type":291,"value":20472}," oltp_read_write",{"type":281,"tag":319,"props":20474,"children":20475},{"style":1622},[20476],{"type":291,"value":20477}," --table-size=2500000",{"type":281,"tag":319,"props":20479,"children":20480},{"style":1622},[20481],{"type":291,"value":20482}," --mysql-user=root",{"type":281,"tag":319,"props":20484,"children":20485},{"style":1622},[20486],{"type":291,"value":20487}," --db-driver=mysql",{"type":281,"tag":319,"props":20489,"children":20490},{"style":1622},[20491],{"type":291,"value":20492}," --mysql-password=",{"type":281,"tag":319,"props":20494,"children":20495},{"style":365},[20496],{"type":291,"value":20497},"  prepare\n",{"type":281,"tag":319,"props":20499,"children":20500},{"class":321,"line":338},[20501,20505,20509,20513,20517,20521,20525,20530],{"type":281,"tag":319,"props":20502,"children":20503},{"style":1607},[20504],{"type":291,"value":20467},{"type":281,"tag":319,"props":20506,"children":20507},{"style":365},[20508],{"type":291,"value":20472},{"type":281,"tag":319,"props":20510,"children":20511},{"style":1622},[20512],{"type":291,"value":20477},{"type":281,"tag":319,"props":20514,"children":20515},{"style":1622},[20516],{"type":291,"value":20482},{"type":281,"tag":319,"props":20518,"children":20519},{"style":1622},[20520],{"type":291,"value":20487},{"type":281,"tag":319,"props":20522,"children":20523},{"style":1622},[20524],{"type":291,"value":20492},{"type":281,"tag":319,"props":20526,"children":20527},{"style":1622},[20528],{"type":291,"value":20529},"  --time=120",{"type":281,"tag":319,"props":20531,"children":20532},{"style":365},[20533],{"type":291,"value":20534}," run\n",{"type":281,"tag":1477,"props":20536,"children":20537},{},[20538],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":20540},[20541],{"id":20032,"depth":338,"text":20035},{"_path":209,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":210,"description":211,"author":136,"image":212,"releaseDate":213,"blogCategories":20543,"articleTags":20544,"tags":20545,"body":20546,"_type":20,"_id":217,"_source":22,"_file":218,"_stem":219,"_extension":25},[15,104],[203],[19],{"type":278,"children":20547,"toc":20711},[20548,20554,20559,20564,20570,20589,20595,20600,20606,20611,20616,20621,20626,20632,20637,20647,20657,20667,20672,20677,20685,20690,20696,20701,20706],{"type":281,"tag":530,"props":20549,"children":20551},{"id":20550},"comment-and-investigation-in-raid-performance",[20552],{"type":291,"value":20553},"Comment and Investigation in RAID Performance",{"type":281,"tag":282,"props":20555,"children":20556},{},[20557],{"type":291,"value":20558},"RAID 5 vs RAID10 has been discussed for ages; its common knowledge that RAID10 offers better performance – but how much depends on the actual implementation, hardware and use-case.",{"type":281,"tag":282,"props":20560,"children":20561},{},[20562],{"type":291,"value":20563},"I just got a Server with 4 x 16TB of disks, all brand new, and decided to give it a test to find out if the performance gains of raid 10 justify the smaller usable disk space. We plan to use it as a Backup-Server so our workload is mostly sequential write.",{"type":281,"tag":530,"props":20565,"children":20567},{"id":20566},"testing-methodology",[20568],{"type":291,"value":20569},"Testing Methodology",{"type":281,"tag":282,"props":20571,"children":20572},{},[20573,20575,20580,20582,20587],{"type":291,"value":20574},"All tests are executed using ",{"type":281,"tag":11370,"props":20576,"children":20577},{},[20578],{"type":291,"value":20579},"fio",{"type":291,"value":20581}," with ",{"type":281,"tag":11370,"props":20583,"children":20584},{},[20585],{"type":291,"value":20586},"iodepth=32 direct=1 ioengine=libaio refill_buffers",{"type":291,"value":20588}," and a time limit of 60 seconds. the sequential read and write tests are done with 1024k block size and 1 process. The random read/write tests with 4k block size and 4 processes. For testing, a 30GB partition on the start of each disk is used. The Linux kernel version is 5.10.",{"type":281,"tag":530,"props":20590,"children":20592},{"id":20591},"plain-disk-performance",[20593],{"type":291,"value":20594},"Plain Disk performance",{"type":281,"tag":282,"props":20596,"children":20597},{},[20598],{"type":291,"value":20599},"Before I get to the actual testing, I want to get the baseline of a single disks performance and also make sure that all disks are performing similar.",{"type":281,"tag":1499,"props":20601,"children":20605},{"alt":20602,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20604},"raid_1",200,"/blog/raid_1.png",[],{"type":281,"tag":1499,"props":20607,"children":20610},{"alt":20608,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20609},"raid_2","/blog/raid_2.png",[],{"type":281,"tag":1499,"props":20612,"children":20615},{"alt":20613,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20614},"raid_3","/blog/raid_3.png",[],{"type":281,"tag":1499,"props":20617,"children":20620},{"alt":20618,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20619},"raid_4","/blog/raid_4.png",[],{"type":281,"tag":282,"props":20622,"children":20623},{},[20624],{"type":291,"value":20625},"Everything looks nice a flat here as it should. We have around 268MB/s sequential read and write and a random IOPS performance of 550 read / 480 write.",{"type":281,"tag":530,"props":20627,"children":20629},{"id":20628},"raid-5-vs-raid-10",[20630],{"type":291,"value":20631},"Raid 5 vs Raid 10",{"type":281,"tag":1499,"props":20633,"children":20636},{"alt":20634,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20635},"raid_5","/blog/raid_5.png",[],{"type":281,"tag":282,"props":20638,"children":20639},{},[20640,20642],{"type":291,"value":20641},"The Seq. Reading performance between RAID5 and RAID10 is smaller than i would have guessed. The far2 layout really makes a difference here.\n",{"type":281,"tag":1499,"props":20643,"children":20646},{"alt":20644,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20645},"raid_6","/blog/raid_6.png",[],{"type":281,"tag":282,"props":20648,"children":20649},{},[20650,20652],{"type":291,"value":20651},"With Seq. writing, we see real differences. The „Classic“ Raid10 shows the best write speed, while the far2 and raid5 are each a step-down.\n",{"type":281,"tag":1499,"props":20653,"children":20656},{"alt":20654,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20655},"raid_7","/blog/raid_7.png",[],{"type":281,"tag":282,"props":20658,"children":20659},{},[20660,20662],{"type":291,"value":20661},"Interestingly, there is not much difference on the random read test, which i would not have expected.\n",{"type":281,"tag":1499,"props":20663,"children":20666},{"alt":20664,"aspect-ratio":19307,"height":20603,"object-fit":19308,"src":20665},"raid_8","/blog/raid_8.png",[],{"type":281,"tag":282,"props":20668,"children":20669},{},[20670],{"type":291,"value":20671},"The Rand Write graph looks very similar to the Seq Write graph. Only difference is that the classic raid10 can handle random writes better than sequential ones.",{"type":281,"tag":282,"props":20673,"children":20674},{},[20675],{"type":291,"value":20676},"MDADM has multiple implementations on how the raid works internally. For raid10 i tested the „near 2“ and „far 2“ layouts, where „near 2“ is the default. From the docs:",{"type":281,"tag":10768,"props":20678,"children":20679},{},[20680],{"type":281,"tag":282,"props":20681,"children":20682},{},[20683],{"type":291,"value":20684},"The advantage of this (… far 2) layout is that MD can easily spread sequential reads over the devices, making them similar to RAID0 in terms of speed. The cost is more seeking for writes, making them substantially slower.",{"type":281,"tag":282,"props":20686,"children":20687},{},[20688],{"type":291,"value":20689},"Yes, this can be seen on the benchmark graphs",{"type":281,"tag":530,"props":20691,"children":20693},{"id":20692},"conclusions",[20694],{"type":291,"value":20695},"Conclusions",{"type":281,"tag":282,"props":20697,"children":20698},{},[20699],{"type":291,"value":20700},"From my tests, it looks like the reading performance difference is neglect. On Writing, RAID10 has a huge advantage.",{"type":281,"tag":282,"props":20702,"children":20703},{},[20704],{"type":291,"value":20705},"For our Backup-Server, we go with Raid 5, because it is 3x faster than the 1GBit network card of the server and won't bottleneck our backup- or restore processes.",{"type":281,"tag":282,"props":20707,"children":20708},{},[20709],{"type":291,"value":20710},"If you have a more critical use case, i advice to do your own benchmarks that reflect your workload better. Especially if you are using SSDs, the results can be drastically different.",{"title":8,"searchDepth":338,"depth":338,"links":20712},[20713,20714,20715,20716,20717],{"id":20550,"depth":338,"text":20553},{"id":20566,"depth":338,"text":20569},{"id":20591,"depth":338,"text":20594},{"id":20628,"depth":338,"text":20631},{"id":20692,"depth":338,"text":20695},{"_path":221,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":222,"description":223,"author":224,"image":225,"releaseDate":226,"blogCategories":20719,"articleTags":20720,"tags":20721,"body":20722,"_type":20,"_id":232,"_source":22,"_file":233,"_stem":234,"_extension":25},[15,228],[203],[231,19],{"type":278,"children":20723,"toc":22256},[20724,20729,20734,20742,20748,20797,20802,20808,20820,20825,20830,20836,20853,20858,22150,22155,22234,22238,22246,22252],{"type":281,"tag":530,"props":20725,"children":20726},{"id":532},[20727],{"type":291,"value":20728},"The Problem",{"type":281,"tag":282,"props":20730,"children":20731},{},[20732],{"type":291,"value":20733},"When attempting to reclaim disk space, deleting data may seem like the obvious first step. However, in Riak this is not necessarily the best thing to do if the disk is nearly full.\nThis is because deleting objects in Riak is complicated. As stated in the object-deletion section of latest Riak documentation:",{"type":281,"tag":282,"props":20735,"children":20736},{},[20737],{"type":281,"tag":11370,"props":20738,"children":20739},{},[20740],{"type":291,"value":20741},"In single-server, non-clustered data storage systems, object deletion is a trivial process. In an eventually consistent, clustered system like Riak, however, object deletion is far less trivial because objects live on multiple nodes, which means that a deletion process must be chosen to determine when an object can be removed from the storage backend.",{"type":281,"tag":530,"props":20743,"children":20745},{"id":20744},"how-deletion-works",[20746],{"type":291,"value":20747},"How deletion works",{"type":281,"tag":608,"props":20749,"children":20750},{},[20751,20764,20777,20782,20787,20792],{"type":281,"tag":459,"props":20752,"children":20753},{},[20754,20756,20762],{"type":291,"value":20755},"Riak writes a ",{"type":281,"tag":286,"props":20757,"children":20759},{"href":20758},"https://riak.docs.hw.ag/riak/kv/latest/using/reference/object-deletion/#tombstones",[20760],{"type":291,"value":20761},"“tombstone”",{"type":291,"value":20763}," value for the key to the N vnodes that contain it\n(this is a new record)",{"type":281,"tag":459,"props":20765,"children":20766},{},[20767,20769,20775],{"type":291,"value":20768},"Riak by ",{"type":281,"tag":286,"props":20770,"children":20772},{"href":20771},"https://riak.docs.hw.ag/riak/kv/latest/configuring/reference/#other-settings",[20773],{"type":291,"value":20774},"default, waits 3 seconds",{"type":291,"value":20776}," to verify all vnodes agree to the\ntombstone/delete",{"type":281,"tag":459,"props":20778,"children":20779},{},[20780],{"type":291,"value":20781},"Riak issues an actual delete operation against the key to leveldb",{"type":281,"tag":459,"props":20783,"children":20784},{},[20785],{"type":291,"value":20786},"leveldb creates its own tombstone",{"type":281,"tag":459,"props":20788,"children":20789},{},[20790],{"type":291,"value":20791},"the leveldb tombstone “floats” through level-0 and level-1 as part of normal\ncompactions",{"type":281,"tag":459,"props":20793,"children":20794},{},[20795],{"type":291,"value":20796},"upon reaching level-2, leveldb will initiate immediate compaction and\npropagation of tombstones in .sst table files containing 1000 or more\ntombstones.",{"type":281,"tag":282,"props":20798,"children":20799},{},[20800],{"type":291,"value":20801},"Consequence of this is that freeing disk space, if it happens either, it happens very slowly.",{"type":281,"tag":530,"props":20803,"children":20805},{"id":20804},"solution-for-eleveldb",[20806],{"type":291,"value":20807},"Solution for e/leveldb",{"type":281,"tag":282,"props":20809,"children":20810},{},[20811,20813,20819],{"type":291,"value":20812},"In short, there is a c++ function in leveldb that is used to compact the underlying storage. The function is called ",{"type":281,"tag":286,"props":20814,"children":20816},{"href":20815},"https://github.com/hw-dwalter/leveldb/blob/5db913fdc28801714d587c44524d90b48e51210e/include/leveldb/db.h#L157",[20817],{"type":291,"value":20818},"\"CompactRange\"",{"type":291,"value":564},{"type":281,"tag":282,"props":20821,"children":20822},{},[20823],{"type":291,"value":20824},"In particular, deleted and overwritten versions are discarded, and the data is rearranged to reduce the cost of operations needed to access the data.",{"type":281,"tag":282,"props":20826,"children":20827},{},[20828],{"type":291,"value":20829},"This function does not exist in the erlang code that uses this c++ library. This means that we needed to build a standalone tool that calls this library function on all leveldb files in Riak. Drawback of this is, that your Riak server has to be offline while running such a 3rd party tool.",{"type":281,"tag":530,"props":20831,"children":20833},{"id":20832},"use-case",[20834],{"type":291,"value":20835},"Use case",{"type":281,"tag":282,"props":20837,"children":20838},{},[20839,20841,20846,20848,20852],{"type":291,"value":20840},"We build such a tool, you can check it out from github RiakToolsCxx.git and build it with ",{"type":281,"tag":11370,"props":20842,"children":20843},{},[20844],{"type":291,"value":20845},"cmake",{"type":291,"value":20847},". External dependency leveldb-basho is pulled automatically by ",{"type":281,"tag":11370,"props":20849,"children":20850},{},[20851],{"type":291,"value":20845},{"type":291,"value":564},{"type":281,"tag":282,"props":20854,"children":20855},{},[20856],{"type":291,"value":20857},"Checkout and build process could look like:",{"type":281,"tag":301,"props":20859,"children":20861},{"className":18404,"code":20860,"language":18406,"meta":8,"style":8},"dwalter@knxwork:~/Projects$ git clone https://github.com/hw-dwalter/RiakToolsCxx.git RiakToolsCxx\nCloning into 'RiakToolsCxx'...\nremote: Counting objects: 11, done.\nremote: Total 11 (delta 0), reused 0 (delta 0), pack-reused 11\nUnpacking objects: 100% (11/11), done.\ndwalter@knxwork:~/Projects$ cd RiakToolsCxx/\ndwalter@knxwork:~/Projects/RiakToolsCxx$ mkdir build\ndwalter@knxwork:~/Projects/RiakToolsCxx$ cd build/\ndwalter@knxwork:~/Projects/RiakToolsCxx/build$ cmake ..\n-- The CXX compiler identification is GNU 6.3.0\n-- Check for working CXX compiler: /usr/bin/c++\n-- Check for working CXX compiler: /usr/bin/c++ -- works\n-- Detecting CXX compiler ABI info\n-- Detecting CXX compiler ABI info - done\n-- Detecting CXX compile features\n-- Detecting CXX compile features - done\n-- Performing Test COMPILER_SUPPORTS_CXX11\n-- Performing Test COMPILER_SUPPORTS_CXX11 - Success\n-- Performing Test COMPILER_SUPPORTS_CXX0X\n-- Performing Test COMPILER_SUPPORTS_CXX0X - Success\n-- The C compiler identification is GNU 6.3.0\n-- Check for working C compiler: /usr/bin/cc\n-- Check for working C compiler: /usr/bin/cc -- works\n-- Detecting C compiler ABI info\n-- Detecting C compiler ABI info - done\n-- Detecting C compile features\n-- Detecting C compile features - done\n-- Boost version: 1.62.0\n-- Found the following Boost libraries:\n--   filesystem\n--   system\n-- Configuring done\n-- Generating done\n-- Build files have been written to: /home/dwalter/Projects/RiakToolsCxx/build\ndwalter@knxwork:~/Projects/RiakToolsCxx/build$ make\nScanning dependencies of target leveldb-basho\n[ 10%] Creating directories for 'leveldb-basho'\n[ 20%] Performing download step (git clone) for 'leveldb-basho'\nCloning into 'leveldb-basho'...\nAlready on 'develop'\nYour branch is up-to-date with 'origin/develop'.\n[ 30%] No patch step for 'leveldb-basho'\n[ 40%] No update step for 'leveldb-basho'\n[ 50%] No configure step for 'leveldb-basho'\n[ 60%] Performing build step for 'leveldb-basho'\nar: creating libleveldb.a\n[ 70%] No install step for 'leveldb-basho'\n[ 80%] Completed 'leveldb-basho'\n[ 80%] Built target leveldb-basho\nScanning dependencies of target riakcompact\n[ 90%] Building CXX object src/CMakeFiles/riakcompact.dir/main.cpp.o\n[100%] Linking CXX executable riakcompact\n[100%] Built target riakcompact\ndwalter@knxwork:~/Projects/RiakToolsCxx/build$ ./src/riakcompact \nusage:   ./src/riakcompact [path]\n",[20862],{"type":281,"tag":315,"props":20863,"children":20864},{"__ignoreMap":8},[20865,20893,20911,20939,20985,21007,21024,21042,21058,21076,21119,21154,21196,21226,21264,21289,21321,21343,21372,21392,21420,21456,21488,21528,21555,21590,21613,21644,21666,21697,21709,21721,21737,21753,21795,21807,21835,21853,21882,21898,21916,21948,21964,21980,21996,22012,22030,22046,22059,22067,22091,22099,22107,22115,22132],{"type":281,"tag":319,"props":20866,"children":20867},{"class":321,"line":322},[20868,20873,20878,20883,20888],{"type":281,"tag":319,"props":20869,"children":20870},{"style":1607},[20871],{"type":291,"value":20872},"dwalter@knxwork:~/Projects$",{"type":281,"tag":319,"props":20874,"children":20875},{"style":365},[20876],{"type":291,"value":20877}," git",{"type":281,"tag":319,"props":20879,"children":20880},{"style":365},[20881],{"type":291,"value":20882}," clone",{"type":281,"tag":319,"props":20884,"children":20885},{"style":365},[20886],{"type":291,"value":20887}," https://github.com/hw-dwalter/RiakToolsCxx.git",{"type":281,"tag":319,"props":20889,"children":20890},{"style":365},[20891],{"type":291,"value":20892}," RiakToolsCxx\n",{"type":281,"tag":319,"props":20894,"children":20895},{"class":321,"line":338},[20896,20901,20906],{"type":281,"tag":319,"props":20897,"children":20898},{"style":1607},[20899],{"type":291,"value":20900},"Cloning",{"type":281,"tag":319,"props":20902,"children":20903},{"style":365},[20904],{"type":291,"value":20905}," into",{"type":281,"tag":319,"props":20907,"children":20908},{"style":365},[20909],{"type":291,"value":20910}," 'RiakToolsCxx'...\n",{"type":281,"tag":319,"props":20912,"children":20913},{"class":321,"line":351},[20914,20919,20924,20929,20934],{"type":281,"tag":319,"props":20915,"children":20916},{"style":1607},[20917],{"type":291,"value":20918},"remote:",{"type":281,"tag":319,"props":20920,"children":20921},{"style":365},[20922],{"type":291,"value":20923}," Counting",{"type":281,"tag":319,"props":20925,"children":20926},{"style":365},[20927],{"type":291,"value":20928}," objects:",{"type":281,"tag":319,"props":20930,"children":20931},{"style":365},[20932],{"type":291,"value":20933}," 11,",{"type":281,"tag":319,"props":20935,"children":20936},{"style":365},[20937],{"type":291,"value":20938}," done.\n",{"type":281,"tag":319,"props":20940,"children":20941},{"class":321,"line":371},[20942,20946,20951,20956,20961,20965,20970,20975,20980],{"type":281,"tag":319,"props":20943,"children":20944},{"style":1607},[20945],{"type":291,"value":20918},{"type":281,"tag":319,"props":20947,"children":20948},{"style":365},[20949],{"type":291,"value":20950}," Total",{"type":281,"tag":319,"props":20952,"children":20953},{"style":1622},[20954],{"type":291,"value":20955}," 11",{"type":281,"tag":319,"props":20957,"children":20958},{"style":332},[20959],{"type":291,"value":20960}," (delta ",{"type":281,"tag":319,"props":20962,"children":20963},{"style":1622},[20964],{"type":291,"value":18687},{"type":281,"tag":319,"props":20966,"children":20967},{"style":332},[20968],{"type":291,"value":20969},"), reused 0 (",{"type":281,"tag":319,"props":20971,"children":20972},{"style":1607},[20973],{"type":291,"value":20974},"delta",{"type":281,"tag":319,"props":20976,"children":20977},{"style":1622},[20978],{"type":291,"value":20979}," 0",{"type":281,"tag":319,"props":20981,"children":20982},{"style":332},[20983],{"type":291,"value":20984},"), pack-reused 11\n",{"type":281,"tag":319,"props":20986,"children":20987},{"class":321,"line":306},[20988,20993,20997,21002],{"type":281,"tag":319,"props":20989,"children":20990},{"style":1607},[20991],{"type":291,"value":20992},"Unpacking",{"type":281,"tag":319,"props":20994,"children":20995},{"style":365},[20996],{"type":291,"value":20928},{"type":281,"tag":319,"props":20998,"children":20999},{"style":365},[21000],{"type":291,"value":21001}," 100%",{"type":281,"tag":319,"props":21003,"children":21004},{"style":332},[21005],{"type":291,"value":21006}," (11/11), done.\n",{"type":281,"tag":319,"props":21008,"children":21009},{"class":321,"line":307},[21010,21014,21019],{"type":281,"tag":319,"props":21011,"children":21012},{"style":1607},[21013],{"type":291,"value":20872},{"type":281,"tag":319,"props":21015,"children":21016},{"style":365},[21017],{"type":291,"value":21018}," cd",{"type":281,"tag":319,"props":21020,"children":21021},{"style":365},[21022],{"type":291,"value":21023}," RiakToolsCxx/\n",{"type":281,"tag":319,"props":21025,"children":21026},{"class":321,"line":308},[21027,21032,21037],{"type":281,"tag":319,"props":21028,"children":21029},{"style":1607},[21030],{"type":291,"value":21031},"dwalter@knxwork:~/Projects/RiakToolsCxx$",{"type":281,"tag":319,"props":21033,"children":21034},{"style":365},[21035],{"type":291,"value":21036}," mkdir",{"type":281,"tag":319,"props":21038,"children":21039},{"style":365},[21040],{"type":291,"value":21041}," build\n",{"type":281,"tag":319,"props":21043,"children":21044},{"class":321,"line":309},[21045,21049,21053],{"type":281,"tag":319,"props":21046,"children":21047},{"style":1607},[21048],{"type":291,"value":21031},{"type":281,"tag":319,"props":21050,"children":21051},{"style":365},[21052],{"type":291,"value":21018},{"type":281,"tag":319,"props":21054,"children":21055},{"style":365},[21056],{"type":291,"value":21057}," build/\n",{"type":281,"tag":319,"props":21059,"children":21060},{"class":321,"line":310},[21061,21066,21071],{"type":281,"tag":319,"props":21062,"children":21063},{"style":1607},[21064],{"type":291,"value":21065},"dwalter@knxwork:~/Projects/RiakToolsCxx/build$",{"type":281,"tag":319,"props":21067,"children":21068},{"style":365},[21069],{"type":291,"value":21070}," cmake",{"type":281,"tag":319,"props":21072,"children":21073},{"style":365},[21074],{"type":291,"value":21075}," ..\n",{"type":281,"tag":319,"props":21077,"children":21078},{"class":321,"line":973},[21079,21084,21089,21094,21099,21104,21109,21114],{"type":281,"tag":319,"props":21080,"children":21081},{"style":1607},[21082],{"type":291,"value":21083},"--",{"type":281,"tag":319,"props":21085,"children":21086},{"style":365},[21087],{"type":291,"value":21088}," The",{"type":281,"tag":319,"props":21090,"children":21091},{"style":365},[21092],{"type":291,"value":21093}," CXX",{"type":281,"tag":319,"props":21095,"children":21096},{"style":365},[21097],{"type":291,"value":21098}," compiler",{"type":281,"tag":319,"props":21100,"children":21101},{"style":365},[21102],{"type":291,"value":21103}," identification",{"type":281,"tag":319,"props":21105,"children":21106},{"style":365},[21107],{"type":291,"value":21108}," is",{"type":281,"tag":319,"props":21110,"children":21111},{"style":365},[21112],{"type":291,"value":21113}," GNU",{"type":281,"tag":319,"props":21115,"children":21116},{"style":1622},[21117],{"type":291,"value":21118}," 6.3.0\n",{"type":281,"tag":319,"props":21120,"children":21121},{"class":321,"line":986},[21122,21126,21131,21135,21140,21144,21149],{"type":281,"tag":319,"props":21123,"children":21124},{"style":1607},[21125],{"type":291,"value":21083},{"type":281,"tag":319,"props":21127,"children":21128},{"style":365},[21129],{"type":291,"value":21130}," Check",{"type":281,"tag":319,"props":21132,"children":21133},{"style":365},[21134],{"type":291,"value":19935},{"type":281,"tag":319,"props":21136,"children":21137},{"style":365},[21138],{"type":291,"value":21139}," working",{"type":281,"tag":319,"props":21141,"children":21142},{"style":365},[21143],{"type":291,"value":21093},{"type":281,"tag":319,"props":21145,"children":21146},{"style":365},[21147],{"type":291,"value":21148}," compiler:",{"type":281,"tag":319,"props":21150,"children":21151},{"style":365},[21152],{"type":291,"value":21153}," /usr/bin/c++\n",{"type":281,"tag":319,"props":21155,"children":21156},{"class":321,"line":999},[21157,21161,21165,21169,21173,21177,21181,21186,21191],{"type":281,"tag":319,"props":21158,"children":21159},{"style":1607},[21160],{"type":291,"value":21083},{"type":281,"tag":319,"props":21162,"children":21163},{"style":365},[21164],{"type":291,"value":21130},{"type":281,"tag":319,"props":21166,"children":21167},{"style":365},[21168],{"type":291,"value":19935},{"type":281,"tag":319,"props":21170,"children":21171},{"style":365},[21172],{"type":291,"value":21139},{"type":281,"tag":319,"props":21174,"children":21175},{"style":365},[21176],{"type":291,"value":21093},{"type":281,"tag":319,"props":21178,"children":21179},{"style":365},[21180],{"type":291,"value":21148},{"type":281,"tag":319,"props":21182,"children":21183},{"style":365},[21184],{"type":291,"value":21185}," /usr/bin/c++",{"type":281,"tag":319,"props":21187,"children":21188},{"style":1622},[21189],{"type":291,"value":21190}," --",{"type":281,"tag":319,"props":21192,"children":21193},{"style":365},[21194],{"type":291,"value":21195}," works\n",{"type":281,"tag":319,"props":21197,"children":21198},{"class":321,"line":1012},[21199,21203,21208,21212,21216,21221],{"type":281,"tag":319,"props":21200,"children":21201},{"style":1607},[21202],{"type":291,"value":21083},{"type":281,"tag":319,"props":21204,"children":21205},{"style":365},[21206],{"type":291,"value":21207}," Detecting",{"type":281,"tag":319,"props":21209,"children":21210},{"style":365},[21211],{"type":291,"value":21093},{"type":281,"tag":319,"props":21213,"children":21214},{"style":365},[21215],{"type":291,"value":21098},{"type":281,"tag":319,"props":21217,"children":21218},{"style":365},[21219],{"type":291,"value":21220}," ABI",{"type":281,"tag":319,"props":21222,"children":21223},{"style":365},[21224],{"type":291,"value":21225}," info\n",{"type":281,"tag":319,"props":21227,"children":21228},{"class":321,"line":1025},[21229,21233,21237,21241,21245,21249,21254,21259],{"type":281,"tag":319,"props":21230,"children":21231},{"style":1607},[21232],{"type":291,"value":21083},{"type":281,"tag":319,"props":21234,"children":21235},{"style":365},[21236],{"type":291,"value":21207},{"type":281,"tag":319,"props":21238,"children":21239},{"style":365},[21240],{"type":291,"value":21093},{"type":281,"tag":319,"props":21242,"children":21243},{"style":365},[21244],{"type":291,"value":21098},{"type":281,"tag":319,"props":21246,"children":21247},{"style":365},[21248],{"type":291,"value":21220},{"type":281,"tag":319,"props":21250,"children":21251},{"style":365},[21252],{"type":291,"value":21253}," info",{"type":281,"tag":319,"props":21255,"children":21256},{"style":365},[21257],{"type":291,"value":21258}," -",{"type":281,"tag":319,"props":21260,"children":21261},{"style":365},[21262],{"type":291,"value":21263}," done\n",{"type":281,"tag":319,"props":21265,"children":21266},{"class":321,"line":1038},[21267,21271,21275,21279,21284],{"type":281,"tag":319,"props":21268,"children":21269},{"style":1607},[21270],{"type":291,"value":21083},{"type":281,"tag":319,"props":21272,"children":21273},{"style":365},[21274],{"type":291,"value":21207},{"type":281,"tag":319,"props":21276,"children":21277},{"style":365},[21278],{"type":291,"value":21093},{"type":281,"tag":319,"props":21280,"children":21281},{"style":365},[21282],{"type":291,"value":21283}," compile",{"type":281,"tag":319,"props":21285,"children":21286},{"style":365},[21287],{"type":291,"value":21288}," features\n",{"type":281,"tag":319,"props":21290,"children":21291},{"class":321,"line":1048},[21292,21296,21300,21304,21308,21313,21317],{"type":281,"tag":319,"props":21293,"children":21294},{"style":1607},[21295],{"type":291,"value":21083},{"type":281,"tag":319,"props":21297,"children":21298},{"style":365},[21299],{"type":291,"value":21207},{"type":281,"tag":319,"props":21301,"children":21302},{"style":365},[21303],{"type":291,"value":21093},{"type":281,"tag":319,"props":21305,"children":21306},{"style":365},[21307],{"type":291,"value":21283},{"type":281,"tag":319,"props":21309,"children":21310},{"style":365},[21311],{"type":291,"value":21312}," features",{"type":281,"tag":319,"props":21314,"children":21315},{"style":365},[21316],{"type":291,"value":21258},{"type":281,"tag":319,"props":21318,"children":21319},{"style":365},[21320],{"type":291,"value":21263},{"type":281,"tag":319,"props":21322,"children":21323},{"class":321,"line":1061},[21324,21328,21333,21338],{"type":281,"tag":319,"props":21325,"children":21326},{"style":1607},[21327],{"type":291,"value":21083},{"type":281,"tag":319,"props":21329,"children":21330},{"style":365},[21331],{"type":291,"value":21332}," Performing",{"type":281,"tag":319,"props":21334,"children":21335},{"style":365},[21336],{"type":291,"value":21337}," Test",{"type":281,"tag":319,"props":21339,"children":21340},{"style":365},[21341],{"type":291,"value":21342}," COMPILER_SUPPORTS_CXX11\n",{"type":281,"tag":319,"props":21344,"children":21345},{"class":321,"line":1074},[21346,21350,21354,21358,21363,21367],{"type":281,"tag":319,"props":21347,"children":21348},{"style":1607},[21349],{"type":291,"value":21083},{"type":281,"tag":319,"props":21351,"children":21352},{"style":365},[21353],{"type":291,"value":21332},{"type":281,"tag":319,"props":21355,"children":21356},{"style":365},[21357],{"type":291,"value":21337},{"type":281,"tag":319,"props":21359,"children":21360},{"style":365},[21361],{"type":291,"value":21362}," COMPILER_SUPPORTS_CXX11",{"type":281,"tag":319,"props":21364,"children":21365},{"style":365},[21366],{"type":291,"value":21258},{"type":281,"tag":319,"props":21368,"children":21369},{"style":365},[21370],{"type":291,"value":21371}," Success\n",{"type":281,"tag":319,"props":21373,"children":21374},{"class":321,"line":1083},[21375,21379,21383,21387],{"type":281,"tag":319,"props":21376,"children":21377},{"style":1607},[21378],{"type":291,"value":21083},{"type":281,"tag":319,"props":21380,"children":21381},{"style":365},[21382],{"type":291,"value":21332},{"type":281,"tag":319,"props":21384,"children":21385},{"style":365},[21386],{"type":291,"value":21337},{"type":281,"tag":319,"props":21388,"children":21389},{"style":365},[21390],{"type":291,"value":21391}," COMPILER_SUPPORTS_CXX0X\n",{"type":281,"tag":319,"props":21393,"children":21394},{"class":321,"line":1096},[21395,21399,21403,21407,21412,21416],{"type":281,"tag":319,"props":21396,"children":21397},{"style":1607},[21398],{"type":291,"value":21083},{"type":281,"tag":319,"props":21400,"children":21401},{"style":365},[21402],{"type":291,"value":21332},{"type":281,"tag":319,"props":21404,"children":21405},{"style":365},[21406],{"type":291,"value":21337},{"type":281,"tag":319,"props":21408,"children":21409},{"style":365},[21410],{"type":291,"value":21411}," COMPILER_SUPPORTS_CXX0X",{"type":281,"tag":319,"props":21413,"children":21414},{"style":365},[21415],{"type":291,"value":21258},{"type":281,"tag":319,"props":21417,"children":21418},{"style":365},[21419],{"type":291,"value":21371},{"type":281,"tag":319,"props":21421,"children":21422},{"class":321,"line":1109},[21423,21427,21431,21436,21440,21444,21448,21452],{"type":281,"tag":319,"props":21424,"children":21425},{"style":1607},[21426],{"type":291,"value":21083},{"type":281,"tag":319,"props":21428,"children":21429},{"style":365},[21430],{"type":291,"value":21088},{"type":281,"tag":319,"props":21432,"children":21433},{"style":365},[21434],{"type":291,"value":21435}," C",{"type":281,"tag":319,"props":21437,"children":21438},{"style":365},[21439],{"type":291,"value":21098},{"type":281,"tag":319,"props":21441,"children":21442},{"style":365},[21443],{"type":291,"value":21103},{"type":281,"tag":319,"props":21445,"children":21446},{"style":365},[21447],{"type":291,"value":21108},{"type":281,"tag":319,"props":21449,"children":21450},{"style":365},[21451],{"type":291,"value":21113},{"type":281,"tag":319,"props":21453,"children":21454},{"style":1622},[21455],{"type":291,"value":21118},{"type":281,"tag":319,"props":21457,"children":21458},{"class":321,"line":1122},[21459,21463,21467,21471,21475,21479,21483],{"type":281,"tag":319,"props":21460,"children":21461},{"style":1607},[21462],{"type":291,"value":21083},{"type":281,"tag":319,"props":21464,"children":21465},{"style":365},[21466],{"type":291,"value":21130},{"type":281,"tag":319,"props":21468,"children":21469},{"style":365},[21470],{"type":291,"value":19935},{"type":281,"tag":319,"props":21472,"children":21473},{"style":365},[21474],{"type":291,"value":21139},{"type":281,"tag":319,"props":21476,"children":21477},{"style":365},[21478],{"type":291,"value":21435},{"type":281,"tag":319,"props":21480,"children":21481},{"style":365},[21482],{"type":291,"value":21148},{"type":281,"tag":319,"props":21484,"children":21485},{"style":365},[21486],{"type":291,"value":21487}," /usr/bin/cc\n",{"type":281,"tag":319,"props":21489,"children":21490},{"class":321,"line":1130},[21491,21495,21499,21503,21507,21511,21515,21520,21524],{"type":281,"tag":319,"props":21492,"children":21493},{"style":1607},[21494],{"type":291,"value":21083},{"type":281,"tag":319,"props":21496,"children":21497},{"style":365},[21498],{"type":291,"value":21130},{"type":281,"tag":319,"props":21500,"children":21501},{"style":365},[21502],{"type":291,"value":19935},{"type":281,"tag":319,"props":21504,"children":21505},{"style":365},[21506],{"type":291,"value":21139},{"type":281,"tag":319,"props":21508,"children":21509},{"style":365},[21510],{"type":291,"value":21435},{"type":281,"tag":319,"props":21512,"children":21513},{"style":365},[21514],{"type":291,"value":21148},{"type":281,"tag":319,"props":21516,"children":21517},{"style":365},[21518],{"type":291,"value":21519}," /usr/bin/cc",{"type":281,"tag":319,"props":21521,"children":21522},{"style":1622},[21523],{"type":291,"value":21190},{"type":281,"tag":319,"props":21525,"children":21526},{"style":365},[21527],{"type":291,"value":21195},{"type":281,"tag":319,"props":21529,"children":21530},{"class":321,"line":1143},[21531,21535,21539,21543,21547,21551],{"type":281,"tag":319,"props":21532,"children":21533},{"style":1607},[21534],{"type":291,"value":21083},{"type":281,"tag":319,"props":21536,"children":21537},{"style":365},[21538],{"type":291,"value":21207},{"type":281,"tag":319,"props":21540,"children":21541},{"style":365},[21542],{"type":291,"value":21435},{"type":281,"tag":319,"props":21544,"children":21545},{"style":365},[21546],{"type":291,"value":21098},{"type":281,"tag":319,"props":21548,"children":21549},{"style":365},[21550],{"type":291,"value":21220},{"type":281,"tag":319,"props":21552,"children":21553},{"style":365},[21554],{"type":291,"value":21225},{"type":281,"tag":319,"props":21556,"children":21557},{"class":321,"line":1156},[21558,21562,21566,21570,21574,21578,21582,21586],{"type":281,"tag":319,"props":21559,"children":21560},{"style":1607},[21561],{"type":291,"value":21083},{"type":281,"tag":319,"props":21563,"children":21564},{"style":365},[21565],{"type":291,"value":21207},{"type":281,"tag":319,"props":21567,"children":21568},{"style":365},[21569],{"type":291,"value":21435},{"type":281,"tag":319,"props":21571,"children":21572},{"style":365},[21573],{"type":291,"value":21098},{"type":281,"tag":319,"props":21575,"children":21576},{"style":365},[21577],{"type":291,"value":21220},{"type":281,"tag":319,"props":21579,"children":21580},{"style":365},[21581],{"type":291,"value":21253},{"type":281,"tag":319,"props":21583,"children":21584},{"style":365},[21585],{"type":291,"value":21258},{"type":281,"tag":319,"props":21587,"children":21588},{"style":365},[21589],{"type":291,"value":21263},{"type":281,"tag":319,"props":21591,"children":21592},{"class":321,"line":1169},[21593,21597,21601,21605,21609],{"type":281,"tag":319,"props":21594,"children":21595},{"style":1607},[21596],{"type":291,"value":21083},{"type":281,"tag":319,"props":21598,"children":21599},{"style":365},[21600],{"type":291,"value":21207},{"type":281,"tag":319,"props":21602,"children":21603},{"style":365},[21604],{"type":291,"value":21435},{"type":281,"tag":319,"props":21606,"children":21607},{"style":365},[21608],{"type":291,"value":21283},{"type":281,"tag":319,"props":21610,"children":21611},{"style":365},[21612],{"type":291,"value":21288},{"type":281,"tag":319,"props":21614,"children":21615},{"class":321,"line":1182},[21616,21620,21624,21628,21632,21636,21640],{"type":281,"tag":319,"props":21617,"children":21618},{"style":1607},[21619],{"type":291,"value":21083},{"type":281,"tag":319,"props":21621,"children":21622},{"style":365},[21623],{"type":291,"value":21207},{"type":281,"tag":319,"props":21625,"children":21626},{"style":365},[21627],{"type":291,"value":21435},{"type":281,"tag":319,"props":21629,"children":21630},{"style":365},[21631],{"type":291,"value":21283},{"type":281,"tag":319,"props":21633,"children":21634},{"style":365},[21635],{"type":291,"value":21312},{"type":281,"tag":319,"props":21637,"children":21638},{"style":365},[21639],{"type":291,"value":21258},{"type":281,"tag":319,"props":21641,"children":21642},{"style":365},[21643],{"type":291,"value":21263},{"type":281,"tag":319,"props":21645,"children":21646},{"class":321,"line":1195},[21647,21651,21656,21661],{"type":281,"tag":319,"props":21648,"children":21649},{"style":1607},[21650],{"type":291,"value":21083},{"type":281,"tag":319,"props":21652,"children":21653},{"style":365},[21654],{"type":291,"value":21655}," Boost",{"type":281,"tag":319,"props":21657,"children":21658},{"style":365},[21659],{"type":291,"value":21660}," version:",{"type":281,"tag":319,"props":21662,"children":21663},{"style":1622},[21664],{"type":291,"value":21665}," 1.62.0\n",{"type":281,"tag":319,"props":21667,"children":21668},{"class":321,"line":2048},[21669,21673,21678,21683,21688,21692],{"type":281,"tag":319,"props":21670,"children":21671},{"style":1607},[21672],{"type":291,"value":21083},{"type":281,"tag":319,"props":21674,"children":21675},{"style":365},[21676],{"type":291,"value":21677}," Found",{"type":281,"tag":319,"props":21679,"children":21680},{"style":365},[21681],{"type":291,"value":21682}," the",{"type":281,"tag":319,"props":21684,"children":21685},{"style":365},[21686],{"type":291,"value":21687}," following",{"type":281,"tag":319,"props":21689,"children":21690},{"style":365},[21691],{"type":291,"value":21655},{"type":281,"tag":319,"props":21693,"children":21694},{"style":365},[21695],{"type":291,"value":21696}," libraries:\n",{"type":281,"tag":319,"props":21698,"children":21699},{"class":321,"line":2049},[21700,21704],{"type":281,"tag":319,"props":21701,"children":21702},{"style":1607},[21703],{"type":291,"value":21083},{"type":281,"tag":319,"props":21705,"children":21706},{"style":365},[21707],{"type":291,"value":21708},"   filesystem\n",{"type":281,"tag":319,"props":21710,"children":21711},{"class":321,"line":2050},[21712,21716],{"type":281,"tag":319,"props":21713,"children":21714},{"style":1607},[21715],{"type":291,"value":21083},{"type":281,"tag":319,"props":21717,"children":21718},{"style":365},[21719],{"type":291,"value":21720},"   system\n",{"type":281,"tag":319,"props":21722,"children":21723},{"class":321,"line":2051},[21724,21728,21733],{"type":281,"tag":319,"props":21725,"children":21726},{"style":1607},[21727],{"type":291,"value":21083},{"type":281,"tag":319,"props":21729,"children":21730},{"style":365},[21731],{"type":291,"value":21732}," Configuring",{"type":281,"tag":319,"props":21734,"children":21735},{"style":365},[21736],{"type":291,"value":21263},{"type":281,"tag":319,"props":21738,"children":21739},{"class":321,"line":2052},[21740,21744,21749],{"type":281,"tag":319,"props":21741,"children":21742},{"style":1607},[21743],{"type":291,"value":21083},{"type":281,"tag":319,"props":21745,"children":21746},{"style":365},[21747],{"type":291,"value":21748}," Generating",{"type":281,"tag":319,"props":21750,"children":21751},{"style":365},[21752],{"type":291,"value":21263},{"type":281,"tag":319,"props":21754,"children":21755},{"class":321,"line":2053},[21756,21760,21765,21770,21775,21780,21785,21790],{"type":281,"tag":319,"props":21757,"children":21758},{"style":1607},[21759],{"type":291,"value":21083},{"type":281,"tag":319,"props":21761,"children":21762},{"style":365},[21763],{"type":291,"value":21764}," Build",{"type":281,"tag":319,"props":21766,"children":21767},{"style":365},[21768],{"type":291,"value":21769}," files",{"type":281,"tag":319,"props":21771,"children":21772},{"style":365},[21773],{"type":291,"value":21774}," have",{"type":281,"tag":319,"props":21776,"children":21777},{"style":365},[21778],{"type":291,"value":21779}," been",{"type":281,"tag":319,"props":21781,"children":21782},{"style":365},[21783],{"type":291,"value":21784}," written",{"type":281,"tag":319,"props":21786,"children":21787},{"style":365},[21788],{"type":291,"value":21789}," to:",{"type":281,"tag":319,"props":21791,"children":21792},{"style":365},[21793],{"type":291,"value":21794}," /home/dwalter/Projects/RiakToolsCxx/build\n",{"type":281,"tag":319,"props":21796,"children":21797},{"class":321,"line":2054},[21798,21802],{"type":281,"tag":319,"props":21799,"children":21800},{"style":1607},[21801],{"type":291,"value":21065},{"type":281,"tag":319,"props":21803,"children":21804},{"style":365},[21805],{"type":291,"value":21806}," make\n",{"type":281,"tag":319,"props":21808,"children":21809},{"class":321,"line":2055},[21810,21815,21820,21825,21830],{"type":281,"tag":319,"props":21811,"children":21812},{"style":1607},[21813],{"type":291,"value":21814},"Scanning",{"type":281,"tag":319,"props":21816,"children":21817},{"style":365},[21818],{"type":291,"value":21819}," dependencies",{"type":281,"tag":319,"props":21821,"children":21822},{"style":365},[21823],{"type":291,"value":21824}," of",{"type":281,"tag":319,"props":21826,"children":21827},{"style":365},[21828],{"type":291,"value":21829}," target",{"type":281,"tag":319,"props":21831,"children":21832},{"style":365},[21833],{"type":291,"value":21834}," leveldb-basho\n",{"type":281,"tag":319,"props":21836,"children":21837},{"class":321,"line":2579},[21838,21843,21848],{"type":281,"tag":319,"props":21839,"children":21840},{"style":332},[21841],{"type":291,"value":21842},"[ 10%] Creating directories ",{"type":281,"tag":319,"props":21844,"children":21845},{"style":7965},[21846],{"type":291,"value":21847},"for",{"type":281,"tag":319,"props":21849,"children":21850},{"style":365},[21851],{"type":291,"value":21852}," 'leveldb-basho'\n",{"type":281,"tag":319,"props":21854,"children":21855},{"class":321,"line":2056},[21856,21861,21865,21869,21874,21878],{"type":281,"tag":319,"props":21857,"children":21858},{"style":332},[21859],{"type":291,"value":21860},"[ 20%] Performing download step (",{"type":281,"tag":319,"props":21862,"children":21863},{"style":1607},[21864],{"type":291,"value":554},{"type":281,"tag":319,"props":21866,"children":21867},{"style":365},[21868],{"type":291,"value":20882},{"type":281,"tag":319,"props":21870,"children":21871},{"style":332},[21872],{"type":291,"value":21873},") ",{"type":281,"tag":319,"props":21875,"children":21876},{"style":7965},[21877],{"type":291,"value":21847},{"type":281,"tag":319,"props":21879,"children":21880},{"style":365},[21881],{"type":291,"value":21852},{"type":281,"tag":319,"props":21883,"children":21884},{"class":321,"line":2605},[21885,21889,21893],{"type":281,"tag":319,"props":21886,"children":21887},{"style":1607},[21888],{"type":291,"value":20900},{"type":281,"tag":319,"props":21890,"children":21891},{"style":365},[21892],{"type":291,"value":20905},{"type":281,"tag":319,"props":21894,"children":21895},{"style":365},[21896],{"type":291,"value":21897}," 'leveldb-basho'...\n",{"type":281,"tag":319,"props":21899,"children":21900},{"class":321,"line":2613},[21901,21906,21911],{"type":281,"tag":319,"props":21902,"children":21903},{"style":1607},[21904],{"type":291,"value":21905},"Already",{"type":281,"tag":319,"props":21907,"children":21908},{"style":365},[21909],{"type":291,"value":21910}," on",{"type":281,"tag":319,"props":21912,"children":21913},{"style":365},[21914],{"type":291,"value":21915}," 'develop'\n",{"type":281,"tag":319,"props":21917,"children":21918},{"class":321,"line":2626},[21919,21924,21929,21933,21938,21943],{"type":281,"tag":319,"props":21920,"children":21921},{"style":1607},[21922],{"type":291,"value":21923},"Your",{"type":281,"tag":319,"props":21925,"children":21926},{"style":365},[21927],{"type":291,"value":21928}," branch",{"type":281,"tag":319,"props":21930,"children":21931},{"style":365},[21932],{"type":291,"value":21108},{"type":281,"tag":319,"props":21934,"children":21935},{"style":365},[21936],{"type":291,"value":21937}," up-to-date",{"type":281,"tag":319,"props":21939,"children":21940},{"style":365},[21941],{"type":291,"value":21942}," with",{"type":281,"tag":319,"props":21944,"children":21945},{"style":365},[21946],{"type":291,"value":21947}," 'origin/develop'.\n",{"type":281,"tag":319,"props":21949,"children":21950},{"class":321,"line":2648},[21951,21956,21960],{"type":281,"tag":319,"props":21952,"children":21953},{"style":332},[21954],{"type":291,"value":21955},"[ 30%] No patch step ",{"type":281,"tag":319,"props":21957,"children":21958},{"style":7965},[21959],{"type":291,"value":21847},{"type":281,"tag":319,"props":21961,"children":21962},{"style":365},[21963],{"type":291,"value":21852},{"type":281,"tag":319,"props":21965,"children":21966},{"class":321,"line":2661},[21967,21972,21976],{"type":281,"tag":319,"props":21968,"children":21969},{"style":332},[21970],{"type":291,"value":21971},"[ 40%] No update step ",{"type":281,"tag":319,"props":21973,"children":21974},{"style":7965},[21975],{"type":291,"value":21847},{"type":281,"tag":319,"props":21977,"children":21978},{"style":365},[21979],{"type":291,"value":21852},{"type":281,"tag":319,"props":21981,"children":21982},{"class":321,"line":2675},[21983,21988,21992],{"type":281,"tag":319,"props":21984,"children":21985},{"style":332},[21986],{"type":291,"value":21987},"[ 50%] No configure step ",{"type":281,"tag":319,"props":21989,"children":21990},{"style":7965},[21991],{"type":291,"value":21847},{"type":281,"tag":319,"props":21993,"children":21994},{"style":365},[21995],{"type":291,"value":21852},{"type":281,"tag":319,"props":21997,"children":21998},{"class":321,"line":2693},[21999,22004,22008],{"type":281,"tag":319,"props":22000,"children":22001},{"style":332},[22002],{"type":291,"value":22003},"[ 60%] Performing build step ",{"type":281,"tag":319,"props":22005,"children":22006},{"style":7965},[22007],{"type":291,"value":21847},{"type":281,"tag":319,"props":22009,"children":22010},{"style":365},[22011],{"type":291,"value":21852},{"type":281,"tag":319,"props":22013,"children":22014},{"class":321,"line":2706},[22015,22020,22025],{"type":281,"tag":319,"props":22016,"children":22017},{"style":1607},[22018],{"type":291,"value":22019},"ar:",{"type":281,"tag":319,"props":22021,"children":22022},{"style":365},[22023],{"type":291,"value":22024}," creating",{"type":281,"tag":319,"props":22026,"children":22027},{"style":365},[22028],{"type":291,"value":22029}," libleveldb.a\n",{"type":281,"tag":319,"props":22031,"children":22032},{"class":321,"line":2719},[22033,22038,22042],{"type":281,"tag":319,"props":22034,"children":22035},{"style":332},[22036],{"type":291,"value":22037},"[ 70%] No install step ",{"type":281,"tag":319,"props":22039,"children":22040},{"style":7965},[22041],{"type":291,"value":21847},{"type":281,"tag":319,"props":22043,"children":22044},{"style":365},[22045],{"type":291,"value":21852},{"type":281,"tag":319,"props":22047,"children":22048},{"class":321,"line":2732},[22049,22054],{"type":281,"tag":319,"props":22050,"children":22051},{"style":332},[22052],{"type":291,"value":22053},"[ 80%] Completed ",{"type":281,"tag":319,"props":22055,"children":22056},{"style":365},[22057],{"type":291,"value":22058},"'leveldb-basho'\n",{"type":281,"tag":319,"props":22060,"children":22061},{"class":321,"line":2750},[22062],{"type":281,"tag":319,"props":22063,"children":22064},{"style":332},[22065],{"type":291,"value":22066},"[ 80%] Built target leveldb-basho\n",{"type":281,"tag":319,"props":22068,"children":22069},{"class":321,"line":2768},[22070,22074,22078,22082,22086],{"type":281,"tag":319,"props":22071,"children":22072},{"style":1607},[22073],{"type":291,"value":21814},{"type":281,"tag":319,"props":22075,"children":22076},{"style":365},[22077],{"type":291,"value":21819},{"type":281,"tag":319,"props":22079,"children":22080},{"style":365},[22081],{"type":291,"value":21824},{"type":281,"tag":319,"props":22083,"children":22084},{"style":365},[22085],{"type":291,"value":21829},{"type":281,"tag":319,"props":22087,"children":22088},{"style":365},[22089],{"type":291,"value":22090}," riakcompact\n",{"type":281,"tag":319,"props":22092,"children":22093},{"class":321,"line":2781},[22094],{"type":281,"tag":319,"props":22095,"children":22096},{"style":332},[22097],{"type":291,"value":22098},"[ 90%] Building CXX object src/CMakeFiles/riakcompact.dir/main.cpp.o\n",{"type":281,"tag":319,"props":22100,"children":22101},{"class":321,"line":2801},[22102],{"type":281,"tag":319,"props":22103,"children":22104},{"style":332},[22105],{"type":291,"value":22106},"[100%] Linking CXX executable riakcompact\n",{"type":281,"tag":319,"props":22108,"children":22109},{"class":321,"line":2821},[22110],{"type":281,"tag":319,"props":22111,"children":22112},{"style":332},[22113],{"type":291,"value":22114},"[100%] Built target riakcompact\n",{"type":281,"tag":319,"props":22116,"children":22117},{"class":321,"line":2838},[22118,22122,22127],{"type":281,"tag":319,"props":22119,"children":22120},{"style":1607},[22121],{"type":291,"value":21065},{"type":281,"tag":319,"props":22123,"children":22124},{"style":365},[22125],{"type":291,"value":22126}," ./src/riakcompact",{"type":281,"tag":319,"props":22128,"children":22129},{"style":332},[22130],{"type":291,"value":22131}," \n",{"type":281,"tag":319,"props":22133,"children":22134},{"class":321,"line":3607},[22135,22140,22145],{"type":281,"tag":319,"props":22136,"children":22137},{"style":1607},[22138],{"type":291,"value":22139},"usage:",{"type":281,"tag":319,"props":22141,"children":22142},{"style":365},[22143],{"type":291,"value":22144},"   ./src/riakcompact",{"type":281,"tag":319,"props":22146,"children":22147},{"style":332},[22148],{"type":291,"value":22149}," [path]\n",{"type":281,"tag":282,"props":22151,"children":22152},{},[22153],{"type":291,"value":22154},"After this tool is build you can use it like this. Take in mind that your Riak node has to be turned off!",{"type":281,"tag":301,"props":22156,"children":22158},{"className":18404,"code":22157,"language":18406,"meta":8,"style":8},"root@knxwork:/home/dwalter/Projects/RiakToolsCxx/build# ./src/riakcompact /var/lib/riak/leveldb/\n\"/var/lib/riak/leveldb/91343852333181432387730302044767688728495783936\" [directory]\ncompacting...\ndone\n\"/var/lib/riak/leveldb/685078892498860742907977265335757665463718379520\" [directory]\ncompacting...\ndone\n",[22159],{"type":281,"tag":315,"props":22160,"children":22161},{"__ignoreMap":8},[22162,22179,22192,22200,22208,22220,22227],{"type":281,"tag":319,"props":22163,"children":22164},{"class":321,"line":322},[22165,22170,22174],{"type":281,"tag":319,"props":22166,"children":22167},{"style":1607},[22168],{"type":291,"value":22169},"root@knxwork:/home/dwalter/Projects/RiakToolsCxx/build#",{"type":281,"tag":319,"props":22171,"children":22172},{"style":365},[22173],{"type":291,"value":22126},{"type":281,"tag":319,"props":22175,"children":22176},{"style":365},[22177],{"type":291,"value":22178}," /var/lib/riak/leveldb/\n",{"type":281,"tag":319,"props":22180,"children":22181},{"class":321,"line":338},[22182,22187],{"type":281,"tag":319,"props":22183,"children":22184},{"style":1607},[22185],{"type":291,"value":22186},"\"/var/lib/riak/leveldb/91343852333181432387730302044767688728495783936\"",{"type":281,"tag":319,"props":22188,"children":22189},{"style":332},[22190],{"type":291,"value":22191}," [directory]\n",{"type":281,"tag":319,"props":22193,"children":22194},{"class":321,"line":351},[22195],{"type":281,"tag":319,"props":22196,"children":22197},{"style":1607},[22198],{"type":291,"value":22199},"compacting...\n",{"type":281,"tag":319,"props":22201,"children":22202},{"class":321,"line":371},[22203],{"type":281,"tag":319,"props":22204,"children":22205},{"style":7965},[22206],{"type":291,"value":22207},"done\n",{"type":281,"tag":319,"props":22209,"children":22210},{"class":321,"line":306},[22211,22216],{"type":281,"tag":319,"props":22212,"children":22213},{"style":1607},[22214],{"type":291,"value":22215},"\"/var/lib/riak/leveldb/685078892498860742907977265335757665463718379520\"",{"type":281,"tag":319,"props":22217,"children":22218},{"style":332},[22219],{"type":291,"value":22191},{"type":281,"tag":319,"props":22221,"children":22222},{"class":321,"line":307},[22223],{"type":281,"tag":319,"props":22224,"children":22225},{"style":1607},[22226],{"type":291,"value":22199},{"type":281,"tag":319,"props":22228,"children":22229},{"class":321,"line":308},[22230],{"type":281,"tag":319,"props":22231,"children":22232},{"style":7965},[22233],{"type":291,"value":22207},{"type":281,"tag":530,"props":22235,"children":22236},{"id":18131},[22237],{"type":291,"value":18134},{"type":281,"tag":282,"props":22239,"children":22240},{},[22241],{"type":281,"tag":11280,"props":22242,"children":22243},{},[22244],{"type":291,"value":22245},"After deleting a complete bucket in our riak (key by key), we are able to reduce consumed disk space from 75GB to 25GB with this tool!",{"type":281,"tag":11512,"props":22247,"children":22249},{"id":22248},"compaction-freed-more-than-66-of-the-data",[22250],{"type":291,"value":22251},"Compaction freed more than 66% of the data!",{"type":281,"tag":1477,"props":22253,"children":22254},{},[22255],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":22257},[22258,22259,22260,22261,22262],{"id":532,"depth":338,"text":20728},{"id":20744,"depth":338,"text":20747},{"id":20804,"depth":338,"text":20807},{"id":20832,"depth":338,"text":20835},{"id":18131,"depth":338,"text":18134},{"_path":236,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":237,"description":238,"author":136,"image":239,"releaseDate":240,"blogCategories":22264,"articleTags":22265,"tags":22266,"body":22267,"_type":20,"_id":245,"_source":22,"_file":246,"_stem":247,"_extension":25},[15,242],[203],[19,231],{"type":278,"children":22268,"toc":23091},[22269,22275,22286,22303,22308,22314,22358,22364,22369,22486,22491,22496,22502,22507,22513,22592,22598,22603,22608,22658,22814,22830,22836,22841,22904,22910,22915,22962,22968,22973,22990,23002,23013,23032,23069,23087],{"type":281,"tag":530,"props":22270,"children":22272},{"id":22271},"what-it-is-good-for",[22273],{"type":291,"value":22274},"What it is good for",{"type":281,"tag":282,"props":22276,"children":22277},{},[22278,22280],{"type":291,"value":22279},"This article is about using BTRFS snapshots as backup solution, usable for databases and full root partition backups. This is not a detailed Step-By-Step guide and requires some linux skills. This Post aims to share my experiences and save you some hassle. We use it in production for years now.\n",{"type":281,"tag":1499,"props":22281,"children":22285},{"alt":22282,"aspect-ratio":22283,"height":20603,"object-fit":19308,"src":22284},"btrfs","5","/blog/btrfs.png",[],{"type":281,"tag":282,"props":22287,"children":22288},{},[22289,22291,22296,22298],{"type":291,"value":22290},"BTRFS snapshots are storing a \"freezed\" Version of the whole filesystem. This is done by BTRFS's copy-on-write technique. This means that modifications on snapshotted files are not written directly into the file like it is done on classic filesystems like ext4. instead, all modifications are written in some other place, so both, the current and the snapshotted version of the file is present. This ",{"type":281,"tag":11370,"props":22292,"children":22293},{},[22294],{"type":291,"value":22295},"Copy-On-Write",{"type":291,"value":22297}," (COW) technique brings a lot nice features to BTRFS,  ",{"type":281,"tag":11280,"props":22299,"children":22300},{},[22301],{"type":291,"value":22302},"but has also some drawbacks you should know about before using BTRFS in production. See \"Always disable COW on Database directories\" below.",{"type":281,"tag":282,"props":22304,"children":22305},{},[22306],{"type":291,"value":22307},"BTRFS has a powerful snapshot capability that allows to incrementally transfer snapshots to remote systems. Its just so simple: create a snapshot, transfer it to a remote system, create a 2nd snapshot and only transfer the changed blocks from the previous one. Solaris/FreeBSD users are doing this for almost a decade with ZFS. A ZFS port is also available for linux, so you can also use it instead of BTRFS if you prefer it for some reason.",{"type":281,"tag":530,"props":22309,"children":22311},{"id":22310},"use-cases-of-btrfs-snapshots",[22312],{"type":291,"value":22313},"Use-Cases of BTRFS-Snapshots",{"type":281,"tag":455,"props":22315,"children":22316},{},[22317,22335,22340,22345],{"type":281,"tag":459,"props":22318,"children":22319},{},[22320,22322],{"type":291,"value":22321},"Backup Root Partitions of one or more Linux-Servers to a central backup Server\n",{"type":281,"tag":455,"props":22323,"children":22324},{},[22325,22330],{"type":281,"tag":459,"props":22326,"children":22327},{},[22328],{"type":291,"value":22329},"Its possible to directly boot the backup server into one of the snapshots, allowing a manual fail-over",{"type":281,"tag":459,"props":22331,"children":22332},{},[22333],{"type":291,"value":22334},"The snapshots can also be transferred into virtual machines. This becomes very handy if you want your “dev vm” to be up to date with the live system and update it with incremental snapshots regularly.",{"type":281,"tag":459,"props":22336,"children":22337},{},[22338],{"type":291,"value":22339},"Backup MySQL, Postgres or whatever data partitions separately at a cycle different from other mount points",{"type":281,"tag":459,"props":22341,"children":22342},{},[22343],{"type":291,"value":22344},"You can use BTRFS Snapshots on the Root partitions to return to a functional rootfs after a failed system upgrade",{"type":281,"tag":459,"props":22346,"children":22347},{},[22348,22350],{"type":291,"value":22349},"If you are a developer, you can use BTRFS Snapshots locally with your Database to test your data-modifying application again and again against the same starting dataset.\n",{"type":281,"tag":455,"props":22351,"children":22352},{},[22353],{"type":281,"tag":459,"props":22354,"children":22355},{},[22356],{"type":291,"value":22357},"you can also share your dev database snapshots with your coworkers and give incremental updates to them.",{"type":281,"tag":530,"props":22359,"children":22361},{"id":22360},"backing-up-a-database-pro-and-cons-of-different-methods",[22362],{"type":291,"value":22363},"Backing up a Database, pro and cons of different methods",{"type":281,"tag":282,"props":22365,"children":22366},{},[22367],{"type":291,"value":22368},"When thinking about MySQL/MariaDB (and some other databases) backups, you have some options to consider:",{"type":281,"tag":608,"props":22370,"children":22371},{},[22372,22403,22429,22450],{"type":281,"tag":459,"props":22373,"children":22374},{},[22375,22380],{"type":281,"tag":11280,"props":22376,"children":22377},{},[22378],{"type":291,"value":22379},"use mysqldump to create a logical backup (also on per-table basis)",{"type":281,"tag":608,"props":22381,"children":22382},{},[22383,22388,22393,22398],{"type":281,"tag":459,"props":22384,"children":22385},{},[22386],{"type":291,"value":22387},"It is slow and creates noticeable load on the server",{"type":281,"tag":459,"props":22389,"children":22390},{},[22391],{"type":291,"value":22392},"Hard to create consistent state (requires locks or a desync replication slave)",{"type":281,"tag":459,"props":22394,"children":22395},{},[22396],{"type":291,"value":22397},"Not incremental, even when backing up only modified tables; if those tables are large, this is a problem.",{"type":281,"tag":459,"props":22399,"children":22400},{},[22401],{"type":291,"value":22402},"Restore: import the dump somewhere, can take ages with large datasets.",{"type":281,"tag":459,"props":22404,"children":22405},{},[22406,22411],{"type":281,"tag":11280,"props":22407,"children":22408},{},[22409],{"type":291,"value":22410},"use mysql binary logs for incremental backup",{"type":281,"tag":608,"props":22412,"children":22413},{},[22414,22419,22424],{"type":281,"tag":459,"props":22415,"children":22416},{},[22417],{"type":291,"value":22418},"allows point-in-time recovery (recover to any moment in the past)",{"type":281,"tag":459,"props":22420,"children":22421},{},[22422],{"type":291,"value":22423},"replaying binary logs can take a long time on write-intensive setups",{"type":281,"tag":459,"props":22425,"children":22426},{},[22427],{"type":291,"value":22428},"you have to do full backups regulary because of this",{"type":281,"tag":459,"props":22430,"children":22431},{},[22432,22437],{"type":281,"tag":11280,"props":22433,"children":22434},{},[22435],{"type":291,"value":22436},"use innobackupex incremental method",{"type":281,"tag":608,"props":22438,"children":22439},{},[22440,22445],{"type":281,"tag":459,"props":22441,"children":22442},{},[22443],{"type":291,"value":22444},"while its more advanced, it seems to have the same characteristics as with mysql binary logs.",{"type":281,"tag":459,"props":22446,"children":22447},{},[22448],{"type":291,"value":22449},"Its also resource intensive and requires a full database lock at the end of the data transfer.",{"type":281,"tag":459,"props":22451,"children":22452},{},[22453,22458],{"type":281,"tag":11280,"props":22454,"children":22455},{},[22456],{"type":291,"value":22457},"use filesystem snapshots",{"type":281,"tag":608,"props":22459,"children":22460},{},[22461,22466,22471,22476,22481],{"type":281,"tag":459,"props":22462,"children":22463},{},[22464],{"type":291,"value":22465},"no point-in-time recovery",{"type":281,"tag":459,"props":22467,"children":22468},{},[22469],{"type":291,"value":22470},"endless incremental, do one full backup and then only incremental ones.",{"type":281,"tag":459,"props":22472,"children":22473},{},[22474],{"type":291,"value":22475},"fast and resource-saving backup process",{"type":281,"tag":459,"props":22477,"children":22478},{},[22479],{"type":291,"value":22480},"restore: you can launch a instance of your database from every snapshot directly on the backup system or move the full mysql directory back to the source server if needet.",{"type":281,"tag":459,"props":22482,"children":22483},{},[22484],{"type":291,"value":22485},"only downside is that you have to relie on the databases own power-outage recovery mechanism.",{"type":281,"tag":282,"props":22487,"children":22488},{},[22489],{"type":291,"value":22490},"While doing mysqldump backups in the past, we now use the filesystem snapshot way. It has proven to be a very reliable, fast and resource-saving way of doing backups and also provides easy restore of the backed up data. It is very common that our Devs ask for a specific data version to be started on the backup server. this is done within 10 minutes and saves them a lot of time.",{"type":281,"tag":282,"props":22492,"children":22493},{},[22494],{"type":291,"value":22495},"A filesystem snapshot is a consistent state of a filesystem that is not modified anymore. From data-integrity point of view, a snapshot features a unclean state like you have after an power failure, a kill -9 or an “Out of Memory” error. Because MySQL/MariaDB and other database engines are designed to survive power failures, you are always able to recover from a snapshot too.",{"type":281,"tag":530,"props":22497,"children":22499},{"id":22498},"stability-of-btrfs-and-production-readyness",[22500],{"type":291,"value":22501},"Stability of BTRFS and production-readyness",{"type":281,"tag":282,"props":22503,"children":22504},{},[22505],{"type":291,"value":22506},"The stability and reliability of BTRFS has been discussed a lot in the past. While it still may have some bugs and problems, they are said to be unlikely to cause data loss. BTRFS improves a lot with every new linux kernel release, we are using it since linux 3.17 in production and even longer on our workstations.",{"type":281,"tag":530,"props":22508,"children":22510},{"id":22509},"using-btrfs-snapshots-for-backup",[22511],{"type":291,"value":22512},"Using BTRFS Snapshots for Backup",{"type":281,"tag":455,"props":22514,"children":22515},{},[22516,22521,22526,22531,22542,22563,22582],{"type":281,"tag":459,"props":22517,"children":22518},{},[22519],{"type":291,"value":22520},"As said before, BTRFS is improving with every linux kernel release, so it is recommended to use a recent kernel version, like 4.9 LTS or newer.",{"type":281,"tag":459,"props":22522,"children":22523},{},[22524],{"type":291,"value":22525},"Obvious: because we want to use BTRFS snapshotting, we need to put the data we want to save on a btrfs volume.",{"type":281,"tag":459,"props":22527,"children":22528},{},[22529],{"type":291,"value":22530},"You need to have BTRFS filesystems running on both source (production)  and destination (backup) server.",{"type":281,"tag":459,"props":22532,"children":22533},{},[22534,22536,22541],{"type":291,"value":22535},"If you dont have btrfs already, you can resize your current filesystem to make some space on the hard drive and create a btrfs there. If you just want to test, you can create a image file and mount it using ",{"type":281,"tag":11370,"props":22537,"children":22538},{},[22539],{"type":291,"value":22540},"losetup",{"type":291,"value":564},{"type":281,"tag":459,"props":22543,"children":22544},{},[22545,22547,22553,22555],{"type":291,"value":22546},"If you are already using BTRFS as rootfs, you can use *btrfs subvolume create ",{"type":281,"tag":315,"props":22548,"children":22550},{"className":22549},[],[22551],{"type":291,"value":22552},"\u003Cpath>*",{"type":291,"value":22554}," to create a new subvolume, i.e. for MySQL. Why should you? Because you may want to backup the mysql data dir more often than the rest of the system. BTRFS snapshots work on per-volume basis, so if you want to backup files independently (or exclude them form backup) you have to put them into a subvolume. You can backup multiple subvolumes from one machine, you just have to create a backup job for each.\n",{"type":281,"tag":455,"props":22556,"children":22557},{},[22558],{"type":281,"tag":459,"props":22559,"children":22560},{},[22561],{"type":291,"value":22562},"I created a subvolumes to exclude fast-growing log directories and temporary folders with cache files that are not required to be backed up.",{"type":281,"tag":459,"props":22564,"children":22565},{},[22566,22568,22573,22575,22580],{"type":291,"value":22567},"You can use the BTRFS ",{"type":281,"tag":11370,"props":22569,"children":22570},{},[22571],{"type":291,"value":22572},"compress",{"type":291,"value":22574}," mount options (like ",{"type":281,"tag":11370,"props":22576,"children":22577},{},[22578],{"type":291,"value":22579},"compress=lzo",{"type":291,"value":22581},") on the source, the destination or both.",{"type":281,"tag":459,"props":22583,"children":22584},{},[22585,22587],{"type":291,"value":22586},"Further informations on incremental backups with BTRFS can be found in the official kernel wiki, ",{"type":281,"tag":286,"props":22588,"children":22590},{"href":22589},"https://btrfs.wiki.kernel.org/index.php/Incremental_Backup",[22591],{"type":291,"value":22589},{"type":281,"tag":530,"props":22593,"children":22595},{"id":22594},"always-disable-cow-on-database-directories",[22596],{"type":291,"value":22597},"Always disable COW on Database directories!",{"type":281,"tag":282,"props":22599,"children":22600},{},[22601],{"type":291,"value":22602},"This is the most important lesson I have learned in years of BTRFS-Usage: Always disable Copy-On-Write on Database Data directories. BTRFS has a COW feature that is enabled by default even if there is no snapshot or hardlink present. As far as i know, this should avoid data corruption on partly overwritten files in case of power outages. But because this \"feature\" is BTRFS specific and not present in most other filesystems, it can be considered optional. For rootfs and most parts of the filesystem, this does not hurt, because files are rarely modified. All DBMS like Mysql or postgres do not expect a COW feature to be present and are doing COW and transactional writes by their own.",{"type":281,"tag":282,"props":22604,"children":22605},{},[22606],{"type":291,"value":22607},"There is no point in having FS-level COW for a database directory. Quite the opposite: having BTRFS-COW enabled on a database directory causes massive fragmentation of the filesystem, slows it down and can lead to BTRFS crashes within some months. If you have your Database already running on BTRFS without explicitly disabled COW, DO IT ASAP before things get worse.",{"type":281,"tag":455,"props":22609,"children":22610},{},[22611,22622,22627,22653],{"type":281,"tag":459,"props":22612,"children":22613},{},[22614,22616,22620],{"type":291,"value":22615},"If you are creating a fresh BTRFS for your database, mount it always with the ",{"type":281,"tag":11370,"props":22617,"children":22618},{},[22619],{"type":291,"value":19565},{"type":291,"value":22621}," option BEFORE writing the first file.",{"type":281,"tag":459,"props":22623,"children":22624},{},[22625],{"type":291,"value":22626},"COW is enabled/disabled on file creation time. if you have created files with COW and mount the filesystem with nodatacow later, the old files are still COW enabled. You need to copy them to actually disable COW.",{"type":281,"tag":459,"props":22628,"children":22629},{},[22630,22632,22637,22639,22644,22646,22651],{"type":291,"value":22631},"There is a no-COW flag you can set on directories by using ",{"type":281,"tag":11370,"props":22633,"children":22634},{},[22635],{"type":291,"value":22636},"chattr +C /path",{"type":291,"value":22638},". Setting ",{"type":281,"tag":11370,"props":22640,"children":22641},{},[22642],{"type":291,"value":22643},"+C",{"type":291,"value":22645}," on a directory causes all child folders/files to be no-COW. You can check this using ",{"type":281,"tag":11370,"props":22647,"children":22648},{},[22649],{"type":291,"value":22650},"lsattr",{"type":291,"value":22652}," command.",{"type":281,"tag":459,"props":22654,"children":22655},{},[22656],{"type":291,"value":22657},"If you already have your database with COW, you can disable it like this (i.e. for MySQL):",{"type":281,"tag":301,"props":22659,"children":22661},{"className":18404,"code":22660,"language":18406,"meta":8,"style":8},"/etc/init.d/mysql stop # make sure your database is stopped!\nmv /var/lib/mysql /var/lib/mysql_old\nmkdir /var/lib/mysql\nchattr +C /var/lib/mysql\ncp -a /var/lib/mysql_old/* /var/lib/mysql\nrm -rf /var/lib/mysql_old\nchown -R mysql:mysql /var/lib/mysql\n/etc/init.d/mysql start #start db again\n",[22662],{"type":281,"tag":315,"props":22663,"children":22664},{"__ignoreMap":8},[22665,22683,22701,22714,22731,22758,22775,22797],{"type":281,"tag":319,"props":22666,"children":22667},{"class":321,"line":322},[22668,22673,22678],{"type":281,"tag":319,"props":22669,"children":22670},{"style":1607},[22671],{"type":291,"value":22672},"/etc/init.d/mysql",{"type":281,"tag":319,"props":22674,"children":22675},{"style":365},[22676],{"type":291,"value":22677}," stop",{"type":281,"tag":319,"props":22679,"children":22680},{"style":9468},[22681],{"type":291,"value":22682}," # make sure your database is stopped!\n",{"type":281,"tag":319,"props":22684,"children":22685},{"class":321,"line":338},[22686,22691,22696],{"type":281,"tag":319,"props":22687,"children":22688},{"style":1607},[22689],{"type":291,"value":22690},"mv",{"type":281,"tag":319,"props":22692,"children":22693},{"style":365},[22694],{"type":291,"value":22695}," /var/lib/mysql",{"type":281,"tag":319,"props":22697,"children":22698},{"style":365},[22699],{"type":291,"value":22700}," /var/lib/mysql_old\n",{"type":281,"tag":319,"props":22702,"children":22703},{"class":321,"line":351},[22704,22709],{"type":281,"tag":319,"props":22705,"children":22706},{"style":1607},[22707],{"type":291,"value":22708},"mkdir",{"type":281,"tag":319,"props":22710,"children":22711},{"style":365},[22712],{"type":291,"value":22713}," /var/lib/mysql\n",{"type":281,"tag":319,"props":22715,"children":22716},{"class":321,"line":371},[22717,22722,22727],{"type":281,"tag":319,"props":22718,"children":22719},{"style":1607},[22720],{"type":291,"value":22721},"chattr",{"type":281,"tag":319,"props":22723,"children":22724},{"style":365},[22725],{"type":291,"value":22726}," +C",{"type":281,"tag":319,"props":22728,"children":22729},{"style":365},[22730],{"type":291,"value":22713},{"type":281,"tag":319,"props":22732,"children":22733},{"class":321,"line":306},[22734,22739,22744,22749,22754],{"type":281,"tag":319,"props":22735,"children":22736},{"style":1607},[22737],{"type":291,"value":22738},"cp",{"type":281,"tag":319,"props":22740,"children":22741},{"style":1622},[22742],{"type":291,"value":22743}," -a",{"type":281,"tag":319,"props":22745,"children":22746},{"style":365},[22747],{"type":291,"value":22748}," /var/lib/mysql_old/",{"type":281,"tag":319,"props":22750,"children":22751},{"style":19014},[22752],{"type":291,"value":22753},"*",{"type":281,"tag":319,"props":22755,"children":22756},{"style":365},[22757],{"type":291,"value":22713},{"type":281,"tag":319,"props":22759,"children":22760},{"class":321,"line":307},[22761,22766,22771],{"type":281,"tag":319,"props":22762,"children":22763},{"style":1607},[22764],{"type":291,"value":22765},"rm",{"type":281,"tag":319,"props":22767,"children":22768},{"style":1622},[22769],{"type":291,"value":22770}," -rf",{"type":281,"tag":319,"props":22772,"children":22773},{"style":365},[22774],{"type":291,"value":22700},{"type":281,"tag":319,"props":22776,"children":22777},{"class":321,"line":308},[22778,22783,22788,22793],{"type":281,"tag":319,"props":22779,"children":22780},{"style":1607},[22781],{"type":291,"value":22782},"chown",{"type":281,"tag":319,"props":22784,"children":22785},{"style":1622},[22786],{"type":291,"value":22787}," -R",{"type":281,"tag":319,"props":22789,"children":22790},{"style":365},[22791],{"type":291,"value":22792}," mysql:mysql",{"type":281,"tag":319,"props":22794,"children":22795},{"style":365},[22796],{"type":291,"value":22713},{"type":281,"tag":319,"props":22798,"children":22799},{"class":321,"line":309},[22800,22804,22809],{"type":281,"tag":319,"props":22801,"children":22802},{"style":1607},[22803],{"type":291,"value":22672},{"type":281,"tag":319,"props":22805,"children":22806},{"style":365},[22807],{"type":291,"value":22808}," start",{"type":281,"tag":319,"props":22810,"children":22811},{"style":9468},[22812],{"type":291,"value":22813}," #start db again\n",{"type":281,"tag":455,"props":22815,"children":22816},{},[22817],{"type":281,"tag":459,"props":22818,"children":22819},{},[22820,22822],{"type":291,"value":22821},"Note that if your database is large and has already a lot of fragmentation, the copy process can take very (in some cases very very) long. You may test how long the copy takes before you shutdown the database on a production system.\n",{"type":281,"tag":455,"props":22823,"children":22824},{},[22825],{"type":281,"tag":459,"props":22826,"children":22827},{},[22828],{"type":291,"value":22829},"If you want to speed up the copy process, you can use btrfs filesystem defrag -v -r -f /var/lib/mysql/ while your database is running.",{"type":281,"tag":530,"props":22831,"children":22833},{"id":22832},"btrfs-sxbackup-as-backup-manager",[22834],{"type":291,"value":22835},"BTRFS-SxBackup as Backup Manager",{"type":281,"tag":282,"props":22837,"children":22838},{},[22839],{"type":291,"value":22840},"BTRFS-SxBackup is simple python CLI Appliation which makes it very easy to create, transfer and manage BTRFS snapshots. I highly recommend it, as its easy to use. After setting it up, you can run it with a cronjob.",{"type":281,"tag":455,"props":22842,"children":22843},{},[22844,22886],{"type":281,"tag":459,"props":22845,"children":22846},{},[22847,22849,22854,22856],{"type":291,"value":22848},"install BTRFS-SxBackup from ",{"type":281,"tag":286,"props":22850,"children":22852},{"href":22851},"https://github.com/masc3d/btrfs-sxbackup",[22853],{"type":291,"value":22851},{"type":291,"value":22855}," on the backup server. With btrfs-sxbackup on the destination, the backup will be “pulled” and centrally managed by the backup server (the client only requires to have ssh running). You also can setup btrfs-sxbackup on the source system and do a “push” backup if you want, both is supported.\n",{"type":281,"tag":455,"props":22857,"children":22858},{},[22859,22871,22876,22881],{"type":281,"tag":459,"props":22860,"children":22861},{},[22862,22864,22869],{"type":291,"value":22863},"on the destination (Backup) server, ",{"type":281,"tag":11280,"props":22865,"children":22866},{},[22867],{"type":291,"value":22868},"i strongly recommend to use LVM and create one BTRFS volume for every backup task.",{"type":291,"value":22870},"  Do not make the volumes too large, you can easily extend them if one needs more space. In the past, we had the problem that storing and managing a lot of snapshots in one btrfs destination volume can cause bugs that render one filesystem unwriteable. Creating one btrfs volume per backup job makes BTRFS faster and safer – and in case of BTRFS problems, only one backup is affected. (and you have space left to create a fresh BTRFS and continue backups there). After doing it this way on the backup server, all the trouble we previously had with a single btrfs-backup-fs went away.",{"type":281,"tag":459,"props":22872,"children":22873},{},[22874],{"type":291,"value":22875},"create a ssh key for root on the backup server and add it to the authorized_keys file on the source. also for the root user. btrfs-sxbackup requires to create, transfer and delete snapshots and only root can do that.",{"type":281,"tag":459,"props":22877,"children":22878},{},[22879],{"type":291,"value":22880},"You have to use the btrfs-sxbackup init and run commands to setup and start the backup process. see the BTRFS-SxBackup git readme for more information. you can also turn on transfer compression",{"type":281,"tag":459,"props":22882,"children":22883},{},[22884],{"type":291,"value":22885},"BTRFS-SxBackup has a retention feature; i.e. if you do a database backup every hour, you can keep the latest two on the source, and configure rules like “after two weeks, keep only 4 backup per day”",{"type":281,"tag":459,"props":22887,"children":22888},{},[22889,22891],{"type":291,"value":22890},"Restore: if you are using btrfs for (root) filesystem backups, you can directly read the plain files from the backup servers filesystem. if you require a full restore, you can use btrfs send and btrfs receive commands to restore your backup.\n",{"type":281,"tag":455,"props":22892,"children":22893},{},[22894],{"type":281,"tag":459,"props":22895,"children":22896},{},[22897,22899],{"type":291,"value":22898},"you can also boot your backup server into a snapshot by using the subvol= kernel option. See also ",{"type":281,"tag":286,"props":22900,"children":22902},{"href":22901},"https://wiki.archlinux.org/index.php/Btrfs#Mounting_subvolumes",[22903],{"type":291,"value":1651},{"type":281,"tag":530,"props":22905,"children":22907},{"id":22906},"tipps-on-restoring-a-mysqlmariadb-database-snapshot",[22908],{"type":291,"value":22909},"Tipps on Restoring a MySql/MariaDB Database Snapshot",{"type":281,"tag":282,"props":22911,"children":22912},{},[22913],{"type":291,"value":22914},"if you are using BTRFS for MySQL backups, you most likely want to investigate the data from your MySQL tables or restore a single table or database.",{"type":281,"tag":455,"props":22916,"children":22917},{},[22918,22923,22934,22939,22952,22957],{"type":281,"tag":459,"props":22919,"children":22920},{},[22921],{"type":291,"value":22922},"In this case, install the same major MySQL/MariaDB version as you have on the source system.",{"type":281,"tag":459,"props":22924,"children":22925},{},[22926,22928],{"type":291,"value":22927},"The snapshots on the backup server are read-only, mysql will be unable to start on a read-only filesystem. to resolve that, create a new snapshot of the read-only snapshot, which will be writeable by default: ",{"type":281,"tag":315,"props":22929,"children":22931},{"className":22930},[],[22932],{"type":291,"value":22933},"btrfs sub snap sx-\u003Cbackupname> \u003Crestorename>",{"type":281,"tag":459,"props":22935,"children":22936},{},[22937],{"type":291,"value":22938},"In case the source system has a different user id for mysql than the backup system, so you have to do a chown -R mysql:mysql on the writeable volume.",{"type":281,"tag":459,"props":22940,"children":22941},{},[22942,22944,22950],{"type":291,"value":22943},"Configure the my.cnf data dir to point to the restore volume and start up mysql. watch the ",{"type":281,"tag":315,"props":22945,"children":22947},{"className":22946},[],[22948],{"type":291,"value":22949},"\u003Chostname>.err",{"type":291,"value":22951}," logfile within the restore volume for startup process. You do not need to copy the live MySQL configuration, just make sure the most important options are set correctly.",{"type":281,"tag":459,"props":22953,"children":22954},{},[22955],{"type":291,"value":22956},"After the startup/recovery completed successfully, you can login with your production user/passwords on the backup instance, inspect data and use mysqldump to transfer tables back to the production system. you can also use btrfs send/receive to transfer the complete snapshot back to the source in case if a disaster recovery is needet.",{"type":281,"tag":459,"props":22958,"children":22959},{},[22960],{"type":291,"value":22961},"If you have a backup instance running, its a fully functional and writeable snapshot of the production data, which can be also used for testing before deployment.",{"type":281,"tag":530,"props":22963,"children":22965},{"id":22964},"known-problems-and-solutions",[22966],{"type":291,"value":22967},"Known Problems and Solutions",{"type":281,"tag":282,"props":22969,"children":22970},{},[22971],{"type":291,"value":22972},"Help! I get \"no space left on device\", but I have plenty of free space left!",{"type":281,"tag":282,"props":22974,"children":22975},{},[22976,22978,22983,22985,22989],{"type":291,"value":22977},"This is a common problem with BTRFS. It took me some time to get an idea what's going wrong there. My explanation on this is that BTRFS has data and metadata blocks allocated on the physical device. Sometimes it happens that all free space is allocated by almost-empty data blocks. When writing new data, BTRFS comes to the point where the new Metadata does not fit within the existing blocks and BTRFS needs to allocate a new metadata block. Because all free space is already claimed by partly or fully empty data blocks, there is no space left to allocate a new metadata block. This gives you \"no space left on device\", not because your data does not fit, but BTRFS is unable to acquire space for the metadata.\nThe solution is to issue a ",{"type":281,"tag":11370,"props":22979,"children":22980},{},[22981],{"type":291,"value":22982},"btrfs balance start /path -dusage=x",{"type":291,"value":22984},". The balance command searches for blocks that have only x% or less of there space occupied, moves their data to other blocks and deletes them afterward, freeing up space for new block allocations. You can start with 5 or 10% and can go up to (or just below) the occupied percentage that is displayed by ",{"type":281,"tag":11370,"props":22986,"children":22987},{},[22988],{"type":291,"value":19386},{"type":291,"value":564},{"type":281,"tag":282,"props":22991,"children":22992},{},[22993,22995,23000],{"type":291,"value":22994},"I have read in the BTRFS docs that BTRFS balances itself when needed. I cannot confirm this, so on important production systems, I set up a daily cronjob with BTRFS balance start ",{"type":281,"tag":11370,"props":22996,"children":22997},{},[22998],{"type":291,"value":22999},"-dusage=20",{"type":291,"value":23001}," to make sure I do not run into problems. Maybe this is fixed or will be fixed in the next BTRFS versions, but I'm not rolling a die on that.",{"type":281,"tag":530,"props":23003,"children":23005},{"id":23004},"i-also-get-no-space-left-on-device-when-i-run-btrfs-balance",[23006,23008],{"type":291,"value":23007},"I also get \"no space left on device\" when i run ",{"type":281,"tag":11370,"props":23009,"children":23010},{},[23011],{"type":291,"value":23012},"btrfs balance",{"type":281,"tag":282,"props":23014,"children":23015},{},[23016,23018,23023,23025,23030],{"type":291,"value":23017},"BTRFS needs some disk space to free up disk space, yes. first, try ",{"type":281,"tag":11370,"props":23019,"children":23020},{},[23021],{"type":291,"value":23022},"-musage",{"type":291,"value":23024}," instead of ",{"type":281,"tag":11370,"props":23026,"children":23027},{},[23028],{"type":291,"value":23029},"-dusage",{"type":291,"value":23031}," and see if this resolves the problem. You can also try to delete some files, but this can also lead to \"no space left on device\" errors.",{"type":281,"tag":282,"props":23033,"children":23034},{},[23035,23037,23041,23043,23048,23050,23054,23056,23061,23063,23068],{"type":291,"value":23036},"The final solution to this is to temporarily add a new block device to the full filesystem, so it can be balanced. You can do so by the ",{"type":281,"tag":11370,"props":23038,"children":23039},{},[23040],{"type":291,"value":22282},{"type":291,"value":23042}," drive add command. If you do not have a spare partition to add, you can also write a file to other filesystems including a ram-only TMPFS using ",{"type":281,"tag":11370,"props":23044,"children":23045},{},[23046],{"type":291,"value":23047},"dd",{"type":291,"value":23049},", then make a block device using ",{"type":281,"tag":11370,"props":23051,"children":23052},{},[23053],{"type":291,"value":22540},{"type":291,"value":23055}," and add it to BTRFS. A size of 2-5GB works most of the time. Start balancing with ",{"type":281,"tag":11370,"props":23057,"children":23058},{},[23059],{"type":291,"value":23060},"-dusage=0",{"type":291,"value":23062}," and increment slowly until some blocks are relocated. After some relocations you can remove the added device with ",{"type":281,"tag":11370,"props":23064,"children":23065},{},[23066],{"type":291,"value":23067},"btrfs drive remove",{"type":291,"value":22652},{"type":281,"tag":282,"props":23070,"children":23071},{},[23072,23074,23079,23080,23085],{"type":291,"value":23073},"Attention: if you add a TMPFS file to your BTRFS filesystem, knock on the wood that there will be no power outage or kernel crash, or you will damage your filesystem. Using a TMPFS is a last-resort solution. Better add a USB storage or a network storage using ",{"type":281,"tag":11370,"props":23075,"children":23076},{},[23077],{"type":291,"value":23078},"nfs",{"type":291,"value":10825},{"type":281,"tag":11370,"props":23081,"children":23082},{},[23083],{"type":291,"value":23084},"sshfs",{"type":291,"value":23086}," if possible.",{"type":281,"tag":1477,"props":23088,"children":23089},{},[23090],{"type":291,"value":1481},{"title":8,"searchDepth":338,"depth":338,"links":23092},[23093,23094,23095,23096,23097,23098,23099,23100,23101,23102],{"id":22271,"depth":338,"text":22274},{"id":22310,"depth":338,"text":22313},{"id":22360,"depth":338,"text":22363},{"id":22498,"depth":338,"text":22501},{"id":22509,"depth":338,"text":22512},{"id":22594,"depth":338,"text":22597},{"id":22832,"depth":338,"text":22835},{"id":22906,"depth":338,"text":22909},{"id":22964,"depth":338,"text":22967},{"id":23004,"depth":338,"text":23103},"I also get \"no space left on device\" when i run btrfs balance",{"_path":249,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":250,"description":251,"image":252,"author":224,"releaseDate":253,"blogCategories":23105,"articleTags":23106,"tags":23107,"body":23108,"_type":20,"_id":257,"_source":22,"_file":258,"_stem":259,"_extension":25},[15,242],[203],[231,19],{"type":278,"children":23109,"toc":23140},[23110,23116],{"type":281,"tag":530,"props":23111,"children":23113},{"id":23112},"find-what-you-need-to-know",[23114],{"type":291,"value":23115},"Find what you need to know",{"type":281,"tag":282,"props":23117,"children":23118},{},[23119,23121,23127,23129,23134],{"type":291,"value":23120},"As the Basho RIAK KV TS CS documentation is unreachable at the moment,\n",{"type":281,"tag":1499,"props":23122,"children":23126},{"alt":23123,"aspect-ratio":22283,"height":23124,"object-fit":19308,"src":23125},"bashoriak",100,"/blog/bashoriak.png",[],{"type":291,"value":23128},"\nwe have created a mirror:\n",{"type":281,"tag":286,"props":23130,"children":23132},{"href":23131},"https://riak.docs.hw.ag/",[23133],{"type":291,"value":23131},{"type":281,"tag":1499,"props":23135,"children":23139},{"alt":23136,"aspect-ratio":23137,"height":1502,"object-fit":19308,"src":23138},"bashoriak_mirror","1.5","/blog/bashoriak_mirror.png",[],{"title":8,"searchDepth":338,"depth":338,"links":23141},[23142],{"id":23112,"depth":338,"text":23115},{"_path":261,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":262,"description":263,"image":264,"author":136,"releaseDate":265,"blogCategories":23144,"articleTags":23145,"tags":23146,"body":23147,"_type":20,"_id":270,"_source":22,"_file":271,"_stem":272,"_extension":25},[15,267],[267],[144,231],{"type":278,"children":23148,"toc":23241},[23149,23154,23159,23165,23170,23176,23181,23187,23192,23198,23203,23209,23214,23220,23225,23230,23236],{"type":281,"tag":282,"props":23150,"children":23151},{},[23152],{"type":291,"value":23153},"We don't work with arbitrary frameworks, libraries, plugins and programming languages. We like it professional.",{"type":281,"tag":282,"props":23155,"children":23156},{},[23157],{"type":291,"value":23158},"Software created at Helm & Walter should be powerful and lean. Here are our favorites:",{"type":281,"tag":530,"props":23160,"children":23162},{"id":23161},"php",[23163],{"type":291,"value":23164},"PHP",{"type":281,"tag":282,"props":23166,"children":23167},{},[23168],{"type":291,"value":23169},"PHP (recursive acronym for PHP: hypertext preprocessor) is a widely used open source scripting language intended for general use, which is particularly suitable for web programming and can be embedded in HTML.",{"type":281,"tag":530,"props":23171,"children":23173},{"id":23172},"c",[23174],{"type":291,"value":23175},"C++",{"type":281,"tag":282,"props":23177,"children":23178},{},[23179],{"type":291,"value":23180},"C++ is a programming language standardized by the ISO. It was developed from 1979 by Bjarne Stroustrup at AT&T as an extension of the C programming language. C++ enables efficient and machine-oriented programming as well as programming at a high level of abstraction. It is particularly suitable for native desktop and server applications and is characterized by very good performance.",{"type":281,"tag":530,"props":23182,"children":23184},{"id":23183},"java",[23185],{"type":291,"value":23186},"Java",{"type":281,"tag":282,"props":23188,"children":23189},{},[23190],{"type":291,"value":23191},"Java is an object-oriented programming language and a registered trademark of Sun Microsystems, which was acquired by Oracle in 2010. It proves its strength particularly in its platform independence, i.e. it can be used anywhere where a corresponding runtime environment is set up, and is formulated almost completely object-oriented.",{"type":281,"tag":530,"props":23193,"children":23195},{"id":23194},"scala",[23196],{"type":291,"value":23197},"Scala",{"type":281,"tag":282,"props":23199,"children":23200},{},[23201],{"type":291,"value":23202},"Scala is a programming language developed by the École polytechnique fédérale de Lausanne under the direction of Martin Odersky. The name is derived from 'scalable language' and expresses the fact that the very compact language core offers the possibility of implementing frequently used language elements such as operators or additional control structures in user classes, thereby extending the scope of the language. It can work together with the Java programs mentioned above, but unlike Java, it is completely object-oriented. Scala is particularly suitable for the parallel processing of data.",{"type":281,"tag":530,"props":23204,"children":23206},{"id":23205},"zend-framework",[23207],{"type":291,"value":23208},"Zend Framework",{"type":281,"tag":282,"props":23210,"children":23211},{},[23212],{"type":291,"value":23213},"The Zend Framework is a component-oriented web framework for PHP with over 135 million installations, including well-known companies such as the BBC. It enables a simple project structure and works seamlessly with most third-party solutions. It is developed by Zend Technologies and is also platform-independent thanks to its PHP foundation.",{"type":281,"tag":530,"props":23215,"children":23217},{"id":23216},"dhtmlx",[23218],{"type":291,"value":23219},"DHTMLX",{"type":281,"tag":282,"props":23221,"children":23222},{},[23223],{"type":291,"value":23224},"The DHTMLX Suite developed by Dinamenta UAB is a JavaScript-based program library for the development of dynamic web applications with a desktop-like user experience. The modular architecture allows the addition or removal of any high-performance program parts for an optimal use of resources on the client side. In addition, DHTMLX can easily be used both on desktop and in mobile environments on- and offline.",{"type":281,"tag":282,"props":23226,"children":23227},{},[23228],{"type":291,"value":23229},"DHTMLX, as one of the foundations for our Verdandi, has been improved by us with some plugins and other extensions - for example the \"Row-Actions\", which offer a compact and flexible way to perform row-specific tasks.",{"type":281,"tag":530,"props":23231,"children":23233},{"id":23232},"infinidb",[23234],{"type":291,"value":23235},"InfiniDB",{"type":281,"tag":282,"props":23237,"children":23238},{},[23239],{"type":291,"value":23240},"InfiniDB was developed by the company of the same name InfiniDB (formerly Calpont Corporation) as a scalable, column-based database management system for analytical applications. It specializes in big data analysis, business intelligence, data warehousing and other read-intensive applications. The column-store architecture used enables extremely fast loading and query execution times.",{"title":8,"searchDepth":338,"depth":338,"links":23242},[23243,23244,23245,23246,23247,23248,23249],{"id":23161,"depth":338,"text":23164},{"id":23172,"depth":338,"text":23175},{"id":23183,"depth":338,"text":23186},{"id":23194,"depth":338,"text":23197},{"id":23205,"depth":338,"text":23208},{"id":23216,"depth":338,"text":23219},{"id":23232,"depth":338,"text":23235},{"_path":23251,"_dir":23252,"_draft":7,"_partial":7,"_locale":8,"slug":11,"teams":23253,"primaryTeam":23255,"firstName":20131,"lastName":23256,"prefixTitle":8,"suffixTitle":23257,"education":23258,"role":23263,"workingSince":23268,"inTheCompanySince":23269,"techSkills":23270,"skills":23304,"projects":23320,"contactDetails":23330,"_image":23333,"image":23334,"_id":23335,"_type":5040,"title":23336,"_source":23252,"_file":23337,"_stem":23338,"_extension":5040},"/employees/robert-juzak","employees",[23254,23255],"appDev","devOps","Juzak","B.Sc.",[23259],[23260,23261,23262],"Bachelor of Computer Science","Technische Universität Breslau","2016",[23264,23265,23266,23267],"softwareDeveloper","fullstackDeveloper","admin","consultant","2015","2018",[23271,23274,23275,23278,23281,23284,23285,23288,23290,23294,23297,23298,23301],{"name":9321,"level":23272,"icon":23273},"expert","/images/Docker.svg",{"name":9339,"level":23272},{"name":23276,"level":23272,"icon":23277},"Kubernetes","/images/Kubernetes.svg",{"name":23279,"level":23272,"icon":23280},"PHPUnit","/images/PHP-Unit.svg",{"name":23282,"level":23272,"icon":23283},"Portainer","/images/Portainer.svg",{"name":17064,"level":23272},{"name":23286,"level":23272,"icon":23287},"Sonarqube","/images/Sonarqube.svg",{"name":23289,"level":23272,"icon":188},"Linux",{"name":23291,"level":23292,"icon":23293},"CSS","advanced","/images/css.svg",{"name":23295,"level":23292,"icon":23296},"HTML","/images/html.svg",{"name":23164,"level":23292},{"name":23299,"level":23292,"icon":23300},"SQL","/images/SQL.svg",{"name":23302,"level":23292,"icon":23303},"VueJS","/images/vuejs.svg",[23305,23306,23308,23309,23311,23313,23315,23316,23318],{"name":1578,"level":23272},{"name":23307,"level":23272},"qualityAssurance",{"name":23255,"level":23272},{"name":23310,"level":23272},"testDrivenBugfix",{"name":23312,"level":23272},"testDrivenDevelopment",{"name":23314,"level":23292},"accessibility",{"name":231,"level":23292},{"name":23317,"level":23292},"linuxServerAdministration",{"name":23319,"level":23292},"softwareArchitect",[23321,23326,23328],{"project":23322,"position":23323},"Herole",[23324,23325],"Dev-Ops","Frontend Developer",{"project":23327,"position":23325},"Huawei-Calibration-aaS",{"project":23329,"position":23325},"Huawei-Inspect-3D",{"eMail":23331,"phone":23332,"visibility":18534},"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":23340,"_dir":23252,"_draft":7,"_partial":7,"_locale":8,"slug":86,"teams":23341,"primaryTeam":23254,"firstName":23342,"lastName":23343,"prefixTitle":23344,"suffixTitle":8,"executiveRole":23345,"education":23346,"role":23354,"workingSince":23353,"inTheCompanySince":23350,"techSkills":23357,"skills":23378,"projects":23390,"contactDetails":23396,"certifications":23399,"image":23405,"_id":23406,"_type":5040,"title":23407,"_source":23252,"_file":23408,"_stem":23409,"_extension":5040},"/employees/jens-bornschein",[23254],"Jens","Bornschein","Dr. Ing.","Projektmanager | Consultant",[23347,23351],[23348,23349,23350],"Doktor-Ingenieur der Informatik","TU Dresden","2020",[23352,23349,23353],"Diplom-Medieninformatiker (TU)","2010",[23355,23264,23265,23356,23314,23267],"projectManager","UI/UX",[23358,23359,23362,23363,23364,23366,23367,23370,23373,23376],{"name":23164,"level":23272},{"name":23360,"level":23272,"icon":23361},"C#","/images/csharp.svg",{"name":23291,"level":23292,"icon":23293},{"name":23295,"level":23292,"icon":23296},{"name":23365,"level":23292,"icon":23303},"Vue.js",{"name":23186,"level":23292},{"name":23368,"level":23272,"icon":23369},"Adobe Photoshop","/images/adobeps-logo.svg",{"name":23371,"level":23272,"icon":23372},"Adobe Illustrator","/images/adobeai-logo.svg",{"name":23374,"level":23292,"icon":23375},"Adobe XD","/images/adobexd-logo.svg",{"name":23377,"level":23292},"Gitlab",[23379,23381,23382,23383,23385,23387,23388],{"name":23380,"level":23272},"projectManagement",{"name":23314,"level":23272},{"name":23356,"level":23272},{"name":23384,"level":23292},"consulting",{"name":23386,"level":23292},"scrum",{"name":23319,"level":23292},{"name":23389,"level":23292},"training",[23391,23394],{"project":23392,"position":23393},"Montagespezis","project manager",{"project":23395,"position":23393},"Vipr",{"eMail":23397,"phone":23398,"visibility":18534},"jens.bornschein@helmundwalter.de","+49 351 799 035 24",[23400],{"image":23401,"link":23402,"title":23403,"pdf":23404},"/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":23411,"_dir":23252,"_draft":7,"_partial":7,"_locale":8,"slug":136,"teams":23412,"primaryTeam":23255,"firstName":20221,"lastName":23414,"prefixTitle":8,"suffixTitle":8,"education":23415,"executiveRole":23419,"role":23420,"workingSince":23425,"inTheCompanySince":23426,"techSkills":23427,"skills":23453,"projects":23462,"contactDetails":23472,"_image":23475,"image":23476,"_id":23477,"_type":5040,"title":23478,"_source":23252,"_file":23479,"_stem":23480,"_extension":5040},"/employees/bernd-helm",[23413,23255],"ai","Helm",[23416],[23417,23418,23353],"B. Sc. Angewandte Informatik","FHDW Dresden","CTO",[23421,23422,23255,23423,23266,23264,23424,23267],"founder","chiefTechnologyOfficer","databaseSpecialist","backendDeveloper","2005","2008",[23428,23429,23430,23431,23434,23436,23439,23440,23441,23443,23444,23446,23447,23448,23449,23452],{"name":9321,"level":23272,"icon":23273},{"name":23289,"level":23272,"icon":188},{"name":17085,"level":23272},{"name":23432,"level":23272,"icon":23433},"MariaDB ColumnStore","/images/maria-db-logo.svg",{"name":23435,"level":23272},"OpenAI",{"name":23437,"level":23272,"icon":23438},"Pytorch","/images/PyTorch.svg",{"name":23164,"level":23272},{"name":23186,"level":23272},{"name":23442,"level":23272},"Python",{"name":23299,"level":23272,"icon":23300},{"name":23175,"level":23292,"icon":23445},"/images/cpp-logo.svg",{"name":23360,"level":23292,"icon":23361},{"name":23291,"level":23292,"icon":23293},{"name":23295,"level":23292,"icon":23296},{"name":23450,"level":23292,"icon":23451},"OpenCV","/images/OpenCV.svg",{"name":23365,"level":23292,"icon":23303},[23454,23456,23458,23459,23460,23461],{"name":23455,"level":23272},"artificialIntelligence",{"name":23457,"level":23272},"codingGuidelines",{"name":231,"level":23272},{"name":23317,"level":23272},{"name":23319,"level":23272},{"name":23307,"level":23292},[23463,23466,23467,23468,23471],{"project":23464,"position":23465},"Gridside","Technical Consultant",{"project":23322,"position":23465},{"project":23392,"position":23465},{"project":23469,"position":23470},"Orsee","Technical Manager",{"project":23395,"position":23465},{"eMail":23473,"phone":23474,"visibility":18534},"bernd.helm@helmundwalter.de","+49 351 799 035 20","images/employees/Portraits/bernd_helm.webp","images/employees/Portraits/BerndHelm_MS.webp","employees:employees:1.bernd-helm.json","Bernd Helm","employees/1.bernd-helm.json","employees/1.bernd-helm",{"_path":23482,"_dir":23252,"_draft":7,"_partial":7,"_locale":8,"slug":224,"teams":23483,"primaryTeam":36,"firstName":20253,"lastName":23484,"prefixTitle":8,"suffixTitle":8,"education":23485,"executiveRole":23488,"role":23489,"workingSince":23426,"inTheCompanySince":23426,"techSkills":23491,"skills":23498,"projects":23504,"contactDetails":23505,"_image":23508,"image":23509,"_id":23510,"_type":5040,"title":23511,"_source":23252,"_file":23512,"_stem":23513,"_extension":5040},"/employees/daniel-walter",[36,23255],"Walter",[23486],[23417,23487,23353],"FHDW","CEO",[23421,23490,23355,23264,23265,23266,23267],"chiefExecutiveOfficer",[23492,23493,23494,23495],{"name":23175,"level":23272,"icon":23445},{"name":23360,"level":23272,"icon":23361},{"name":23299,"level":23272,"icon":23300},{"name":23496,"level":23292,"icon":23497},"Flutter","/images/Flutter.svg",[23499,23500,23501,23502,23503],{"name":231,"level":23272},{"name":23317,"level":23272},{"name":23380,"level":23272},{"name":36,"level":23272},{"name":23319,"level":23292},[],{"eMail":23506,"phone":23507,"visibility":18534},"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",1782284035631]