[{"data":1,"prerenderedAt":1630},["ShallowReactive",2],{"/blog/how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci":3,"navigation-en-us":844,"banner-en-us":1270,"footer-en-us":1280,"blog-post-authors-en-us-Riccardo Padovani":1525,"blog-related-posts-en-us-how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci":1540,"blog-promotions-en-us":1566,"next-steps-en-us":1620},{"id":4,"title":5,"authors":6,"body":8,"category":807,"date":808,"description":809,"extension":810,"externalUrl":811,"faq":811,"featured":812,"heroImage":813,"meta":814,"navigation":173,"path":831,"seo":832,"slug":836,"stem":837,"tags":838,"template":842,"updatedDate":811,"__hash__":843},"blogPosts/en-us/blog/how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci.md","How to automatically create a new MR on GitLab with GitLab CI",[7],"Riccardo Padovani",{"type":9,"value":10,"toc":800},"minimark",[11,42,45,48,61,70,73,92,97,104,107,110,677,680,687,695,698,705,709,712,715,718,727,731,734,737,750,753,761,764,772,783,788,796],[12,13,14,15,21,22,27,28,32,33,37,38,41],"p",{},"At ",[16,17,20],"a",{"href":18,"rel":19},"https://www.fleetster.net/",[],"fleetster",", we have our own instance of ",[16,23,26],{"href":24,"rel":25},"https://gitlab.com/",[],"GitLab"," and we rely a lot on ",[16,29,31],{"href":30},"/solutions/continuous-integration/","GitLab CI",". How could it be otherwise? We are a small team, with a lot of different projects (only in last month, we had more than ",[34,35,36],"strong",{},"13,000 commits"," over ",[34,39,40],{},"25 different projects",", and we are only 10 people – with myself working part time). Automating as many development steps as possible (from build to QA to deploy) is helping us a lot, but sometimes we write some code and then forget about it. This is a disaster! We have some bug fix or some new feature ready, but it is forgotten in some branch somewhere.",[12,43,44],{},"This is why we have a policy to push as soon as possible to open a new MR, mark it as WIP, and assign to ourselves; in this way GitLab will remind us we have an MR.",[12,46,47],{},"You need to do three steps to achieve that:",[49,50,51,55,58],"ul",{},[52,53,54],"li",{},"Push the code",[52,56,57],{},"Click on the link that appears on your terminal",[52,59,60],{},"Fill a form",[12,62,63,64,69],{},"But we are nerds. We are lazy. So one night, after a couple of beers, ",[16,65,68],{"href":66,"rel":67},"https://www.linkedin.com/in/alberto-urbano-047a4b19/",[],"Alberto Urbano"," and I spent some hours to automate a task that requires 10 seconds.",[12,71,72],{},"Actually, the experience was quite fun, it was the first time we used GitLab APIs and we learned things we will apply to others scripts as well.",[12,74,75,80,83],{},[76,77],"img",{"alt":78,"src":79},"Image via Riccardo's blog","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782397977/blog/Content%20Images/automating-tasks-expectation-versus-reality.png",[81,82],"br",{},[84,85,86,87],"em",{},"Image by Randall Munroe, ",[16,88,91],{"href":89,"rel":90},"https://imgs.xkcd.com/comics/automation.png",[],"xkcd.com",[93,94,96],"h3",{"id":95},"the-script","The script",[12,98,99,100,103],{},"With this script, every time we push a commit, GitLab CI checks if the branch that commit belongs to already has an open MR and, if not, it creates it. It then assigns the MR to you, and puts ",[34,101,102],{},"WIP"," in the title to mark it as a work in progress.",[12,105,106],{},"In this way you cannot forget about that branch, and when you’ve finished writing code on it, you just need to remove the WIP from the title and assign to the right person to review it.",[12,108,109],{},"In the end, this is the script we came out with (when you add to your project, remember to make it executable):",[111,112,117],"pre",{"className":113,"code":114,"language":115,"meta":116,"style":116},"language-bash shiki shiki-themes github-light","#!/usr/bin/env bash\n# Extract the host where the server is running, and add the URL to the APIs\n[[ $HOST =~ ^https?://[^/]+ ]] && HOST=\"${BASH_REMATCH[0]}/api/v4/projects/\"\n\n# Look which is the default branch\nTARGET_BRANCH=`curl --silent \"${HOST}${CI_PROJECT_ID}\" --header \"PRIVATE-TOKEN:${PRIVATE_TOKEN}\" | python3 -c \"import sys, json; print(json.load(sys.stdin)['default_branch'])\"`;\n\n# The description of our new MR, we want to remove the branch after the MR has\n# been closed\nBODY=\"{\n    \\\"id\\\": ${CI_PROJECT_ID},\n    \\\"source_branch\\\": \\\"${CI_COMMIT_REF_NAME}\\\",\n    \\\"target_branch\\\": \\\"${TARGET_BRANCH}\\\",\n    \\\"remove_source_branch\\\": true,\n    \\\"title\\\": \\\"WIP: ${CI_COMMIT_REF_NAME}\\\",\n    \\\"assignee_id\\\":\\\"${GITLAB_USER_ID}\\\"\n}\";\n\n# Require a list of all the merge request and take a look if there is already\n# one with the same source branch\nLISTMR=`curl --silent \"${HOST}${CI_PROJECT_ID}/merge_requests?state=opened\" --header \"PRIVATE-TOKEN:${PRIVATE_TOKEN}\"`;\nCOUNTBRANCHES=`echo ${LISTMR} | grep -o \"\\\"source_branch\\\":\\\"${CI_COMMIT_REF_NAME}\\\"\" | wc -l`;\n\n# No MR found, let's create a new one\nif [ ${COUNTBRANCHES} -eq \"0\" ]; then\n    curl -X POST \"${HOST}${CI_PROJECT_ID}/merge_requests\" \\\n        --header \"PRIVATE-TOKEN:${PRIVATE_TOKEN}\" \\\n        --header \"Content-Type: application/json\" \\\n        --data \"${BODY}\";\n\n    echo \"Opened a new merge request: WIP: ${CI_COMMIT_REF_NAME} and assigned to you\";\n    exit;\nfi\n\necho \"No new merge request opened\";\n","bash","",[118,119,120,129,135,168,175,181,241,246,252,258,269,289,318,342,355,380,405,413,418,424,430,466,531,536,542,563,589,603,613,627,632,648,656,662,667],"code",{"__ignoreMap":116},[121,122,125],"span",{"class":123,"line":124},"line",1,[121,126,128],{"class":127},"sAwPA","#!/usr/bin/env bash\n",[121,130,132],{"class":123,"line":131},2,[121,133,134],{"class":127},"# Extract the host where the server is running, and add the URL to the APIs\n",[121,136,138,142,146,149,152,155,158,162,165],{"class":123,"line":137},3,[121,139,141],{"class":140},"sgsFI","[[ $HOST ",[121,143,145],{"class":144},"sD7c4","=~",[121,147,148],{"class":140}," ^https",[121,150,151],{"class":144},"?",[121,153,154],{"class":140},"://[^/]+ ]] && HOST",[121,156,157],{"class":144},"=",[121,159,161],{"class":160},"sYBdl","\"${",[121,163,164],{"class":140},"BASH_REMATCH",[121,166,167],{"class":160},"[0]}/api/v4/projects/\"\n",[121,169,171],{"class":123,"line":170},4,[121,172,174],{"emptyLinePlaceholder":173},true,"\n",[121,176,178],{"class":123,"line":177},5,[121,179,180],{"class":127},"# Look which is the default branch\n",[121,182,184,187,189,192,196,200,203,206,209,212,215,218,221,224,226,229,232,235,238],{"class":123,"line":183},6,[121,185,186],{"class":140},"TARGET_BRANCH",[121,188,157],{"class":144},[121,190,191],{"class":160},"`",[121,193,195],{"class":194},"s7eDp","curl",[121,197,199],{"class":198},"sYu0t"," --silent",[121,201,202],{"class":160}," \"${",[121,204,205],{"class":140},"HOST",[121,207,208],{"class":160},"}${",[121,210,211],{"class":140},"CI_PROJECT_ID",[121,213,214],{"class":160},"}\" ",[121,216,217],{"class":198},"--header",[121,219,220],{"class":160}," \"PRIVATE-TOKEN:${",[121,222,223],{"class":140},"PRIVATE_TOKEN",[121,225,214],{"class":160},[121,227,228],{"class":144},"|",[121,230,231],{"class":194}," python3",[121,233,234],{"class":198}," -c",[121,236,237],{"class":160}," \"import sys, json; print(json.load(sys.stdin)['default_branch'])\"`",[121,239,240],{"class":140},";\n",[121,242,244],{"class":123,"line":243},7,[121,245,174],{"emptyLinePlaceholder":173},[121,247,249],{"class":123,"line":248},8,[121,250,251],{"class":127},"# The description of our new MR, we want to remove the branch after the MR has\n",[121,253,255],{"class":123,"line":254},9,[121,256,257],{"class":127},"# been closed\n",[121,259,261,264,266],{"class":123,"line":260},10,[121,262,263],{"class":140},"BODY",[121,265,157],{"class":144},[121,267,268],{"class":160},"\"{\n",[121,270,272,275,278,281,284,286],{"class":123,"line":271},11,[121,273,274],{"class":198},"    \\\"",[121,276,277],{"class":160},"id",[121,279,280],{"class":198},"\\\"",[121,282,283],{"class":160},": ${",[121,285,211],{"class":140},[121,287,288],{"class":160},"},\n",[121,290,292,294,297,299,302,304,307,310,313,315],{"class":123,"line":291},12,[121,293,274],{"class":198},[121,295,296],{"class":160},"source_branch",[121,298,280],{"class":198},[121,300,301],{"class":160},": ",[121,303,280],{"class":198},[121,305,306],{"class":160},"${",[121,308,309],{"class":140},"CI_COMMIT_REF_NAME",[121,311,312],{"class":160},"}",[121,314,280],{"class":198},[121,316,317],{"class":160},",\n",[121,319,321,323,326,328,330,332,334,336,338,340],{"class":123,"line":320},13,[121,322,274],{"class":198},[121,324,325],{"class":160},"target_branch",[121,327,280],{"class":198},[121,329,301],{"class":160},[121,331,280],{"class":198},[121,333,306],{"class":160},[121,335,186],{"class":140},[121,337,312],{"class":160},[121,339,280],{"class":198},[121,341,317],{"class":160},[121,343,345,347,350,352],{"class":123,"line":344},14,[121,346,274],{"class":198},[121,348,349],{"class":160},"remove_source_branch",[121,351,280],{"class":198},[121,353,354],{"class":160},": true,\n",[121,356,358,360,363,365,367,369,372,374,376,378],{"class":123,"line":357},15,[121,359,274],{"class":198},[121,361,362],{"class":160},"title",[121,364,280],{"class":198},[121,366,301],{"class":160},[121,368,280],{"class":198},[121,370,371],{"class":160},"WIP: ${",[121,373,309],{"class":140},[121,375,312],{"class":160},[121,377,280],{"class":198},[121,379,317],{"class":160},[121,381,383,385,388,390,393,395,397,400,402],{"class":123,"line":382},16,[121,384,274],{"class":198},[121,386,387],{"class":160},"assignee_id",[121,389,280],{"class":198},[121,391,392],{"class":160},":",[121,394,280],{"class":198},[121,396,306],{"class":160},[121,398,399],{"class":140},"GITLAB_USER_ID",[121,401,312],{"class":160},[121,403,404],{"class":198},"\\\"\n",[121,406,408,411],{"class":123,"line":407},17,[121,409,410],{"class":160},"}\"",[121,412,240],{"class":140},[121,414,416],{"class":123,"line":415},18,[121,417,174],{"emptyLinePlaceholder":173},[121,419,421],{"class":123,"line":420},19,[121,422,423],{"class":127},"# Require a list of all the merge request and take a look if there is already\n",[121,425,427],{"class":123,"line":426},20,[121,428,429],{"class":127},"# one with the same source branch\n",[121,431,433,436,438,440,442,444,446,448,450,452,455,457,459,461,464],{"class":123,"line":432},21,[121,434,435],{"class":140},"LISTMR",[121,437,157],{"class":144},[121,439,191],{"class":160},[121,441,195],{"class":194},[121,443,199],{"class":198},[121,445,202],{"class":160},[121,447,205],{"class":140},[121,449,208],{"class":160},[121,451,211],{"class":140},[121,453,454],{"class":160},"}/merge_requests?state=opened\" ",[121,456,217],{"class":198},[121,458,220],{"class":160},[121,460,223],{"class":140},[121,462,463],{"class":160},"}\"`",[121,465,240],{"class":140},[121,467,469,472,474,476,479,482,484,487,489,492,495,498,500,502,504,506,508,510,512,514,516,519,521,524,527,529],{"class":123,"line":468},22,[121,470,471],{"class":140},"COUNTBRANCHES",[121,473,157],{"class":144},[121,475,191],{"class":160},[121,477,478],{"class":198},"echo",[121,480,481],{"class":160}," ${",[121,483,435],{"class":140},[121,485,486],{"class":160},"} ",[121,488,228],{"class":144},[121,490,491],{"class":194}," grep",[121,493,494],{"class":198}," -o",[121,496,497],{"class":160}," \"",[121,499,280],{"class":198},[121,501,296],{"class":160},[121,503,280],{"class":198},[121,505,392],{"class":160},[121,507,280],{"class":198},[121,509,306],{"class":160},[121,511,309],{"class":140},[121,513,312],{"class":160},[121,515,280],{"class":198},[121,517,518],{"class":160},"\" ",[121,520,228],{"class":144},[121,522,523],{"class":194}," wc",[121,525,526],{"class":198}," -l",[121,528,191],{"class":160},[121,530,240],{"class":140},[121,532,534],{"class":123,"line":533},23,[121,535,174],{"emptyLinePlaceholder":173},[121,537,539],{"class":123,"line":538},24,[121,540,541],{"class":127},"# No MR found, let's create a new one\n",[121,543,545,548,551,554,557,560],{"class":123,"line":544},25,[121,546,547],{"class":144},"if",[121,549,550],{"class":140}," [ ${COUNTBRANCHES} ",[121,552,553],{"class":144},"-eq",[121,555,556],{"class":160}," \"0\"",[121,558,559],{"class":140}," ]; ",[121,561,562],{"class":144},"then\n",[121,564,566,569,572,575,577,579,581,583,586],{"class":123,"line":565},26,[121,567,568],{"class":194},"    curl",[121,570,571],{"class":198}," -X",[121,573,574],{"class":160}," POST",[121,576,202],{"class":160},[121,578,205],{"class":140},[121,580,208],{"class":160},[121,582,211],{"class":140},[121,584,585],{"class":160},"}/merge_requests\"",[121,587,588],{"class":198}," \\\n",[121,590,592,595,597,599,601],{"class":123,"line":591},27,[121,593,594],{"class":198},"        --header",[121,596,220],{"class":160},[121,598,223],{"class":140},[121,600,410],{"class":160},[121,602,588],{"class":198},[121,604,606,608,611],{"class":123,"line":605},28,[121,607,594],{"class":198},[121,609,610],{"class":160}," \"Content-Type: application/json\"",[121,612,588],{"class":198},[121,614,616,619,621,623,625],{"class":123,"line":615},29,[121,617,618],{"class":198},"        --data",[121,620,202],{"class":160},[121,622,263],{"class":140},[121,624,410],{"class":160},[121,626,240],{"class":140},[121,628,630],{"class":123,"line":629},30,[121,631,174],{"emptyLinePlaceholder":173},[121,633,635,638,641,643,646],{"class":123,"line":634},31,[121,636,637],{"class":198},"    echo",[121,639,640],{"class":160}," \"Opened a new merge request: WIP: ${",[121,642,309],{"class":140},[121,644,645],{"class":160},"} and assigned to you\"",[121,647,240],{"class":140},[121,649,651,654],{"class":123,"line":650},32,[121,652,653],{"class":198},"    exit",[121,655,240],{"class":140},[121,657,659],{"class":123,"line":658},33,[121,660,661],{"class":144},"fi\n",[121,663,665],{"class":123,"line":664},34,[121,666,174],{"emptyLinePlaceholder":173},[121,668,670,672,675],{"class":123,"line":669},35,[121,671,478],{"class":198},[121,673,674],{"class":160}," \"No new merge request opened\"",[121,676,240],{"class":140},[93,678,31],{"id":679},"gitlab-ci",[12,681,682,683,686],{},"The variables used in the script are passed to it by our ",[118,684,685],{},".gitlab_ci.yml"," file:",[111,688,693],{"className":689,"code":691,"language":692,"meta":116},[690],"language-text","stages:\n    - openMr\n    - otherStages\n\nopenMr:\n    before_script: []   # We do not need any setup work, let's remove the global one (if any)\n    stage: openMr\n    only:\n      - /^feature\\/*/   # We have a very strict naming convention\n    script:\n        - HOST=${CI_PROJECT_URL} CI_PROJECT_ID=${CI_PROJECT_ID} CI_COMMIT_REF_NAME=${CI_COMMIT_REF_NAME} GITLAB_USER_ID=${GITLAB_USER_ID} PRIVATE_TOKEN=${PRIVATE_TOKEN} ./utils/autoMergeRequest.sh # The name of the script\n\n","text",[118,694,691],{"__ignoreMap":116},[12,696,697],{},"All these environment variables are set by GitLab itself, but the PRIVATE-TOKEN. A master of the project has to create it in its own profile and add to the project settings.",[12,699,700,701,704],{},"To create the personal token you can go to ",[118,702,703],{},"/profile/personal_access_tokens"," on your GitLab instance, and then you add to your pipeline following this guide.",[93,706,708],{"id":707},"ways-to-improve","Ways to improve",[12,710,711],{},"The script is far from perfect.",[12,713,714],{},"First of all, it has two API calls, one to take the list of MR and one to take the default branch, to use it as target. Of course you can hardcode the value (in the end it shouldn’t change often), but hardcoding is always bad.",[12,716,717],{},"Also, it uses python3 to extract the name of the target branch – this is just one of many possible solutions, just use what is available on your system. Apart from that, the script doesn’t have any external dependency.",[12,719,720,721,726],{},"The other thing is how you need to set up the secret token to call the APIs. Luckily, GitLab’s developers are working on a ",[16,722,725],{"href":723,"rel":724},"https://gitlab.com/gitlab-org/gitlab-ce/issues/12729",[],"new way"," to manage secret tokens.",[93,728,730],{"id":729},"conclusion","Conclusion",[12,732,733],{},"This was a very small and very simple example about how much powerful Continuous Integration can be. It takes some time to set up everything, but in the long run it will save your team a lot of headache.",[12,735,736],{},"In fleetster we use it not only for running tests, but also for having automatic versioning of the software and automatic deploys to testing environments. We are working to automate other jobs as well (building apps and publish them on the Play Store and so on).",[12,738,739,740,743,744,749],{},"Speaking of which, ",[34,741,742],{},"do you want to work in a young and dynamic office with me and a lot of other amazing people?"," Take a look at the ",[16,745,748],{"href":746,"rel":747},"https://www.fleetster.net/fleetster-team.html",[],"open positions at fleetster","!",[12,751,752],{},"Kudos to the GitLab team (and other guys who help in their free time) for their awesome work!",[12,754,755,756,760],{},"If you have any question or feedback about this blog post, please drop me an email at ",[16,757,759],{"href":758},"mailto:riccardo@rpadovani.com","riccardo@rpadovani.com"," :-)",[12,762,763],{},"Bye for now,\nA. & R.",[12,765,766,767,151],{},"P.S: if you have found this article helpful and you’d like we write others, do you mind to help us reaching the Ballmer’s peak and buy us a ",[16,768,771],{"href":769,"rel":770},"https://rpadovani.com/donations",[],"beer",[12,773,774,775,782],{},"This post originally appeared on ",[16,776,779],{"href":777,"rel":778},"https://rpadovani.com/open-mr-gitlab-ci",[],[84,780,781],{},"rpadovani.com",".",[784,785,787],"h2",{"id":786},"about-the-guest-author","About the Guest Author",[12,789,790,791,795],{},"Riccardo is a university student and a part-time developer at ",[16,792,20],{"href":793,"rel":794},"http://www.fleetster.net/",[],". When not busy with university or work, he likes to contribute to open-source projects.",[797,798,799],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}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);}",{"title":116,"searchDepth":131,"depth":131,"links":801},[802,803,804,805,806],{"id":95,"depth":137,"text":96},{"id":679,"depth":137,"text":31},{"id":707,"depth":137,"text":708},{"id":729,"depth":137,"text":730},{"id":786,"depth":131,"text":787},"engineering","2017-09-05","With this script, every time we push a commit, GitLab CI checks if the branch that commit belongs to already has an open MR and, if not, creates one.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679783/Blog/Hero%20Images/whats-next-for-gitlab-ci.jpg",{"excerpt":815},{"type":9,"value":816},[817],[12,818,14,819,21,822,27,825,32,827,37,829,41],{},[16,820,20],{"href":18,"rel":821},[],[16,823,26],{"href":24,"rel":824},[],[16,826,31],{"href":30},[34,828,36],{},[34,830,40],{},"/en-us/blog/how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci",{"title":5,"description":809,"ogTitle":5,"ogDescription":809,"noIndex":812,"ogImage":813,"ogUrl":833,"ogSiteName":834,"ogType":835,"canonicalUrls":833},"https://about.gitlab.com/blog/how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci","https://about.gitlab.com","article","how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci","en-us/blog/how-to-automatically-create-a-new-mr-on-gitlab-with-gitlab-ci",[839,840,841],"CI/CD","user stories","tutorial","BlogPost","WVzE5HBnhhgXVtOQtEvA_HXlQOfJJLD6yBzw-Gd_Crw",{"logo":845,"freeTrial":850,"sales":855,"login":860,"items":865,"search":1190,"minimal":1221,"duo":1240,"switchNav":1249,"pricingDeployment":1260},{"config":846},{"href":847,"dataGaName":848,"dataGaLocation":849},"/","gitlab logo","header",{"text":851,"config":852},"Get free trial",{"href":853,"dataGaName":854,"dataGaLocation":849},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":856,"config":857},"Request a demo",{"href":858,"dataGaName":859,"dataGaLocation":849},"/sales/?contact-topic=request-demo","sales",{"text":861,"config":862},"Sign in",{"href":863,"dataGaName":864,"dataGaLocation":849},"https://gitlab.com/users/sign_in/","sign in",[866,895,993,998,1112,1168],{"text":867,"config":868,"menu":870},"Platform",{"dataNavLevelOne":869},"platform",{"type":871,"columns":872},"cards",[873,879,887],{"title":867,"description":874,"link":875},"The intelligent orchestration platform for DevSecOps",{"text":876,"config":877},"Explore our Platform",{"href":878,"dataGaName":869,"dataGaLocation":849},"/platform/",{"title":880,"description":881,"link":882},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":883,"config":884},"Meet GitLab Duo",{"href":885,"dataGaName":886,"dataGaLocation":849},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":888,"description":889,"link":890},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":891,"config":892},"Learn more",{"href":893,"dataGaName":894,"dataGaLocation":849},"/why-gitlab/","why gitlab",{"text":896,"left":173,"config":897,"menu":899},"Product",{"dataNavLevelOne":898},"solutions",{"type":900,"link":901,"columns":905,"feature":972},"lists",{"text":902,"config":903},"View all Solutions",{"href":904,"dataGaName":898,"dataGaLocation":849},"/solutions/",[906,928,951],{"title":907,"description":908,"link":909,"items":914},"Automation","CI/CD and automation to accelerate deployment",{"config":910},{"icon":911,"href":912,"dataGaName":913,"dataGaLocation":849},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[915,917,920,924],{"text":839,"config":916},{"href":30,"dataGaLocation":849,"dataGaName":839},{"text":880,"config":918},{"href":885,"dataGaLocation":849,"dataGaName":919},"gitlab duo agent platform - product menu",{"text":921,"config":922},"Source Code Management",{"href":923,"dataGaLocation":849,"dataGaName":921},"/solutions/source-code-management/",{"text":925,"config":926},"Automated Software Delivery",{"href":912,"dataGaLocation":849,"dataGaName":927},"Automated software delivery",{"title":929,"description":930,"link":931,"items":936},"Security","Deliver code faster without compromising security",{"config":932},{"href":933,"dataGaName":934,"dataGaLocation":849,"icon":935},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[937,941,946],{"text":938,"config":939},"Application Security Testing",{"href":933,"dataGaName":940,"dataGaLocation":849},"Application security testing",{"text":942,"config":943},"Software Supply Chain Security",{"href":944,"dataGaLocation":849,"dataGaName":945},"/solutions/supply-chain/","Software supply chain security",{"text":947,"config":948},"Software Compliance",{"href":949,"dataGaName":950,"dataGaLocation":849},"/solutions/software-compliance/","software compliance",{"title":952,"link":953,"items":958},"Measurement",{"config":954},{"icon":955,"href":956,"dataGaName":957,"dataGaLocation":849},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[959,963,967],{"text":960,"config":961},"Visibility & Measurement",{"href":956,"dataGaLocation":849,"dataGaName":962},"Visibility and Measurement",{"text":964,"config":965},"Value Stream Management",{"href":966,"dataGaLocation":849,"dataGaName":964},"/solutions/value-stream-management/",{"text":968,"config":969},"Analytics & Insights",{"href":970,"dataGaLocation":849,"dataGaName":971},"/solutions/analytics-and-insights/","Analytics and insights",{"title":973,"type":900,"items":974},"GitLab for",[975,981,987],{"text":976,"config":977},"Enterprise",{"icon":978,"href":979,"dataGaLocation":849,"dataGaName":980},"Building","/enterprise/","enterprise",{"text":982,"config":983},"Small Business",{"icon":984,"href":985,"dataGaLocation":849,"dataGaName":986},"Work","/small-business/","small business",{"text":988,"config":989},"Public Sector",{"icon":990,"href":991,"dataGaLocation":849,"dataGaName":992},"Organization","/solutions/public-sector/","public sector",{"text":994,"config":995},"Pricing",{"href":996,"dataGaName":997,"dataGaLocation":849,"dataNavLevelOne":997},"/pricing/","pricing",{"text":999,"config":1000,"menu":1002},"Resources",{"dataNavLevelOne":1001},"resources",{"type":900,"link":1003,"columns":1007,"feature":1101},{"text":1004,"config":1005},"View all resources",{"href":1006,"dataGaName":1001,"dataGaLocation":849},"/resources/",[1008,1041,1068],{"title":1009,"items":1010},"Getting started",[1011,1016,1021,1026,1031,1036],{"text":1012,"config":1013},"Install",{"href":1014,"dataGaName":1015,"dataGaLocation":849},"/install/","install",{"text":1017,"config":1018},"Quick start guides",{"href":1019,"dataGaName":1020,"dataGaLocation":849},"/get-started/","quick setup checklists",{"text":1022,"config":1023},"Learn",{"href":1024,"dataGaLocation":849,"dataGaName":1025},"https://university.gitlab.com/","learn",{"text":1027,"config":1028},"Product documentation",{"href":1029,"dataGaName":1030,"dataGaLocation":849},"https://docs.gitlab.com/","product documentation",{"text":1032,"config":1033},"Best practice videos",{"href":1034,"dataGaName":1035,"dataGaLocation":849},"/getting-started-videos/","best practice videos",{"text":1037,"config":1038},"Integrations",{"href":1039,"dataGaName":1040,"dataGaLocation":849},"/integrations/","integrations",{"title":1042,"items":1043},"Discover",[1044,1049,1054,1059,1063],{"text":1045,"config":1046},"Customer success stories",{"href":1047,"dataGaName":1048,"dataGaLocation":849},"/customers/","customer success stories",{"text":1050,"config":1051},"Blog",{"href":1052,"dataGaName":1053,"dataGaLocation":849},"/blog/","blog",{"text":1055,"config":1056},"Demo Hub",{"href":1057,"dataGaName":1058,"dataGaLocation":849},"/demo-hub/","demo hub",{"text":1060,"config":1061},"The Source",{"href":1062,"dataGaName":1053,"dataGaLocation":849},"/the-source/",{"text":1064,"config":1065},"Remote",{"href":1066,"dataGaName":1067,"dataGaLocation":849},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1069,"items":1070},"Connect",[1071,1076,1081,1086,1091,1096],{"text":1072,"config":1073},"GitLab Services",{"href":1074,"dataGaName":1075,"dataGaLocation":849},"/services/","services",{"text":1077,"config":1078},"Contribute",{"href":1079,"dataGaName":1080,"dataGaLocation":849},"https://contributors.gitlab.com","contribute",{"text":1082,"config":1083},"Community",{"href":1084,"dataGaName":1085,"dataGaLocation":849},"/community/","community",{"text":1087,"config":1088},"Forum",{"href":1089,"dataGaName":1090,"dataGaLocation":849},"https://forum.gitlab.com/","forum",{"text":1092,"config":1093},"Events",{"href":1094,"dataGaName":1095,"dataGaLocation":849},"/events/","events",{"text":1097,"config":1098},"Partners",{"href":1099,"dataGaName":1100,"dataGaLocation":849},"/partners/","partners",{"config":1102,"title":1105,"text":1106,"link":1107},{"background":1103,"textColor":1104},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1108,"config":1109},"Read the latest",{"href":1110,"dataGaName":1111,"dataGaLocation":849},"/whats-new/","whats new",{"text":1113,"config":1114,"menu":1116},"Company",{"dataNavLevelOne":1115},"company",{"type":900,"columns":1117},[1118],{"items":1119},[1120,1125,1131,1133,1138,1143,1148,1153,1158,1163],{"text":1121,"config":1122},"About",{"href":1123,"dataGaName":1124,"dataGaLocation":849},"/company/","about",{"text":1126,"config":1127,"footerGa":1130},"Jobs",{"href":1128,"dataGaName":1129,"dataGaLocation":849},"/jobs/","jobs",{"dataGaName":1129},{"text":1092,"config":1132},{"href":1094,"dataGaName":1095,"dataGaLocation":849},{"text":1134,"config":1135},"Leadership",{"href":1136,"dataGaName":1137,"dataGaLocation":849},"/company/team/e-group/","leadership",{"text":1139,"config":1140},"Handbook",{"href":1141,"dataGaName":1142,"dataGaLocation":849},"https://handbook.gitlab.com/","handbook",{"text":1144,"config":1145},"Investor relations",{"href":1146,"dataGaName":1147,"dataGaLocation":849},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1149,"config":1150},"Trust Center",{"href":1151,"dataGaName":1152,"dataGaLocation":849},"/security/","trust center",{"text":1154,"config":1155},"AI Transparency Center",{"href":1156,"dataGaName":1157,"dataGaLocation":849},"/ai-transparency-center/","ai transparency center",{"text":1159,"config":1160},"Newsletter",{"href":1161,"dataGaName":1162,"dataGaLocation":849},"/company/contact/#contact-forms","newsletter",{"text":1164,"config":1165},"Press",{"href":1166,"dataGaName":1167,"dataGaLocation":849},"/press/","press",{"text":1169,"config":1170,"menu":1171},"Contact us",{"dataNavLevelOne":1115},{"type":900,"columns":1172},[1173],{"items":1174},[1175,1180,1185],{"text":1176,"config":1177},"Talk to sales",{"href":1178,"dataGaName":1179,"dataGaLocation":849},"/sales/","talk to sales",{"text":1181,"config":1182},"Support portal",{"href":1183,"dataGaName":1184,"dataGaLocation":849},"https://support.gitlab.com/hc/en-us","support portal",{"text":1186,"config":1187},"Customer portal",{"href":1188,"dataGaName":1189,"dataGaLocation":849},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1191,"login":1192,"suggestions":1199},"Close",{"text":1193,"link":1194},"To search repositories and projects, login to",{"text":1195,"config":1196},"gitlab.com",{"href":863,"dataGaName":1197,"dataGaLocation":1198},"search login","search",{"text":1200,"default":1201},"Suggestions",[1202,1204,1208,1210,1214,1218],{"text":880,"config":1203},{"href":885,"dataGaName":880,"dataGaLocation":1198},{"text":1205,"config":1206},"Code Suggestions (AI)",{"href":1207,"dataGaName":1205,"dataGaLocation":1198},"/solutions/code-suggestions/",{"text":839,"config":1209},{"href":30,"dataGaName":839,"dataGaLocation":1198},{"text":1211,"config":1212},"GitLab on AWS",{"href":1213,"dataGaName":1211,"dataGaLocation":1198},"/partners/technology-partners/aws/",{"text":1215,"config":1216},"GitLab on Google Cloud",{"href":1217,"dataGaName":1215,"dataGaLocation":1198},"/partners/technology-partners/google-cloud-platform/",{"text":1219,"config":1220},"Why GitLab?",{"href":893,"dataGaName":1219,"dataGaLocation":1198},{"freeTrial":1222,"mobileIcon":1227,"desktopIcon":1232,"secondaryButton":1235},{"text":1223,"config":1224},"Start free trial",{"href":1225,"dataGaName":854,"dataGaLocation":1226},"https://gitlab.com/-/trials/new/","nav",{"altText":1228,"config":1229},"Gitlab Icon",{"src":1230,"dataGaName":1231,"dataGaLocation":1226},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1228,"config":1233},{"src":1234,"dataGaName":1231,"dataGaLocation":1226},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1236,"config":1237},"Get Started",{"href":1238,"dataGaName":1239,"dataGaLocation":1226},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1241,"mobileIcon":1245,"desktopIcon":1247},{"text":1242,"config":1243},"Learn more about GitLab Duo",{"href":885,"dataGaName":1244,"dataGaLocation":1226},"gitlab duo",{"altText":1228,"config":1246},{"src":1230,"dataGaName":1231,"dataGaLocation":1226},{"altText":1228,"config":1248},{"src":1234,"dataGaName":1231,"dataGaLocation":1226},{"button":1250,"mobileIcon":1255,"desktopIcon":1257},{"text":1251,"config":1252},"/switch",{"href":1253,"dataGaName":1254,"dataGaLocation":1226},"#contact","switch",{"altText":1228,"config":1256},{"src":1230,"dataGaName":1231,"dataGaLocation":1226},{"altText":1228,"config":1258},{"src":1259,"dataGaName":1231,"dataGaLocation":1226},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1261,"mobileIcon":1266,"desktopIcon":1268},{"text":1262,"config":1263},"Back to pricing",{"href":996,"dataGaName":1264,"dataGaLocation":1226,"icon":1265},"back to pricing","GoBack",{"altText":1228,"config":1267},{"src":1230,"dataGaName":1231,"dataGaLocation":1226},{"altText":1228,"config":1269},{"src":1234,"dataGaName":1231,"dataGaLocation":1226},{"title":1271,"titleMobile":1272,"button":1273,"config":1278},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":891,"config":1274},{"href":1275,"dataGaName":1276,"dataGaLocation":1277},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1279,"disabled":812},"release",{"data":1281},{"text":1282,"source":1283,"edit":1289,"contribute":1294,"config":1299,"items":1304,"minimal":1514},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1284,"config":1285},"View page source",{"href":1286,"dataGaName":1287,"dataGaLocation":1288},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1290,"config":1291},"Edit this page",{"href":1292,"dataGaName":1293,"dataGaLocation":1288},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1295,"config":1296},"Please contribute",{"href":1297,"dataGaName":1298,"dataGaLocation":1288},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1300,"facebook":1301,"youtube":1302,"linkedin":1303},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1305,1352,1406,1450,1482],{"title":994,"links":1306,"subMenu":1321},[1307,1311,1316],{"text":1308,"config":1309},"View plans",{"href":996,"dataGaName":1310,"dataGaLocation":1288},"view plans",{"text":1312,"config":1313},"Why Premium?",{"href":1314,"dataGaName":1315,"dataGaLocation":1288},"/pricing/premium/","why premium",{"text":1317,"config":1318},"Why Ultimate?",{"href":1319,"dataGaName":1320,"dataGaLocation":1288},"/pricing/ultimate/","why ultimate",[1322],{"title":1323,"links":1324},"Contact Us",[1325,1328,1330,1332,1337,1342,1347],{"text":1326,"config":1327},"Contact sales",{"href":1178,"dataGaName":859,"dataGaLocation":1288},{"text":1181,"config":1329},{"href":1183,"dataGaName":1184,"dataGaLocation":1288},{"text":1186,"config":1331},{"href":1188,"dataGaName":1189,"dataGaLocation":1288},{"text":1333,"config":1334},"Status",{"href":1335,"dataGaName":1336,"dataGaLocation":1288},"https://status.gitlab.com/","status",{"text":1338,"config":1339},"Terms of use",{"href":1340,"dataGaName":1341,"dataGaLocation":1288},"/terms/","terms of use",{"text":1343,"config":1344},"Privacy statement",{"href":1345,"dataGaName":1346,"dataGaLocation":1288},"/privacy/","privacy statement",{"text":1348,"config":1349},"Cookie preferences",{"dataGaName":1350,"dataGaLocation":1288,"id":1351,"isOneTrustButton":173},"cookie preferences","ot-sdk-btn",{"title":896,"links":1353,"subMenu":1362},[1354,1358],{"text":1355,"config":1356},"DevSecOps platform",{"href":878,"dataGaName":1357,"dataGaLocation":1288},"devsecops platform",{"text":1359,"config":1360},"AI-Assisted Development",{"href":885,"dataGaName":1361,"dataGaLocation":1288},"ai-assisted development",[1363],{"title":1364,"links":1365},"Topics",[1366,1371,1376,1381,1386,1391,1396,1401],{"text":1367,"config":1368},"CICD",{"href":1369,"dataGaName":1370,"dataGaLocation":1288},"/topics/ci-cd/","cicd",{"text":1372,"config":1373},"GitOps",{"href":1374,"dataGaName":1375,"dataGaLocation":1288},"/topics/gitops/","gitops",{"text":1377,"config":1378},"DevOps",{"href":1379,"dataGaName":1380,"dataGaLocation":1288},"/topics/devops/","devops",{"text":1382,"config":1383},"Version Control",{"href":1384,"dataGaName":1385,"dataGaLocation":1288},"/topics/version-control/","version control",{"text":1387,"config":1388},"DevSecOps",{"href":1389,"dataGaName":1390,"dataGaLocation":1288},"/topics/devsecops/","devsecops",{"text":1392,"config":1393},"Cloud Native",{"href":1394,"dataGaName":1395,"dataGaLocation":1288},"/topics/cloud-native/","cloud native",{"text":1397,"config":1398},"AI for Coding",{"href":1399,"dataGaName":1400,"dataGaLocation":1288},"/topics/devops/ai-for-coding/","ai for coding",{"text":1402,"config":1403},"Agentic AI",{"href":1404,"dataGaName":1405,"dataGaLocation":1288},"/topics/agentic-ai/","agentic ai",{"title":1407,"links":1408},"Solutions",[1409,1411,1413,1418,1422,1425,1429,1432,1434,1437,1440,1445],{"text":938,"config":1410},{"href":933,"dataGaName":938,"dataGaLocation":1288},{"text":927,"config":1412},{"href":912,"dataGaName":913,"dataGaLocation":1288},{"text":1414,"config":1415},"Agile development",{"href":1416,"dataGaName":1417,"dataGaLocation":1288},"/solutions/agile-delivery/","agile delivery",{"text":1419,"config":1420},"SCM",{"href":923,"dataGaName":1421,"dataGaLocation":1288},"source code management",{"text":1367,"config":1423},{"href":30,"dataGaName":1424,"dataGaLocation":1288},"continuous integration & delivery",{"text":1426,"config":1427},"Value stream management",{"href":966,"dataGaName":1428,"dataGaLocation":1288},"value stream management",{"text":1372,"config":1430},{"href":1431,"dataGaName":1375,"dataGaLocation":1288},"/solutions/gitops/",{"text":976,"config":1433},{"href":979,"dataGaName":980,"dataGaLocation":1288},{"text":1435,"config":1436},"Small business",{"href":985,"dataGaName":986,"dataGaLocation":1288},{"text":1438,"config":1439},"Public sector",{"href":991,"dataGaName":992,"dataGaLocation":1288},{"text":1441,"config":1442},"Education",{"href":1443,"dataGaName":1444,"dataGaLocation":1288},"/solutions/education/","education",{"text":1446,"config":1447},"Financial services",{"href":1448,"dataGaName":1449,"dataGaLocation":1288},"/solutions/finance/","financial services",{"title":999,"links":1451},[1452,1454,1456,1458,1461,1463,1466,1468,1470,1472,1474,1476,1478,1480],{"text":1012,"config":1453},{"href":1014,"dataGaName":1015,"dataGaLocation":1288},{"text":1017,"config":1455},{"href":1019,"dataGaName":1020,"dataGaLocation":1288},{"text":1022,"config":1457},{"href":1024,"dataGaName":1025,"dataGaLocation":1288},{"text":1027,"config":1459},{"href":1029,"dataGaName":1460,"dataGaLocation":1288},"docs",{"text":1050,"config":1462},{"href":1052,"dataGaName":1053,"dataGaLocation":1288},{"text":1464,"config":1465},"What's new",{"href":1110,"dataGaName":1111,"dataGaLocation":1288},{"text":1045,"config":1467},{"href":1047,"dataGaName":1048,"dataGaLocation":1288},{"text":1064,"config":1469},{"href":1066,"dataGaName":1067,"dataGaLocation":1288},{"text":1072,"config":1471},{"href":1074,"dataGaName":1075,"dataGaLocation":1288},{"text":1077,"config":1473},{"href":1079,"dataGaName":1080,"dataGaLocation":1288},{"text":1082,"config":1475},{"href":1084,"dataGaName":1085,"dataGaLocation":1288},{"text":1087,"config":1477},{"href":1089,"dataGaName":1090,"dataGaLocation":1288},{"text":1092,"config":1479},{"href":1094,"dataGaName":1095,"dataGaLocation":1288},{"text":1097,"config":1481},{"href":1099,"dataGaName":1100,"dataGaLocation":1288},{"title":1113,"links":1483},[1484,1486,1488,1490,1492,1494,1498,1503,1505,1507,1509],{"text":1121,"config":1485},{"href":1123,"dataGaName":1115,"dataGaLocation":1288},{"text":1126,"config":1487},{"href":1128,"dataGaName":1129,"dataGaLocation":1288},{"text":1134,"config":1489},{"href":1136,"dataGaName":1137,"dataGaLocation":1288},{"text":1139,"config":1491},{"href":1141,"dataGaName":1142,"dataGaLocation":1288},{"text":1144,"config":1493},{"href":1146,"dataGaName":1147,"dataGaLocation":1288},{"text":1495,"config":1496},"Sustainability",{"href":1497,"dataGaName":1495,"dataGaLocation":1288},"/sustainability/",{"text":1499,"config":1500},"Diversity, inclusion and belonging (DIB)",{"href":1501,"dataGaName":1502,"dataGaLocation":1288},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1149,"config":1504},{"href":1151,"dataGaName":1152,"dataGaLocation":1288},{"text":1159,"config":1506},{"href":1161,"dataGaName":1162,"dataGaLocation":1288},{"text":1164,"config":1508},{"href":1166,"dataGaName":1167,"dataGaLocation":1288},{"text":1510,"config":1511},"Modern Slavery Transparency Statement",{"href":1512,"dataGaName":1513,"dataGaLocation":1288},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1515},[1516,1519,1522],{"text":1517,"config":1518},"Terms",{"href":1340,"dataGaName":1341,"dataGaLocation":1288},{"text":1520,"config":1521},"Cookies",{"dataGaName":1350,"dataGaLocation":1288,"id":1351,"isOneTrustButton":173},{"text":1523,"config":1524},"Privacy",{"href":1345,"dataGaName":1346,"dataGaLocation":1288},[1526],{"id":1527,"title":7,"body":811,"config":1528,"content":1530,"description":811,"extension":1534,"meta":1535,"navigation":173,"path":1536,"seo":1537,"stem":1538,"__hash__":1539},"blogAuthors/en-us/blog/authors/riccardo-padovani.yml",{"template":1529},"BlogAuthor",{"name":7,"config":1531},{"headshot":1532,"ctfId":1533},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659488/Blog/Author%20Headshots/gitlab-logo-extra-whitespace.png","Riccardo-Padovani","yml",{},"/en-us/blog/authors/riccardo-padovani",{},"en-us/blog/authors/riccardo-padovani","T-wtYATHMXc45-YIVJc6pk7jItpWUbE44wCUfv7YeVY",[1541,1550,1558],{"title":1542,"description":1543,"heroImage":1544,"category":807,"date":1545,"authors":1546,"slug":1549,"externalUrl":811},"Confidential AI for GitLab Self-Hosted","Give developers AI coding agents in GitLab Duo without source code leaving a hardware-encrypted boundary — no GPUs needed.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1773866173/vte9qh8rriznvyclhkes.png","2026-08-06",[1547,1548],"Mathias Ewald","Martin Paloncy, Edgeless Systems","confidential-ai-for-gitlab-self-hosted",{"title":1551,"description":1552,"heroImage":1553,"category":807,"date":1554,"authors":1555,"slug":1557,"externalUrl":811},"Green DevOps: Why carbon measurement belongs in your CI/CD pipeline","CI/CD pipelines have a hidden carbon cost. Here's why measuring it matters, and how you can get started with Eco CI and Carmen in GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1765809212/noh0mdfn9o94ry9ykura.png","2026-07-09",[1556],"Lysanne Pinto","green-devops-carbon-measurement-cicd-pipeline",{"title":1559,"description":1560,"heroImage":1561,"category":807,"date":1562,"authors":1563,"slug":1565,"externalUrl":811},"How to build CI/CD observability at scale","This practical guide to GitLab pipeline analytics helps self-managed users gain operational insights using Prometheus and Grafana.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1774465167/n5hlvrsrheadeccyr1oz.png","2026-04-28",[1564],"Paul Meresanu","how-to-build-ci-cd-observability-at-scale",{"promotions":1567},[1568,1582,1594,1606],{"id":1569,"categories":1570,"header":1572,"text":1573,"button":1574,"image":1579},"ai-modernization",[1571],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":1575,"config":1576},"Get your AI maturity score",{"href":1577,"dataGaName":1578,"dataGaLocation":1053},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":1580},{"src":1581},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":1583,"categories":1584,"header":1586,"text":1573,"button":1587,"image":1591},"devops-modernization",[1585,1390],"product","Are you just managing tools or shipping innovation?",{"text":1588,"config":1589},"Get your DevOps maturity score",{"href":1590,"dataGaName":1578,"dataGaLocation":1053},"/assessments/devops-modernization-assessment/",{"config":1592},{"src":1593},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":1595,"categories":1596,"header":1598,"text":1573,"button":1599,"image":1603},"security-modernization",[1597],"security","Are you trading speed for security?",{"text":1600,"config":1601},"Get your security maturity score",{"href":1602,"dataGaName":1578,"dataGaLocation":1053},"/assessments/security-modernization-assessment/",{"config":1604},{"src":1605},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":1607,"paths":1608,"header":1611,"text":1612,"button":1613,"image":1618},"github-azure-migration",[1609,1610],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":1614,"config":1615},"See how GitLab compares to GitHub",{"href":1616,"dataGaName":1617,"dataGaLocation":1053},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":1619},{"src":1593},{"header":1621,"blurb":1622,"button":1623,"secondaryButton":1628},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":1624,"config":1625},"Get your free trial",{"href":1626,"dataGaName":854,"dataGaLocation":1627},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1326,"config":1629},{"href":1178,"dataGaName":859,"dataGaLocation":1627},1786803751928]