[{"data":1,"prerenderedAt":3708},["ShallowReactive",2],{"/en-us/blog/tags/integrations/":3,"navigation-en-us":19,"banner-en-us":447,"footer-en-us":464,"integrations-tag-page-en-us":674},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"content":8,"config":10,"_id":12,"_type":13,"title":14,"_source":15,"_file":16,"_stem":17,"_extension":18},"/en-us/blog/tags/integrations","tags",false,"",{"tag":9,"tagSlug":9},"integrations",{"template":11},"BlogTag","content:en-us:blog:tags:integrations.yml","yaml","Integrations","content","en-us/blog/tags/integrations.yml","en-us/blog/tags/integrations","yml",{"_path":20,"_dir":21,"_draft":6,"_partial":6,"_locale":7,"data":22,"_id":443,"_type":13,"title":444,"_source":15,"_file":445,"_stem":446,"_extension":18},"/shared/en-us/main-navigation","en-us",{"logo":23,"freeTrial":28,"sales":33,"login":38,"items":43,"search":374,"minimal":405,"duo":424,"pricingDeployment":433},{"config":24},{"href":25,"dataGaName":26,"dataGaLocation":27},"/","gitlab logo","header",{"text":29,"config":30},"Get free trial",{"href":31,"dataGaName":32,"dataGaLocation":27},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":34,"config":35},"Talk to sales",{"href":36,"dataGaName":37,"dataGaLocation":27},"/sales/","sales",{"text":39,"config":40},"Sign in",{"href":41,"dataGaName":42,"dataGaLocation":27},"https://gitlab.com/users/sign_in/","sign in",[44,88,186,191,295,355],{"text":45,"config":46,"cards":48,"footer":71},"Platform",{"dataNavLevelOne":47},"platform",[49,55,63],{"title":45,"description":50,"link":51},"The most comprehensive AI-powered DevSecOps Platform",{"text":52,"config":53},"Explore our Platform",{"href":54,"dataGaName":47,"dataGaLocation":27},"/platform/",{"title":56,"description":57,"link":58},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":59,"config":60},"Meet GitLab Duo",{"href":61,"dataGaName":62,"dataGaLocation":27},"/gitlab-duo/","gitlab duo ai",{"title":64,"description":65,"link":66},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":67,"config":68},"Learn more",{"href":69,"dataGaName":70,"dataGaLocation":27},"/why-gitlab/","why gitlab",{"title":72,"items":73},"Get started with",[74,79,84],{"text":75,"config":76},"Platform Engineering",{"href":77,"dataGaName":78,"dataGaLocation":27},"/solutions/platform-engineering/","platform engineering",{"text":80,"config":81},"Developer Experience",{"href":82,"dataGaName":83,"dataGaLocation":27},"/developer-experience/","Developer experience",{"text":85,"config":86},"MLOps",{"href":87,"dataGaName":85,"dataGaLocation":27},"/topics/devops/the-role-of-ai-in-devops/",{"text":89,"left":90,"config":91,"link":93,"lists":97,"footer":168},"Product",true,{"dataNavLevelOne":92},"solutions",{"text":94,"config":95},"View all Solutions",{"href":96,"dataGaName":92,"dataGaLocation":27},"/solutions/",[98,123,147],{"title":99,"description":100,"link":101,"items":106},"Automation","CI/CD and automation to accelerate deployment",{"config":102},{"icon":103,"href":104,"dataGaName":105,"dataGaLocation":27},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[107,111,115,119],{"text":108,"config":109},"CI/CD",{"href":110,"dataGaLocation":27,"dataGaName":108},"/solutions/continuous-integration/",{"text":112,"config":113},"AI-Assisted Development",{"href":61,"dataGaLocation":27,"dataGaName":114},"AI assisted development",{"text":116,"config":117},"Source Code Management",{"href":118,"dataGaLocation":27,"dataGaName":116},"/solutions/source-code-management/",{"text":120,"config":121},"Automated Software Delivery",{"href":104,"dataGaLocation":27,"dataGaName":122},"Automated software delivery",{"title":124,"description":125,"link":126,"items":131},"Security","Deliver code faster without compromising security",{"config":127},{"href":128,"dataGaName":129,"dataGaLocation":27,"icon":130},"/solutions/security-compliance/","security and compliance","ShieldCheckLight",[132,137,142],{"text":133,"config":134},"Application Security Testing",{"href":135,"dataGaName":136,"dataGaLocation":27},"/solutions/application-security-testing/","Application security testing",{"text":138,"config":139},"Software Supply Chain Security",{"href":140,"dataGaLocation":27,"dataGaName":141},"/solutions/supply-chain/","Software supply chain security",{"text":143,"config":144},"Software Compliance",{"href":145,"dataGaName":146,"dataGaLocation":27},"/solutions/software-compliance/","software compliance",{"title":148,"link":149,"items":154},"Measurement",{"config":150},{"icon":151,"href":152,"dataGaName":153,"dataGaLocation":27},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[155,159,163],{"text":156,"config":157},"Visibility & Measurement",{"href":152,"dataGaLocation":27,"dataGaName":158},"Visibility and Measurement",{"text":160,"config":161},"Value Stream Management",{"href":162,"dataGaLocation":27,"dataGaName":160},"/solutions/value-stream-management/",{"text":164,"config":165},"Analytics & Insights",{"href":166,"dataGaLocation":27,"dataGaName":167},"/solutions/analytics-and-insights/","Analytics and insights",{"title":169,"items":170},"GitLab for",[171,176,181],{"text":172,"config":173},"Enterprise",{"href":174,"dataGaLocation":27,"dataGaName":175},"/enterprise/","enterprise",{"text":177,"config":178},"Small Business",{"href":179,"dataGaLocation":27,"dataGaName":180},"/small-business/","small business",{"text":182,"config":183},"Public Sector",{"href":184,"dataGaLocation":27,"dataGaName":185},"/solutions/public-sector/","public sector",{"text":187,"config":188},"Pricing",{"href":189,"dataGaName":190,"dataGaLocation":27,"dataNavLevelOne":190},"/pricing/","pricing",{"text":192,"config":193,"link":195,"lists":199,"feature":282},"Resources",{"dataNavLevelOne":194},"resources",{"text":196,"config":197},"View all resources",{"href":198,"dataGaName":194,"dataGaLocation":27},"/resources/",[200,231,254],{"title":201,"items":202},"Getting started",[203,208,213,218,223,228],{"text":204,"config":205},"Install",{"href":206,"dataGaName":207,"dataGaLocation":27},"/install/","install",{"text":209,"config":210},"Quick start guides",{"href":211,"dataGaName":212,"dataGaLocation":27},"/get-started/","quick setup checklists",{"text":214,"config":215},"Learn",{"href":216,"dataGaLocation":27,"dataGaName":217},"https://university.gitlab.com/","learn",{"text":219,"config":220},"Product documentation",{"href":221,"dataGaName":222,"dataGaLocation":27},"https://docs.gitlab.com/","product documentation",{"text":224,"config":225},"Best practice videos",{"href":226,"dataGaName":227,"dataGaLocation":27},"/getting-started-videos/","best practice videos",{"text":14,"config":229},{"href":230,"dataGaName":9,"dataGaLocation":27},"/integrations/",{"title":232,"items":233},"Discover",[234,239,244,249],{"text":235,"config":236},"Customer success stories",{"href":237,"dataGaName":238,"dataGaLocation":27},"/customers/","customer success stories",{"text":240,"config":241},"Blog",{"href":242,"dataGaName":243,"dataGaLocation":27},"/blog/","blog",{"text":245,"config":246},"Remote",{"href":247,"dataGaName":248,"dataGaLocation":27},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":250,"config":251},"TeamOps",{"href":252,"dataGaName":253,"dataGaLocation":27},"/teamops/","teamops",{"title":255,"items":256},"Connect",[257,262,267,272,277],{"text":258,"config":259},"GitLab Services",{"href":260,"dataGaName":261,"dataGaLocation":27},"/services/","services",{"text":263,"config":264},"Community",{"href":265,"dataGaName":266,"dataGaLocation":27},"/community/","community",{"text":268,"config":269},"Forum",{"href":270,"dataGaName":271,"dataGaLocation":27},"https://forum.gitlab.com/","forum",{"text":273,"config":274},"Events",{"href":275,"dataGaName":276,"dataGaLocation":27},"/events/","events",{"text":278,"config":279},"Partners",{"href":280,"dataGaName":281,"dataGaLocation":27},"/partners/","partners",{"backgroundColor":283,"textColor":284,"text":285,"image":286,"link":290},"#2f2a6b","#fff","Insights for the future of software development",{"altText":287,"config":288},"the source promo card",{"src":289},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":291,"config":292},"Read the latest",{"href":293,"dataGaName":294,"dataGaLocation":27},"/the-source/","the source",{"text":296,"config":297,"lists":299},"Company",{"dataNavLevelOne":298},"company",[300],{"items":301},[302,307,313,315,320,325,330,335,340,345,350],{"text":303,"config":304},"About",{"href":305,"dataGaName":306,"dataGaLocation":27},"/company/","about",{"text":308,"config":309,"footerGa":312},"Jobs",{"href":310,"dataGaName":311,"dataGaLocation":27},"/jobs/","jobs",{"dataGaName":311},{"text":273,"config":314},{"href":275,"dataGaName":276,"dataGaLocation":27},{"text":316,"config":317},"Leadership",{"href":318,"dataGaName":319,"dataGaLocation":27},"/company/team/e-group/","leadership",{"text":321,"config":322},"Team",{"href":323,"dataGaName":324,"dataGaLocation":27},"/company/team/","team",{"text":326,"config":327},"Handbook",{"href":328,"dataGaName":329,"dataGaLocation":27},"https://handbook.gitlab.com/","handbook",{"text":331,"config":332},"Investor relations",{"href":333,"dataGaName":334,"dataGaLocation":27},"https://ir.gitlab.com/","investor relations",{"text":336,"config":337},"Trust Center",{"href":338,"dataGaName":339,"dataGaLocation":27},"/security/","trust center",{"text":341,"config":342},"AI Transparency Center",{"href":343,"dataGaName":344,"dataGaLocation":27},"/ai-transparency-center/","ai transparency center",{"text":346,"config":347},"Newsletter",{"href":348,"dataGaName":349,"dataGaLocation":27},"/company/contact/","newsletter",{"text":351,"config":352},"Press",{"href":353,"dataGaName":354,"dataGaLocation":27},"/press/","press",{"text":356,"config":357,"lists":358},"Contact us",{"dataNavLevelOne":298},[359],{"items":360},[361,364,369],{"text":34,"config":362},{"href":36,"dataGaName":363,"dataGaLocation":27},"talk to sales",{"text":365,"config":366},"Get help",{"href":367,"dataGaName":368,"dataGaLocation":27},"/support/","get help",{"text":370,"config":371},"Customer portal",{"href":372,"dataGaName":373,"dataGaLocation":27},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":375,"login":376,"suggestions":383},"Close",{"text":377,"link":378},"To search repositories and projects, login to",{"text":379,"config":380},"gitlab.com",{"href":41,"dataGaName":381,"dataGaLocation":382},"search login","search",{"text":384,"default":385},"Suggestions",[386,388,392,394,398,402],{"text":56,"config":387},{"href":61,"dataGaName":56,"dataGaLocation":382},{"text":389,"config":390},"Code Suggestions (AI)",{"href":391,"dataGaName":389,"dataGaLocation":382},"/solutions/code-suggestions/",{"text":108,"config":393},{"href":110,"dataGaName":108,"dataGaLocation":382},{"text":395,"config":396},"GitLab on AWS",{"href":397,"dataGaName":395,"dataGaLocation":382},"/partners/technology-partners/aws/",{"text":399,"config":400},"GitLab on Google Cloud",{"href":401,"dataGaName":399,"dataGaLocation":382},"/partners/technology-partners/google-cloud-platform/",{"text":403,"config":404},"Why GitLab?",{"href":69,"dataGaName":403,"dataGaLocation":382},{"freeTrial":406,"mobileIcon":411,"desktopIcon":416,"secondaryButton":419},{"text":407,"config":408},"Start free trial",{"href":409,"dataGaName":32,"dataGaLocation":410},"https://gitlab.com/-/trials/new/","nav",{"altText":412,"config":413},"Gitlab Icon",{"src":414,"dataGaName":415,"dataGaLocation":410},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":412,"config":417},{"src":418,"dataGaName":415,"dataGaLocation":410},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":420,"config":421},"Get Started",{"href":422,"dataGaName":423,"dataGaLocation":410},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":425,"mobileIcon":429,"desktopIcon":431},{"text":426,"config":427},"Learn more about GitLab Duo",{"href":61,"dataGaName":428,"dataGaLocation":410},"gitlab duo",{"altText":412,"config":430},{"src":414,"dataGaName":415,"dataGaLocation":410},{"altText":412,"config":432},{"src":418,"dataGaName":415,"dataGaLocation":410},{"freeTrial":434,"mobileIcon":439,"desktopIcon":441},{"text":435,"config":436},"Back to pricing",{"href":189,"dataGaName":437,"dataGaLocation":410,"icon":438},"back to pricing","GoBack",{"altText":412,"config":440},{"src":414,"dataGaName":415,"dataGaLocation":410},{"altText":412,"config":442},{"src":418,"dataGaName":415,"dataGaLocation":410},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":448,"_dir":21,"_draft":6,"_partial":6,"_locale":7,"title":449,"button":450,"image":455,"config":459,"_id":461,"_type":13,"_source":15,"_file":462,"_stem":463,"_extension":18},"/shared/en-us/banner","is now in public beta!",{"text":451,"config":452},"Try the Beta",{"href":453,"dataGaName":454,"dataGaLocation":27},"/gitlab-duo/agent-platform/","duo banner",{"altText":456,"config":457},"GitLab Duo Agent Platform",{"src":458},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":460},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":465,"_dir":21,"_draft":6,"_partial":6,"_locale":7,"data":466,"_id":670,"_type":13,"title":671,"_source":15,"_file":672,"_stem":673,"_extension":18},"/shared/en-us/main-footer",{"text":467,"source":468,"edit":474,"contribute":479,"config":484,"items":489,"minimal":662},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":469,"config":470},"View page source",{"href":471,"dataGaName":472,"dataGaLocation":473},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":475,"config":476},"Edit this page",{"href":477,"dataGaName":478,"dataGaLocation":473},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":480,"config":481},"Please contribute",{"href":482,"dataGaName":483,"dataGaLocation":473},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":485,"facebook":486,"youtube":487,"linkedin":488},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[490,513,569,598,632],{"title":45,"links":491,"subMenu":496},[492],{"text":493,"config":494},"DevSecOps platform",{"href":54,"dataGaName":495,"dataGaLocation":473},"devsecops platform",[497],{"title":187,"links":498},[499,503,508],{"text":500,"config":501},"View plans",{"href":189,"dataGaName":502,"dataGaLocation":473},"view plans",{"text":504,"config":505},"Why Premium?",{"href":506,"dataGaName":507,"dataGaLocation":473},"/pricing/premium/","why premium",{"text":509,"config":510},"Why Ultimate?",{"href":511,"dataGaName":512,"dataGaLocation":473},"/pricing/ultimate/","why ultimate",{"title":514,"links":515},"Solutions",[516,521,523,525,530,535,539,542,546,551,553,556,559,564],{"text":517,"config":518},"Digital transformation",{"href":519,"dataGaName":520,"dataGaLocation":473},"/topics/digital-transformation/","digital transformation",{"text":133,"config":522},{"href":135,"dataGaName":133,"dataGaLocation":473},{"text":122,"config":524},{"href":104,"dataGaName":105,"dataGaLocation":473},{"text":526,"config":527},"Agile development",{"href":528,"dataGaName":529,"dataGaLocation":473},"/solutions/agile-delivery/","agile delivery",{"text":531,"config":532},"Cloud transformation",{"href":533,"dataGaName":534,"dataGaLocation":473},"/topics/cloud-native/","cloud transformation",{"text":536,"config":537},"SCM",{"href":118,"dataGaName":538,"dataGaLocation":473},"source code management",{"text":108,"config":540},{"href":110,"dataGaName":541,"dataGaLocation":473},"continuous integration & delivery",{"text":543,"config":544},"Value stream management",{"href":162,"dataGaName":545,"dataGaLocation":473},"value stream management",{"text":547,"config":548},"GitOps",{"href":549,"dataGaName":550,"dataGaLocation":473},"/solutions/gitops/","gitops",{"text":172,"config":552},{"href":174,"dataGaName":175,"dataGaLocation":473},{"text":554,"config":555},"Small business",{"href":179,"dataGaName":180,"dataGaLocation":473},{"text":557,"config":558},"Public sector",{"href":184,"dataGaName":185,"dataGaLocation":473},{"text":560,"config":561},"Education",{"href":562,"dataGaName":563,"dataGaLocation":473},"/solutions/education/","education",{"text":565,"config":566},"Financial services",{"href":567,"dataGaName":568,"dataGaLocation":473},"/solutions/finance/","financial services",{"title":192,"links":570},[571,573,575,577,580,582,584,586,588,590,592,594,596],{"text":204,"config":572},{"href":206,"dataGaName":207,"dataGaLocation":473},{"text":209,"config":574},{"href":211,"dataGaName":212,"dataGaLocation":473},{"text":214,"config":576},{"href":216,"dataGaName":217,"dataGaLocation":473},{"text":219,"config":578},{"href":221,"dataGaName":579,"dataGaLocation":473},"docs",{"text":240,"config":581},{"href":242,"dataGaName":243,"dataGaLocation":473},{"text":235,"config":583},{"href":237,"dataGaName":238,"dataGaLocation":473},{"text":245,"config":585},{"href":247,"dataGaName":248,"dataGaLocation":473},{"text":258,"config":587},{"href":260,"dataGaName":261,"dataGaLocation":473},{"text":250,"config":589},{"href":252,"dataGaName":253,"dataGaLocation":473},{"text":263,"config":591},{"href":265,"dataGaName":266,"dataGaLocation":473},{"text":268,"config":593},{"href":270,"dataGaName":271,"dataGaLocation":473},{"text":273,"config":595},{"href":275,"dataGaName":276,"dataGaLocation":473},{"text":278,"config":597},{"href":280,"dataGaName":281,"dataGaLocation":473},{"title":296,"links":599},[600,602,604,606,608,610,612,616,621,623,625,627],{"text":303,"config":601},{"href":305,"dataGaName":298,"dataGaLocation":473},{"text":308,"config":603},{"href":310,"dataGaName":311,"dataGaLocation":473},{"text":316,"config":605},{"href":318,"dataGaName":319,"dataGaLocation":473},{"text":321,"config":607},{"href":323,"dataGaName":324,"dataGaLocation":473},{"text":326,"config":609},{"href":328,"dataGaName":329,"dataGaLocation":473},{"text":331,"config":611},{"href":333,"dataGaName":334,"dataGaLocation":473},{"text":613,"config":614},"Sustainability",{"href":615,"dataGaName":613,"dataGaLocation":473},"/sustainability/",{"text":617,"config":618},"Diversity, inclusion and belonging (DIB)",{"href":619,"dataGaName":620,"dataGaLocation":473},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":336,"config":622},{"href":338,"dataGaName":339,"dataGaLocation":473},{"text":346,"config":624},{"href":348,"dataGaName":349,"dataGaLocation":473},{"text":351,"config":626},{"href":353,"dataGaName":354,"dataGaLocation":473},{"text":628,"config":629},"Modern Slavery Transparency Statement",{"href":630,"dataGaName":631,"dataGaLocation":473},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":633,"links":634},"Contact Us",[635,638,640,642,647,652,657],{"text":636,"config":637},"Contact an expert",{"href":36,"dataGaName":37,"dataGaLocation":473},{"text":365,"config":639},{"href":367,"dataGaName":368,"dataGaLocation":473},{"text":370,"config":641},{"href":372,"dataGaName":373,"dataGaLocation":473},{"text":643,"config":644},"Status",{"href":645,"dataGaName":646,"dataGaLocation":473},"https://status.gitlab.com/","status",{"text":648,"config":649},"Terms of use",{"href":650,"dataGaName":651,"dataGaLocation":473},"/terms/","terms of use",{"text":653,"config":654},"Privacy statement",{"href":655,"dataGaName":656,"dataGaLocation":473},"/privacy/","privacy statement",{"text":658,"config":659},"Cookie preferences",{"dataGaName":660,"dataGaLocation":473,"id":661,"isOneTrustButton":90},"cookie preferences","ot-sdk-btn",{"items":663},[664,666,668],{"text":648,"config":665},{"href":650,"dataGaName":651,"dataGaLocation":473},{"text":653,"config":667},{"href":655,"dataGaName":656,"dataGaLocation":473},{"text":658,"config":669},{"dataGaName":660,"dataGaLocation":473,"id":661,"isOneTrustButton":90},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",{"allPosts":675,"featuredPost":3687,"totalPagesCount":3706,"initialPosts":3707},[676,701,724,749,771,792,814,834,858,879,899,920,941,961,983,1005,1026,1047,1067,1087,1107,1127,1147,1168,1190,1210,1231,1253,1273,1294,1314,1335,1355,1375,1395,1415,1434,1454,1476,1496,1516,1535,1555,1576,1596,1616,1636,1655,1678,1697,1717,1738,1759,1780,1800,1820,1840,1860,1879,1897,1916,1935,1955,1975,1996,2015,2034,2055,2076,2096,2115,2135,2154,2175,2195,2215,2236,2256,2274,2295,2314,2335,2353,2373,2392,2412,2432,2453,2472,2492,2512,2531,2551,2571,2591,2611,2631,2652,2671,2691,2710,2731,2752,2772,2791,2810,2829,2846,2864,2884,2904,2923,2943,2962,2982,3001,3020,3039,3058,3077,3097,3118,3138,3158,3177,3199,3217,3237,3256,3275,3295,3315,3335,3355,3376,3395,3417,3437,3457,3478,3496,3515,3533,3551,3569,3589,3608,3627,3647,3666],{"_path":677,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":678,"content":686,"config":694,"_id":697,"_type":13,"title":698,"_source":15,"_file":699,"_stem":700,"_extension":18},"/en-us/blog/a-visual-prototype-of-drupal-dot-orgs-integration-with-gitlab",{"title":679,"description":680,"ogTitle":679,"ogDescription":680,"noIndex":6,"ogImage":681,"ogUrl":682,"ogSiteName":683,"ogType":684,"canonicalUrls":682,"schema":685},"A visual prototype of Drupal.org's GitLab integration","Guest author Tim Lehnen shares a visual preview of free and open source platform Drupal's upcoming integration with GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671386/Blog/Hero%20Images/drupal-cover.png","https://about.gitlab.com/blog/a-visual-prototype-of-drupal-dot-orgs-integration-with-gitlab","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"A visual prototype of Drupal.org's GitLab integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Lehnen\"}],\n        \"datePublished\": \"2018-12-19\",\n      }",{"title":679,"description":680,"authors":687,"heroImage":681,"date":689,"body":690,"category":691,"tags":692},[688],"Tim Lehnen","2018-12-19","\nAt [Drupal Europe](https://www.drupaleurope.org) in September, we were very pleased that project founder [Dries Buytaert](https://dri.es) highlighted a visual prototype of our upcoming integration with GitLab in his keynote. This follows our announcement that we'd be [moving to GitLab](/blog/drupal-moves-to-gitlab/) back in August.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/q06taaJPGDw?rel=0&amp;showinfo=0\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nThis video outlines the migration phases that we discussed [in the announcement of our partnership with GitLab](https://www.drupal.org/drupalorg/blog/developer-tools-initiative-part-5-gitlab-partnership). Our migration window for Phase 1 is targeted for the first weeks of January, and we hope Phase 2 to be completed shortly in the beginning of 2019.\n\n## So what has it taken to get this integration working between September and now?\n\nPrimarily, lots of collaboration with the GitLab team. We've worked with their excellent engineering staff to resolve a number of issues that affect our integration, including:\n\n- [git merge-base web API](https://gitlab.com/gitlab-org/gitlab-ce/issues/49850)\n- [Add ability to confirm a user’s email address via \"Add email for user\" API](https://gitlab.com/gitlab-org/gitlab-ce/issues/50876)\n- [Allow configuration of the display URL for clone instructions](https://gitlab.com/gitlab-org/gitlab-ce/issues/49698)\n- [Ability to hide User's Email Address from GitLab UI](https://gitlab.com/gitlab-org/gitlab-ce/issues/24221)\n- [Allow ability for developer role to delete tags](https://gitlab.com/gitlab-org/gitlab-ce/issues/52954)\n- [Set GL_REPOSITORY in update hooks for API-initiated requests](https://gitlab.com/gitlab-org/gitaly/issues/1402)\n- [Deduplication of Git objects, reducing disk space of repository forks](https://gitlab.com/gitlab-org/gitlab-ce/issues/23029)\n\nOn the Drupal.org side:\n\n - We've built a [`versioncontrol_gitlab` module](https://www.drupal.org/project/versioncontrol_gitlab), which extends our use of the [`versioncontrol_git` module](https://www.drupal.org/project/versioncontrol_git) to orchestrate our integration.\n - We've also been cleaning up our data, to ensure there are no namespace conflicts between existing Drupal projects and users, and the reserved terms used by GitLab.\n\nWe're now in the midst of serious migration testing: testing and re-testing the process in our staging environment, putting load testing in place to stress test our integration, and doing user-validation testing to ensure that the workflows affected by this integration are working as expected.\n\nAll in all, we're thrilled with the progress, and very thankful for GitLab's close collaboration. We're excited to be moving the Drupal project to its next generation tooling soon. Once Phase 1 of our migration is complete, it'll be time for Phase 2 and our community will start seeing some tremendous improvements in efficiency and collaboration.\n\n## How can people get involved in Drupal?\n\nThe Drupal community has a comprehensive [Getting Involved Guide](https://www.drupal.org/getting-involved-guide) that can help individuals find their place in the Drupal community. There are also meetups and conferences around the world that are a great way to start your Drupal journey. In particular, [DrupalCon will be coming to Seattle from Apr. 8-12, 2019](https://events.drupal.org/seattle2019).\n\nThe Drupal project's motto has always been \"Come for the code, stay for the community\" and 17 years later, that's a sentiment we still believe in.\n\n### About the guest author\n\nTim Lehnen is the Executive Director at the [Drupal Association](https://www.drupal.org/association).\n\n_This guest post was originally published [on the Drupal blog](https://www.drupal.org/drupalorg/blog/a-visual-prototype-of-drupalorgs-integration-with-gitlab)._\n","open-source",[693,266,9],"open source",{"slug":695,"featured":6,"template":696},"a-visual-prototype-of-drupal-dot-orgs-integration-with-gitlab","BlogPost","content:en-us:blog:a-visual-prototype-of-drupal-dot-orgs-integration-with-gitlab.yml","A Visual Prototype Of Drupal Dot Orgs Integration With Gitlab","en-us/blog/a-visual-prototype-of-drupal-dot-orgs-integration-with-gitlab.yml","en-us/blog/a-visual-prototype-of-drupal-dot-orgs-integration-with-gitlab",{"_path":702,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":703,"content":709,"config":718,"_id":720,"_type":13,"title":721,"_source":15,"_file":722,"_stem":723,"_extension":18},"/en-us/blog/a-year-of-iteration",{"title":704,"description":705,"ogTitle":704,"ogDescription":705,"noIndex":6,"ogImage":706,"ogUrl":707,"ogSiteName":683,"ogType":684,"canonicalUrls":707,"schema":708},"2020: A year of iteration","A look at how far Vulnerability Management progressed in 2020 through hard work and lots of iterations.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681857/Blog/Hero%20Images/cover-2020-a-year-of-iteration.jpg","https://about.gitlab.com/blog/a-year-of-iteration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"2020: A year of iteration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Matt Wilson\"}],\n        \"datePublished\": \"2021-01-18\",\n      }",{"title":704,"description":705,"authors":710,"heroImage":706,"date":712,"body":713,"category":714,"tags":715},[711],"Matt Wilson","2021-01-18","\n\n{::options parse_block_html=\"true\" /}\n\n\n\nAt GitLab, [we’re all about iteration](https://handbook.gitlab.com/handbook/values/#iteration). It helps us continuously push out product improvements and additional value to our users. One interesting side effect of iteration is that it can make it harder to see the true scope of what you’ve delivered. Rather than a few big bang giant feature releases per year, a steady flow of iterative improvements requires taking a few steps back to look at all the work in aggregate to get a full sense of accomplishment. As we look forward to 2021, it’s worth a look back to see how far the [Threat Insights group](https://about.gitlab.com/handbook/product/categories/#threat-insights-group) has come with [Vulnerability Management](https://about.gitlab.com/direction/govern/threat_insights/vulnerability_management/) in the past year.\n\nThe year 2020 was filled with unprecedented challenges far beyond what most of us have ever experienced. The Threat Insights team formed against a backdrop of uncertainty with a global pandemic just starting to spread. Most of our team joined GitLab last year. We took over a fledgling area of the product that was off to a good start but hadn’t had a dedicated team to push it forward. Many of us—myself included—had security experience yet little to no background in vulnerability management. In short: we faced a daunting challenge.\n\nInitially, progress was slow as we took inventory of the current state of Vulnerability Management. We gathered input from others who worked on existing functionality. Early on, we determined that a major architectural upgrade to how GitLab stored vulnerability data from pipeline jobs was essential to do first. It took several months of hard work that culminated in [Standalone Vulnerability Objects](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#standalone-vulnerability-objects) debuting in GitLab 13.0 in May.\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/2020-a-year-of-iteration/project-security-dashboard-early-2020.png){: .shadow}\nProject-level Vulnerability Management in early 2020\n{: .note.text-center}\n\nYou may be wondering how a post that started by talking about iteration fits with spending a few months for one big change. Sometimes there are necessary exceptions where iterative releases would be more disruptive to users. Because we were changing the underlying storage model for vulnerability data, it was critical to upgrade all components of Vulnerability Management together. Otherwise, the experience for our users would have been inconsistent and confusing. We did still develop the new vulnerability object model iteratively; however, the work was held back behind a (large) feature flag until all pieces were complete and we could publicly release them simultaneously.\n\nThe Standalone Vulnerability Objects release was a major step forward technically. It also brought about another key milestone: Vulnerability Management’s [maturity](https://about.gitlab.com/direction/maturity/) officially moved to Minimal. Reaching Minimal signaled our category now had a complete foundation on which our users could build their vulnerability management and remediation programs. Getting this key piece of architecture in place further marked a turning point in our team’s ability to start quickly delivering new features built on top of it.\n\nTo illustrate how much the team accomplished just since 13.0, here are some highlights from our May-December progress:\n\n* 10 release post-worthy new features\n* Over 40 total new features and enhancements to existing features\n* Numerous new GraphQL endpoints (and one of the first teams to go GraphQL-first)\n* Over 150 bugs squashed\n* Numerous technical and performance improvements\n\nWe transformed the Group- and Project-level Security Dashboards into separate experiences for dashboarding and working with vulnerability lists. We created a personal [Security Center](https://about.gitlab.com/releases/2020/09/22/gitlab-13-4-released/#security-center). We made managing vulnerabilities a more seamless part of an integrated DevSecOps workflow with new features like [linking existing issues to vulnerabilities](https://about.gitlab.com/releases/2020/08/22/gitlab-13-3-released/#link-existing-issues-to-a-vulnerability), [showing pipeline status on Project Security Dashboards](https://about.gitlab.com/releases/2020/11/22/gitlab-13-6-released/#pipeline-status-in-project-security-dashboard), and adding [Special references for vulnerabilities](https://about.gitlab.com/releases/2020/12/22/gitlab-13-7-released/#special-references-for-vulnerabilities). And, perhaps most impressively, Vulnerability Management reached the next maturity level of Viable a mere 7 months after reaching Minimal—and a month ahead of plan. Reaching Viable so quickly is an especially big achievement since it requires successfully passing a [research-based maturity evaluation process](https://about.gitlab.com/handbook/product/ux/category-maturity/category-maturity-scorecards/) with real users.\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/2020-a-year-of-iteration/project-security-dashboard-december-2020.png){: .shadow}\nProject-level Vulnerability Management in December 2020\n{: .note.text-center}\n\nLast year, many of us were stuck at home, our routines becoming monotonous with days seeming to blur together. It’s easy to get lost in the day-to-day. This can make it difficult to see just how much forward progress might actually be happening. Taking time to inventory our accomplishments highlights that we achieved quite a bit in a few short months. This perspective of hindsight makes it clear just how far we’ve come. None of this would have been possible without hard work and dedication by the talented Threat Insights team. As we look forward to 2021, I’m excited about [what lies ahead](https://about.gitlab.com/direction/govern/threat_insights/vulnerability_management/). Expect even more big things—in monthly iterations—from Threat Insights!\n\nCover image by \u003Ca href=\"https://unsplash.com/@marcello54?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Marcello Gennari\u003C/a> on \u003Ca href=\"https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Unsplash\u003C/a>\n{: .note}\n","unfiltered",[9,716,717],"security","collaboration",{"slug":719,"featured":6,"template":696},"a-year-of-iteration","content:en-us:blog:a-year-of-iteration.yml","A Year Of Iteration","en-us/blog/a-year-of-iteration.yml","en-us/blog/a-year-of-iteration",{"_path":725,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":726,"content":733,"config":743,"_id":745,"_type":13,"title":746,"_source":15,"_file":747,"_stem":748,"_extension":18},"/en-us/blog/android-publishing-with-gitlab-and-fastlane",{"title":727,"description":728,"ogTitle":729,"ogDescription":728,"noIndex":6,"ogImage":730,"ogUrl":731,"ogSiteName":683,"ogType":684,"canonicalUrls":731,"schema":732},"Publishing Android apps to Play Store with GitLab & fastlane","See how GitLab, together with fastlane, can build, sign, and publish apps for Android to the Google Play Store.","HPublishing Android apps to Play Store with GitLab & fastlane","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679918/Blog/Hero%20Images/android-fastlane-pipeline.png","https://about.gitlab.com/blog/android-publishing-with-gitlab-and-fastlane","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to publish Android apps to the Google Play Store with GitLab and fastlane\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jason Yavorska\"}],\n        \"datePublished\": \"2019-01-28\",\n      }",{"title":734,"description":728,"authors":735,"heroImage":730,"date":737,"body":738,"category":739,"tags":740},"How to publish Android apps to the Google Play Store with GitLab and fastlane",[736],"Jason Yavorska","2019-01-28","When we heard about [_fastlane_](https://fastlane.tools), an app automation\ntool for delivering iOS and Android builds, we wanted to give it a spin to\nsee if a combination of GitLab and _fastlane_ could help us bring our mobile\nbuild and deployment automation to the next level and make mobile\ndevelopment a bit easier. You can see an [actual production\ndeployment](https://gitlab.com/gitlab-org/gitter/gitter-android-app/pipelines/40768761)\nof the [Gitter Android\napp](https://gitlab.com/gitlab-org/gitter/gitter-android-app) that uses what\nwe'll be implementing in this blog post; suffice to say, the results were\nfantastic and we've become big believers that the combination of GitLab and\n_fastlane_ is a truly game-changing way for developers to [enable\nCI/CD](/topics/ci-cd/) (continuous integration and continuous delivery) for\ntheir mobile applications. With GitLab and _fastlane_ we're getting, with\nminimal effort:\n\n\n- Source control, project home, issue tracking, and everything else that\ncomes with GitLab.\n\n- Content and images (metadata) for Google Play Store listing managed in\nsource control.\n\n- Automatic signing, version numbers, and changelog.\n\n- Automatic publishing to `internal` distribution channel in Google Play\nStore.\n\n- Manual promotion through `alpha`, `beta`, and `production` channels.\n\n- Containerized build environment, available in GitLab's container registry.\n\n\nIf you'd like to jump ahead and see the finished product, you can take a\nlook at the already-completed Gitter for Android\n[.gitlab-ci.yml](https://gitlab.com/gitlab-org/gitter/gitter-android-app/blob/master/.gitlab-ci.yml),\n[build.gradle](https://gitlab.com/gitlab-org/gitter/gitter-android-app/blob/master/app/build.gradle),\n[Dockerfile](https://gitlab.com/gitlab-org/gitter/gitter-android-app/blob/master/Dockerfile),\nand [_fastlane_\nconfiguration](https://gitlab.com/gitlab-org/gitter/gitter-android-app/tree/master/fastlane).\n\n\n## Configuring _fastlane_\n\n\nWe'll begin first by setting up _fastlane_ in our project, make a couple key\nchanges to our Gradle configuration, and then wrap everything up in a GitLab\npipeline.\n\n\n_fastlane_ has pretty good\n[documentation](https://docs.fastlane.tools/getting-started/android/setup/)\nto get you started, and if you run into platform-specific trouble it's the\nfirst place to check, but to get under way you really just need to complete\na few straightforward steps.\n\n\n### Initializing your project\n\n\nFirst up, you need to get _fastlane_ installed locally and initialize your\nproduct. We're using the Ruby `fastlane` gem so you'll need Ruby on your\nsystem for this to work. You can read about [other install options in the\n_fastlane_\ndocumentation](https://docs.fastlane.tools/getting-started/android/setup/).\n\n\n``` ruby\n\nsource \"https://rubygems.org\"\n\n\ngem \"fastlane\"\n\n```\n\n\nOnce your Gemfile is updated, you can run `bundle update` to update/generate\nyour `Gemfile.lock`. From this point you can run _fastlane_ by typing\n`bundle exec fastlane`. Later, you'll see that in CI/CD we use `bundle\ninstall ...` to ensure the command runs within the context of our project\nenvironment.\n\n\nNow that we have _fastlane_ ready to run, we just need to initialize our\nrepo with our configuration. Run `bundle exec fastlane init` from within\nyour project directory, answer a few questions, and _fastlane_ will create a\nnew `./fastlane` directory containing its configuration.\n\n\n### Setting up _supply_\n\n\n_supply_ is a feature built into _fastlane_ which will help you manage\nscreenshots, descriptions, and other localized metadata/assets for\npublishing to the Google Play Store.\n\n\nPlease refer to these [detailed instructions for collecting the credentials\nnecessary to run\n_supply_](https://docs.fastlane.tools/getting-started/android/setup/#setting-up-supply).\n\n\nOnce you've set this up, simply run `bundle exec fastlane supply init` and\nall your current metadata will be downloaded from your store listing and\nsaved in `fastlane/metadata/android`. From this point you're able to manage\nall of your store content as-code; when we publish a new version to the\nstore later, the versions of content checked into your source repo will be\nused to populate the entry.\n\n\n### Appfile\n\n\nThe `./fastlane/Appfile` is pretty straightforward, and contains basic\nconfiguration you chose when you initialized your project. Later we'll see\nhow to inject the `json_key_file` in your CI/CD pipeline at runtime.\n\n\n`./fastlane/Appfile`\n\n``` yaml\n\njson_key_file(\"~/google_play_api_key.json\") # Path to the json secret file -\nFollow https://docs.fastlane.tools/actions/supply/#setup to get one\n\npackage_name(\"im.gitter.gitter\") # e.g. com.krausefx.app\n\n```\n\n\n### Fastfile\n\n\nThe `./fastlane/Fastfile` is more interesting, and contains the first\nchanges you'll see that we made for Gitter vs. the default one created when\nyou run `bundle exec fastlane init`.\n\n\nThe first section contains our definitions for how we want to run builds and\ntests. As you can see, this is pretty straightforward and builds right on\ntop of your already set up Gradle tasks.\n\n\n`./fastlane/Fastfile`\n\n``` yaml\n\ndefault_platform(:android)\n\n\nplatform :android do\n\n  desc \"Builds the debug code\"\n  lane :buildDebug do\n    gradle(task: \"assembleDebug\")\n  end\n\n  desc \"Builds the release code\"\n  lane :buildRelease do\n    gradle(task: \"assembleRelease\")\n  end\n\n  desc \"Runs all the tests\"\n  lane :test do\n    gradle(task: \"test\")\n  end\n\n...\n\n```\n\n\nCreating Gradle tasks that publish/promote builds can be complicated and\nerror prone, but _fastlane_ makes this much easier by giving you pre-built\ncommands (called _fastlane_ actions) that let you perform complex tasks with\njust a few simple actions.\n\n\nIn our example, we've set up a workflow where a new build can be published\nto the internal track and then optionally promoted through alpha, beta, and\nultimately production. We initially had a new build for each track but it's\nsafer to have the same/known build go through the whole process.\n\n\n``` yaml\n\n...\n\n  desc \"Submit a new Internal Build to Play Store\"\n  lane :internal do\n    upload_to_play_store(track: 'internal', apk: 'app/build/outputs/apk/release/app-release.apk')\n  end\n\n  desc \"Promote Internal to Alpha\"\n  lane :promote_internal_to_alpha do\n    upload_to_play_store(track: 'internal', track_promote_to: 'alpha')\n  end\n\n  desc \"Promote Alpha to Beta\"\n  lane :promote_alpha_to_beta do\n    upload_to_play_store(track: 'alpha', track_promote_to: 'beta')\n  end\n\n  desc \"Promote Beta to Production\"\n  lane :promote_beta_to_production do\n    upload_to_play_store(track: 'beta', track_promote_to: 'production')\n  end\nend\n\n```\n\n\nAn important note is that we've only scratched the surface of the kinds of\nactions that _fastlane_ can automate. You can [read more about available\nactions here](https://docs.fastlane.tools/actions/), and it's even possible\nto create your own.\n\n\n## Gradle configuration\n\n\nWe also made a couple of key changes to our basic Gradle configuration to\nmake publishing easier. Nothing major here, but it does help us make things\nrun a little more smoothly.\n\n\n### Secret properties\n\n\nThe first changed section gathers the secret variables to be used for\nsigning. These are either loaded via configuration file, or gathered from\nenvironment variables in the case of CI.\n\n\n`app/build.gradle`\n\n``` groovy\n\n// Try reading secrets from file\n\ndef secretsPropertiesFile = rootProject.file(\"secrets.properties\")\n\ndef secretProperties = new Properties()\n\n\nif (secretsPropertiesFile.exists()) {\n    secretProperties.load(new FileInputStream(secretsPropertiesFile))\n}\n\n// Otherwise read from environment variables, this happens in CI\n\nelse {\n    secretProperties.setProperty(\"oauth_client_id\", \"\\\"${System.getenv('oauth_client_id')}\\\"\")\n    secretProperties.setProperty(\"oauth_client_secret\", \"\\\"${System.getenv('oauth_client_secret')}\\\"\")\n    secretProperties.setProperty(\"oauth_redirect_uri\", \"\\\"${System.getenv('oauth_redirect_uri')}\\\"\")\n    secretProperties.setProperty(\"google_project_id\", \"\\\"${System.getenv('google_project_id') ?: \"null\"}\\\"\")\n    secretProperties.setProperty(\"signing_keystore_password\", \"${System.getenv('signing_keystore_password')}\")\n    secretProperties.setProperty(\"signing_key_password\", \"${System.getenv('signing_key_password')}\")\n    secretProperties.setProperty(\"signing_key_alias\", \"${System.getenv('signing_key_alias')}\")\n}\n\n```\n\n\n### Automatic versioning\n\n\nWe also set up automatic versioning using environment variables\n`VERSION_CODE`, `VERSION_SHA`, which we will set up later in CI/CD (locally\nthey will just be `null` which is fine). Because each build's `versionCode`\nthat you submit to the Google Play Store needs to be higher than the last,\nthis makes it simple to deal with.\n\n\n`app/build.gradle`\n\n``` groovy\n\nandroid {\n    defaultConfig {\n        applicationId \"im.gitter.gitter\"\n        minSdkVersion 19\n        targetSdkVersion 26\n        versionCode Integer.valueOf(System.env.VERSION_CODE ?: 0)\n        // Manually bump the semver version part of the string as necessary\n        versionName \"3.2.0-${System.env.VERSION_SHA}\"\n```\n\n\n### Signing configuration\n\n\nFinally, we inject the signing configuration which will automatically be\nused by Gradle to sign the release build. Depending on your configuration,\nyou may already be doing this. We only worry about signing in the release\nbuild that would potentially be published to the Google Play Store.\n\n\n> When using App Signing by Google Play, you will use two keys: the app\nsigning key and the upload key. You keep the upload key and use it to sign\nyour app for upload to the Google Play Store.\n\n>\n\n>\n[*https://developer.android.com/studio/publish/app-signing#google-play-app-signing*](https://developer.android.com/studio/publish/app-signing#google-play-app-signing)\n\n\n> IMPORTANT: Google will not re-sign any of your existing or new APKs that\nare signed with the app signing key. This enables you to start testing your\napp bundle in the internal test, alpha, or beta tracks while you continue to\nrelease your existing APK in production without Google Play changing it.\n\n>\n\n>\n*`https://play.google.com/apps/publish/?account=xxx#KeyManagementPlace:p=im.gitter.gitter&appid=xxx`*\n\n\n`app/build.gradle`\n\n``` groovy\n    signingConfigs {\n        release {\n            // You need to specify either an absolute path or include the\n            // keystore file in the same directory as the build.gradle file.\n            storeFile file(\"../android-signing-keystore.jks\")\n            storePassword \"${secretProperties['signing_keystore_password']}\"\n            keyAlias \"${secretProperties['signing_key_alias']}\"\n            keyPassword \"${secretProperties['signing_key_password']}\"\n        }\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            testCoverageEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            signingConfig signingConfigs.release\n        }\n    }\n}\n\n```\n\n\n## Setting up the Docker build environment\n\n\nWe are building a Docker image to be used as a repeatable, consistent build\nenvironment which will speed things up because it will already have the\ndependencies downloaded and installed. We're just fetching a few\nprerequisites, installing the Android SDK, and then grabbing _fastlane_.\n\n\n`Dockerfile`\n\n```dockerfile\n\nFROM openjdk:8-jdk\n\n\n# Just matched `app/build.gradle`\n\nENV ANDROID_COMPILE_SDK \"26\"\n\n# Just matched `app/build.gradle`\n\nENV ANDROID_BUILD_TOOLS \"28.0.3\"\n\n# Version from https://developer.android.com/studio/releases/sdk-tools\n\nENV ANDROID_SDK_TOOLS \"24.4.1\"\n\n\nENV ANDROID_HOME /android-sdk-linux\n\nENV PATH=\"${PATH}:/android-sdk-linux/platform-tools/\"\n\n\n# install OS packages\n\nRUN apt-get --quiet update --yes\n\nRUN apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1\nbuild-essential ruby ruby-dev\n\n# We use this for xxd hex->binary\n\nRUN apt-get --quiet install --yes vim-common\n\n# install Android SDK\n\nRUN wget --quiet --output-document=android-sdk.tgz\nhttps://dl.google.com/android/android-sdk_r${ANDROID_SDK_TOOLS}-linux.tgz\n\nRUN tar --extract --gzip --file=android-sdk.tgz\n\nRUN echo y | android-sdk-linux/tools/android --silent update sdk --no-ui\n--all --filter android-${ANDROID_COMPILE_SDK}\n\nRUN echo y | android-sdk-linux/tools/android --silent update sdk --no-ui\n--all --filter platform-tools\n\nRUN echo y | android-sdk-linux/tools/android --silent update sdk --no-ui\n--all --filter build-tools-${ANDROID_BUILD_TOOLS}\n\nRUN echo y | android-sdk-linux/tools/android --silent update sdk --no-ui\n--all --filter extra-android-m2repository\n\nRUN echo y | android-sdk-linux/tools/android --silent update sdk --no-ui\n--all --filter extra-google-google_play_services\n\nRUN echo y | android-sdk-linux/tools/android --silent update sdk --no-ui\n--all --filter extra-google-m2repository\n\n# install Fastlane\n\nCOPY Gemfile.lock .\n\nCOPY Gemfile .\n\nRUN gem install bundle\n\nRUN bundle install\n\n```\n\n\n## Setting up GitLab\n\n\nWith our build environment ready, let's set up our `.gitlab-ci.yml` to tie\nit all together in a CI/CD pipeline.\n\n\n### Stages\n\n\nThe first thing we do is define the stages that we're going to use. We'll\nset up our build environment, do our debug and release builds, run our\ntests, deploy to internal, and then promote through alpha, beta, and\nproduction. You can see that, apart from `environment`, these map to the\nlanes we set up in our `Fastfile`.\n\n\n``` yaml\n\nstages:\n  - environment\n  - build\n  - test\n  - internal\n  - alpha\n  - beta\n  - production\n```\n\n\n### Build environment update\n\n\nNext up we're going to update our build environment, if needed. If you're\nnot familiar with `.gitlab-ci.yml` it may look like there's a lot going on\nhere, but we'll take it one step at a time. The very first thing we do is\nset up an `.updateContainerJob` yaml template which can be used to capture\nshared configuration for other steps that want to use it. In this case, it\nwill be used by the subsequent `updateContainer` and `ensureContainer` jobs.\n\n\n#### `.updateContainerJob` template\n\n\nIn this case, since we're dealing with Docker in Docker (`dind`), we are\nrunning some scripts which log into the local [GitLab container\nregistry](https://docs.gitlab.com/ee/user/packages/container_registry/index.html),\nfetch the latest image to be used as a layer cache reference, build a new\nimage, and finally push the new version to the registry.\n\n\n``` yaml\n\n.updateContainerJob:\n  image: docker:stable\n  stage: environment\n  services:\n    - docker:dind\n  script:\n    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY\n    - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG || true\n    - docker build --cache-from $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG .\n    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n```\n\n\n#### `updateContainer` job\n\n\nThe first job that inherits `.updateContainerJob`, `updateContainer`, only\nruns if the `Dockerfile` was updated and will run through the template steps\ndescribed above.\n\n\n``` yaml\n\nupdateContainer:\n  extends: .updateContainerJob\n  only:\n    changes:\n      - Dockerfile\n```\n\n\n#### `ensureContainer` job\n\n\nBecause the first pipeline on a branch can fail, the `only: changes:\nDockerfile` syntax won't trigger for a subsequent pipeline after you fix\nthings. This can leave your branch without a Docker image to use. So the\n`ensureContainer` job will look for an existing image and only build one if\nit doesn't exist. The one downside to this is that both of these jobs will\nrun at the same time if it is a new branch.\n\n\nIdeally, we could just use `$CI_REGISTRY_IMAGE:master` as a fallback when\n`$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG` isn't found but there isn't any\nsyntax for this.\n\n\n``` yaml\n\nensureContainer:\n  extends: .updateContainerJob\n  allow_failure: true\n  before_script:\n    - \"mkdir -p ~/.docker && echo '{\\\"experimental\\\": \\\"enabled\\\"}' > ~/.docker/config.json\"\n    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY\n    # Skip update container `script` if the container already exists\n    # via https://gitlab.com/gitlab-org/gitlab-ce/issues/26866#note_97609397 -> https://stackoverflow.com/a/52077071/796832\n    - docker manifest inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG > /dev/null && exit || true\n```\n\n\n### Build and test\n\n\nWith our build environment ready, we're ready to build our `debug` and\n`release` targets. Similar to above, we use a template to set up repeated\nsteps within our build jobs, avoiding duplication. Within this section, the\nfirst thing we do is set the image to the build environment container image\nwe built in the previous step.\n\n\n#### `.build_job` template\n\n\n``` yaml\n\n.build_job:\n  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n  stage: build\n\n...\n\n```\n\n\nNext up is a step that's specific to Gitter, but if you use shared assets\nbetween a iOS and Android build you might consider doing something similar.\nWhat we're doing here is grabbing the latest mobile artifacts built by the\nweb application pipeline and placing them in the appropriate location.\n\n\n``` yaml\n  before_script:\n    - wget --output-document=artifacts.zip --quiet \"https://gitlab.com/gitlab-org/gitter/webapp/-/jobs/artifacts/master/download?job=mobile-asset-build\"\n    - unzip artifacts.zip\n    - mkdir -p app/src/main/assets/www\n    - mv output/android/www/* app/src/main/assets/www/\n```\n\n\nNext, we use [project-level\nvariables](https://docs.gitlab.com/ee/ci/variables/) containing a binary\n(hex) dump of our signing keystore file and convert it back to a binary\nfile. This allows us to inject the file into the build at runtime instead of\nchecking it into source control, a potential security concern. To get the\n`signing_jks_file_hex` variable hex value, we use this binary -> hex\ncommand, `xxd -p gitter-android-app.jks`\n\n\n``` yaml\n    # We store this binary file in a variable as hex with this command, `xxd -p gitter-android-app.jks`\n    # Then we convert the hex back to a binary file\n    - echo \"$signing_jks_file_hex\" | xxd -r -p - > android-signing-keystore.jks\n```\n\n\nHere we're setting the version at runtime – these environment variables will\nbe used by the Gradle build as implemented above. Because `$CI_PIPELINE_IID`\nincrements on each pipeline, we can guarantee our `versionCode` is always\nhigher than the last and be able to publish to the Google Play Store.\n\n\n``` yaml\n    # We add 100 to get this high enough above current versionCodes that are published\n    - \"export VERSION_CODE=$((100 + $CI_PIPELINE_IID)) && echo $VERSION_CODE\"\n    - \"export VERSION_SHA=`echo ${CI_COMMIT_SHORT_SHA}` && echo $VERSION_SHA\"\n```\n\n\nNext, we automatically generate a changelog to include by copying whatever\nyou have in `CURRENT_VERSION.txt` to the current `\u003CversionCode>.text`. You\ncan update `CURRENT_VERSION.txt` as necessary. I won't dive into the details\nof the merge request (MR) creation script here since it's somewhat specific\nto Gitter, but if you're interested in how something like this might work\ncheck out the [`create-changlog-mr.sh`\nscript](https://gitlab.com/gitlab-org/gitter/gitter-android-app/blob/master/ci-scripts/create-changlog-mr.sh).\n\n\n``` yaml\n    # Make the changelog\n    - cp ./fastlane/metadata/android/en-GB/changelogs/CURRENT_VERSION.txt \"./fastlane/metadata/android/en-GB/changelogs/$VERSION_CODE.txt\"\n    # We allow the remote push and MR creation to fail because the other job could create it\n    # and it's not strictly necessary (we just need the file locally for the CI/CD build)\n    - ./ci-scripts/create-changlog-mr.sh || true\n    # Because we allow the MR creation to fail, just make sure we are back in the right repo state\n    - git checkout \"$CI_COMMIT_SHA\"\n```\n\n\nJust a couple of final items: First, whenever a build job is done, we remove\nthe jks file just to be sure it doesn't get saved to artifacts, and second\nwe set up the artifact directory from where the output of the build (`.apk`)\nwill be saved.\n\n\n``` yaml\n  after_script:\n    - rm android-signing-keystore.jks || true\n  artifacts:\n    paths:\n    - app/build/outputs\n```\n\n\n#### `buildDebug` and `buildRelease` jobs\n\n\nMost of the complexity here was set up in the template, so as you can see\nour `buildDebug` and `buildRelease` job definitions are very clear. Both\njust call the appropriate _fastlane_ task (which, if you remember, then\ncalls the appropriate Gradle task). The `buildRelease` output is associated\nwith the `production` environment so we can define an extra\nproduction-scoped set of [project-level\nvariables](https://docs.gitlab.com/ee/ci/variables/) which are different\nfrom our testing variables.\n\n\nSince we set up code signing in the Gradle config (`build.gradle`) earlier,\nwe can be confident here that our `release` builds are appropriately signed\nand ready for publishing.\n\n\n```\n\nbuildDebug:\n  extends: .build_job\n  script:\n    - bundle exec fastlane buildDebug\n\nbuildRelease:\n  extends: .build_job\n  script:\n    - bundle exec fastlane buildRelease\n  environment:\n    name: production\n```\n\n\nTesting is really just another instance of the same thing, but instead of\ncalling one of the build lanes we call the test lane. Note that we are using\na `dependency` from the `buildDebug` job to ensure we don't need to rebuild\nanything.\n\n\n``` yaml\n\ntestDebug:\n  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n  stage: test\n  dependencies:\n    - buildDebug\n  script:\n    - bundle exec fastlane test\n```\n\n\n### Publish\n\n\nNow that our code is being built, we're ready to publish to the Google Play\nStore. We only *publish* to the `internal` testing track and *promote* this\nsame build to the rest of the tracks.\n\n\nThis is achieved through the _fastlane_ integration, using a pre-built\naction to handle the job. In this case we are using a `dependency` on the\n`buildRelease` job, and creating a local copy of the Google API JSON keyfile\n(again stored in a [project-level\nvariable](https://docs.gitlab.com/ee/ci/variables/) instead of checking it\ninto source control.) We have this job (and all subsequent jobs) set to run\nonly on `manual` action so we have full human control/intervention from this\npoint forward. If you prefer to continuously deliver to your `internal`\ntrack you'd simply need to remove the `when: manual` entry and you'd have\nachieved your goal.\n\n\nIf you're like me, this may seem too easy to work. With everything we've\nconfigured in GitLab and _fastlane_ to this point, it's really this simple!\n\n\n``` yaml\n\npublishInternal:\n  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n  stage: internal\n  dependencies:\n    - buildRelease\n  when: manual\n  before_script:\n    - echo $google_play_service_account_api_key_json > ~/google_play_api_key.json\n  after_script:\n    - rm ~/google_play_api_key.json\n  script:\n    - bundle exec fastlane internal\n```\n\n\n### Promote\n\n\nAs indicated earlier, promotion through alpha, beta, and production are all\n`manual` jobs. If internal testing is good, it can be promoted one step\nforward in sequence all the way through to production using these manual\njobs.\n\n\nIf you're with me to this point, there's really nothing new here and this\nreally highlights the power of GitLab with _fastlane_. We have a\n`.promote_job` template job which creates the local Google API JSON key file\nand the promote jobs themselves are basically identical.\n\n\n``` yaml\n\n.promote_job:\n  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n  when: manual\n  dependencies: []\n  only:\n    - master\n  before_script:\n    - echo $google_play_service_account_api_key_json > ~/google_play_api_key.json\n  after_script:\n    - rm ~/google_play_api_key.json\n\npromoteAlpha:\n  extends: .promote_job\n  stage: alpha\n  script:\n    - bundle exec fastlane promote_internal_to_alpha\n\npromoteBeta:\n  extends: .promote_job\n  stage: beta\n  script:\n    - bundle exec fastlane promote_alpha_to_beta\n\npromoteProduction:\n  extends: .promote_job\n  stage: production\n  script:\n    - bundle exec fastlane promote_beta_to_production\n```\n\n\nNote that we're `only` allowing production promotion from the `master`\nbranch, instead of from any branch. This is to ensure that the production\nbuild uses the separate set of `production` environment variables which only\nhappens for the `buildRelease` job. We also have these [variables set as\nprotected](https://docs.gitlab.com/ee/ci/variables/#protected-variables) so\nwe can enforce that they are only used on the `master` branch which is\nprotected.\n\n\n### Variables\n\n\nThe last step is to make sure you set up the [project-level\nvariables](https://docs.gitlab.com/ee/ci/variables/) we used throughout the\nconfiguration above:\n\n - `google_play_service_account_api_key_json`: see [https://docs.fastlane.tools/getting-started/android/setup/#collect-your-google-credentials](https://docs.fastlane.tools/getting-started/android/setup/#collect-your-google-credentials)\n - `oauth_client_id`\n - `oauth_client_id`, protected, `production` environment\n - `oauth_client_secret`\n - `oauth_client_secret`, protected, `production` environment\n - `oauth_redirect_uri`\n - `oauth_redirect_uri`, protected, `production` environment\n - `signing_jks_file_hex`: `xxd -p gitter-android-app.jks`\n - `signing_key_alias`\n - `signing_key_password`\n - `signing_keystore_password`\n\nIf you are using the same [`create-changlog-mr.sh`\nscript](https://gitlab.com/gitlab-org/gitter/gitter-android-app/blob/master/ci-scripts/create-changlog-mr.sh)\nas us,\n\n - `deploy_key_android_repo`: see [https://docs.gitlab.com/ee/user/project/deploy_tokens/](https://docs.gitlab.com/ee/user/project/deploy_tokens/)\n - `gitlab_api_access_token`: see [https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) (we use a bot user)\n\n![Project variables for Gitter for\nAndroid](https://about.gitlab.com/images/blogimages/android-fastlane-variables.png){:\n.shadow.medium.center}\n\n\n## What's next\n\n\nUsing this configuration we've got Gitter for Android building, signing,\ndeploying to our internal track, and publishing to production as frequently\nas we like. Next up will be to do the same for iOS, so watch this space for\nour next post!\n\n\nPhoto by [Patrick Tomasso](https://unsplash.com/@impatrickt) on\n[Unsplash](https://unsplash.com/photos/KGcLJwIYiac)\n\n{: .note}\n","engineering",[108,9,741,742],"google","features",{"slug":744,"featured":6,"template":696},"android-publishing-with-gitlab-and-fastlane","content:en-us:blog:android-publishing-with-gitlab-and-fastlane.yml","Android Publishing With Gitlab And Fastlane","en-us/blog/android-publishing-with-gitlab-and-fastlane.yml","en-us/blog/android-publishing-with-gitlab-and-fastlane",{"_path":750,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":751,"content":757,"config":765,"_id":767,"_type":13,"title":768,"_source":15,"_file":769,"_stem":770,"_extension":18},"/en-us/blog/api-v3-removal-impending",{"title":752,"description":753,"ogTitle":752,"ogDescription":753,"noIndex":6,"ogImage":754,"ogUrl":755,"ogSiteName":683,"ogType":684,"canonicalUrls":755,"schema":756},"Breaking change: Support for API v3 will be removed June 4","With the removal of deprecated GitLab API v3 in GitLab 11.0, requests to the API v3 will fail.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663397/Blog/Hero%20Images/logoforblogpost.jpg","https://about.gitlab.com/blog/api-v3-removal-impending","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Breaking change: Support for API v3 will be removed June 4\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"James Ramsay\"}],\n        \"datePublished\": \"2018-06-01\",\n      }",{"title":752,"description":753,"authors":758,"heroImage":754,"date":760,"body":761,"category":298,"tags":762},[759],"James Ramsay","2018-06-01","\nOn June 4, 2018 integrations using API v3 connected to GitLab.com will stop\nworking. With the release of GitLab 11 on June 22, 2018 the API v3 will be\nremoved completely. **Update all integrations before June 4 to avoid downtime.**\n\n\u003C!-- more -->\n\nIn the GitLab 8.17 release post, we announced the [deprecation of API v3](/releases/2017/02/22/gitlab-8-17-released/), and that support for API\nv3 would be dropped in a future release.\n\nPlease ensure that you upgrade any integrations to API v4 to avoid any\ndowntime. Documentation is available for [upgrading from v3 to v4](https://docs.gitlab.com/ee/update/).\n\n## When will this happen?\n\nThe API v3 will be removed in GitLab 11.0 on 22 June, 2018.\nPlease consider that integrations using API v3 connected to GitLab.com will\nstop working as soon as the first RC is deployed to production, and this will\nhappen around 4 June, 2018. **Update all integrations before this date**.\n",[763,764,9],"news","releases",{"slug":766,"featured":6,"template":696},"api-v3-removal-impending","content:en-us:blog:api-v3-removal-impending.yml","Api V3 Removal Impending","en-us/blog/api-v3-removal-impending.yml","en-us/blog/api-v3-removal-impending",{"_path":772,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":773,"content":779,"config":786,"_id":788,"_type":13,"title":789,"_source":15,"_file":790,"_stem":791,"_extension":18},"/en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean",{"title":774,"description":775,"ogTitle":774,"ogDescription":775,"noIndex":6,"ogImage":776,"ogUrl":777,"ogSiteName":683,"ogType":684,"canonicalUrls":777,"schema":778},"How to autoscale continuous deployment with GitLab Runner on DigitalOcean","Our friends over at DigitalOcean share how to configure a highly scalable, responsive and cost-effective GitLab infrastructure.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680042/Blog/Hero%20Images/gitlab-digitalocean-cover.jpg","https://about.gitlab.com/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to autoscale continuous deployment with GitLab Runner on DigitalOcean\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Owen Williams\"}],\n        \"datePublished\": \"2018-06-19\",\n      }",{"title":774,"description":775,"authors":780,"heroImage":776,"date":782,"body":783,"category":739,"tags":784},[781],"Owen Williams","2018-06-19","[GitLab CI/CD](/solutions/continuous-integration/) is an effective way to\nbuild the habit of testing all code before it’s deployed. GitLab CI/CD is\nalso highly scalable thanks to an additional tool, GitLab Runner, which\nautomates scaling your build queue in order to avoid long wait times for\ndevelopment teams trying to release code.\n\n\nIn this guide, we will demonstrate how to configure a highly scalable GitLab\ninfrastructure that manages its own costs, and automatically responds to\nload by increasing and decreasing available server capacity.\n\n\n## Goals\n\n\nWe’re going to build a scalable CI/CD process on DigitalOcean that\nautomatically responds to demand by creating new servers on the platform and\ndestroys them when the queue is empty.\n\n\nThese reusable servers are spawned by the GitLab Runner process and are\nautomatically deleted when no jobs are running, reducing costs and\nadministration overhead for your team.\n\n\nAs we’ll explain in this tutorial, you are in control of how many machines\nare created at any given time, as well as the length of time they’re\nretained before being destroyed.\n\n\nWe’ll be using three separate servers to build this project, so let’s go\nover terminology first:\n\n\n* **GitLab**: Your hosted GitLab instance or self-managed instance where\nyour code repositories are stored.\n\n\n* **GitLab Bastion**: The *bastion* server or Droplet is the core of what\nwe’ll be configuring. It is the control instance that is used to interact\nwith the DigitalOcean API to create Droplets and destroy them when\nnecessary. No jobs are executed on this server.\n\n\n* **GitLab Runner**: Your *runners* are transient servers or Droplets that\nare created on the fly by the *bastion* server when needed to execute a\nCI/CD job in your build queue. These servers are disposable, and are where\nyour code is executed or tested before your build is marked as passing or\nfailing.\n\n\n![GitLab Runners\nDiagram](https://assets.digitalocean.com/articles/gitlab-runner/Autoscaling-GitLab-Runners.png){:\n.medium.center}\n\n\nBy leveraging each of the GitLab components, the CI/CD process will enable\nyou to scale responsively based on demands. With these goals in mind, we are\nready to begin setting up our [continuous deployment](/topics/ci-cd/) with\nGitLab and DigitalOcean.\n\n\n## Prerequisites\n\n\nThis tutorial will assume you have already configured GitLab on your own\nserver or through the hosted service, and that you have an existing\nDigitalOcean account.\n\n\nTo set this up on an Ubuntu 16.04 Droplet, you can use the DigitalOcean\none-click image, or follow our guide: “[How To Install and Configure GitLab\non Ubuntu\n16.04](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-gitlab-on-ubuntu-16-04).”\n\n\nFor the purposes of this tutorial, we assume you have private networking\nenabled on this Droplet, which you can achieve by following our guide on\n“[How To Enable DigitalOcean Private Networking on Existing\nDroplets](https://www.digitalocean.com/community/tutorials/how-to-enable-digitalocean-private-networking-on-existing-droplets),”\nbut it is not compulsory.\n\n\nThroughout this tutorial, we’ll be using non-root users with admin\nprivileges on our Droplets.\n\n\n## Step 1: Import JavaScript project\n\nTo begin, we will create a new example project in your existing GitLab\ninstance containing a sample Node.js application.\n\n\n![GitLab\ninterface](https://assets.digitalocean.com/articles/gitlab-runner/gitlab.jpg){:\n.shadow.large.center}\n\n\nLog into your GitLab instance and click the **plus icon**, then select **New\nproject** from the dropdown menu.\n\n\nOn the new project screen, select the **Import project** tag, then click\n**Repo by URL** to import our example project directly from GitHub.\n\n\nPaste the below clone URL into the Git repository URL:\n\n\n```bash\n\nhttps://github.com/do-community/hello_hapi.git\n\n```\n\n\nThis repository is a basic JavaScript application for the purposes of\ndemonstration, which we won’t be running in production. To complete the\nimport, click the **New Project** button.\n\n\nYour new project will now be in GitLab and we can get started setting up our\nCI pipeline.\n\n\n## Step 2: Set up infrastructure\n\n\nOur GitLab Code Runner requires specific configuration as we’re planning to\nprogrammatically create Droplets to handle CI load as it grows and shrinks.\n\n\nWe will create two types of machines in this tutorial: a **bastion**\ninstance, which controls and spawns new machines, and our **runner**\ninstances, which are temporary servers spawned by the bastion Droplet to\nbuild code when required. The bastion instance uses Docker to create your\nrunners.\n\n\nHere are the DigitalOcean products we’ll use, and what each component is\nused for:\n\n\n* **Flexible Droplets** — We will create memory-optimized Droplets for our\nGitLab Runners as it’s a memory-intensive process which will run using\nDocker for containerization. You can shrink or grow this Droplet in the\nfuture as needed, however we recommend the flexible Droplet option as a\nstarting point to understand how your pipeline will perform under load.\n\n\n* **DigitalOcean Spaces (Object Storage)** — We will use [DigitalOcean\nSpaces](https://www.digitalocean.com/products/spaces/) to persist cached\nbuild components across your runners as they’re created and destroyed. This\nreduces the time required to set up a new runner when the CI pipeline is\nbusy, and allows new runners to pick up where others left off immediately.\n\n\n* **Private Networking** — We will create a private network for your bastion\nDroplet and GitLab runners to ensure secure code compilation and to reduce\nfirewall configuration required.\n\n\nTo start, we’ll create the bastion Droplet. Create a [new\nDroplet](https://cloud.digitalocean.com/droplets/new), then under **choose\nan image**, select the **One-click apps** tab. From there, select **Docker\n17.12.0-ce on 16.04** (note that this version is current at the time of\nwriting), then choose the smallest Droplet size available, as our bastion\nDroplet will manage the creation of other Droplets rather than actually\nperform tests.\n\n\nIt is recommended that you create your server in a data center that\nincludes  [DigitalOcean\nSpaces](https://www.digitalocean.com/community/tutorials/an-introduction-to-digitalocean-spaces)\nin order to use the object storage caching features mentioned earlier.\n\n\nSelect both the **Private networking** and **Monitoring** options, then\nclick **Create Droplet**.\n\n\nWe also need to set up our storage space which will be used for caching.\nFollow the steps in “[How To Create a DigitalOcean Space and API\nKey](https://www.digitalocean.com/community/tutorials/how-to-create-a-digitalocean-space-and-api-key)”\nto create a new Space in the same or nearest data center as your hosted\nGitLab instance, along with an API Key.\n\n\nNote this key down, as we’ll need it later in the tutorial.\n\n\nNow it’s time to get our CI started!\n\n\n## Step 3: Configure the GitLab Runner Bastion Server\n\n\nWith the fresh Droplet ready, we can now configure GitLab Runner. We’ll be\ninstalling scripts from GitLab and GitHub repositories.\n\n\nAs a best practice, be sure to inspect scripts to confirm what you will be\ninstalling prior to running the full commands below.\n\n\nConnect to the Droplet using SSH, move into the `/tmp` directory, then add\nthe [official GitLab Runner\nrepository](https://docs.gitlab.com/runner/install/linux-repository.html) to\nUbuntu’s package manager:\n\n\n```bash\n\ncd /tmp\n\ncurl -L\nhttps://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh\n| sudo bash\n\n```\n\n\nOnce added, install the GitLab Runner application:\n\n\n```bash\n\nsudo apt-get install gitlab-runner\n\n```\n\n\nWe also need to install **[Docker\nMachine](https://docs.docker.com/machine/install-machine/#install-machine-directly)**,\nwhich is an additional Docker tool that assists with automating the\ndeployment of containers on cloud providers:\n\n\n```bash\n\ncurl -L\nhttps://github.com/docker/machine/releases/download/v0.14.0/docker-machine-`uname\n-s`-`uname -m` >/tmp/docker-machine && \\\n\nsudo install /tmp/docker-machine /usr/local/bin/docker-machine\n\n```\n\n\nWith these installations complete, we can move on to connecting our GitLab\nRunner to our GitLab install.\n\n\n## Step 4: Obtain Runner registration token\n\n\nTo link GitLab Runner to your existing GitLab install, we need to link the\ntwo instances together by obtaining a token that authenticates your runner\nto your code repositories.\n\n\nLogin to your existing GitLab instance as the admin user, then click the\nwrench icon to enter the admin settings area.\n\n\nOn the left of your screen, hover over **Overview** and select **Runners**\nfrom the list that appears.\n\n\nOn the Runners page under the **How to set up a shared Runner for a new\nproject** section, copy the token shown in Step 3, and make a note of it\nalong with the publicly accessible URL of your GitLab instance from Step 2.\nIf you are using HTTPS for Gitlab, make sure it is not a self-signed\ncertificate, or GitLab Runner will fail to start.\n\n\n## Step 5: Configure GitLab on the Bastion Droplet\n\n\nBack in your SSH connection with your bastion Droplet, run the following\ncommand:\n\n\n```bash\n\nsudo gitlab-runner register\n\n```\n\n\nThis will initiate the linking process, and you will be asked a series of\nquestions.\n\n\nOn the next step, enter the **GitLab instance URL** from the previous step:\n\n\n```bash\n\nPlease enter the gitlab-ci coordinator URL (e.g. https://gitlab.com)\n\nhttps://example.digitalocean.com\n\n```\n\n\nEnter the token you obtained from your GitLab instance:\n\n\n```bash\n\nPlease enter the gitlab-ci token for this runner\n\nsample-gitlab-ci-token\n\n```\n\n\nEnter a description that will help you recognize it in the GitLab web\ninterface. We recommend naming this instance something unique, like\n`runner-bastion` for clarity.\n\n\n```bash\n\nPlease enter the gitlab-ci description for this runner\n\n[yourhostname] runner-bastion\n\n```\n\n\nIf relevant, you may enter the tags for code you will build with your\nrunner. However, we recommend this is left blank at this stage. This can\neasily be changed from the GitLab interface later.\n\n\n```bash\n\nPlease enter the gitlab-ci tags for this runner (comma separated):\n\ncode-tag\n\n```\n\n\nChoose whether or not your runner should be able to run untagged jobs. This\nsetting allows you to choose whether your runner should build repositories\nwith no tags at all, or require specific tags. Select true in this case, so\nyour runner can execute all repositories.\n\n\n```bash\n\nWhether to run untagged jobs [true/false]: true\n\n```\n\n\nChoose if this runner should be shared among your projects, or locked to the\ncurrent one, which blocks it from building any code other than those\nspecified. Select false for now, as this can be changed later in GitLab’s\ninterface:\n\n\n```bash\n\nWhether to lock Runner to current project [true/false]: false\n\n```\n\n\nChoose the executor which will build your machines. Because we’ll be\ncreating new Droplets using Docker, we’ll choose `docker+machine` here, but\nyou can read more about the advantages of each approach in this\n[compatibility\nchart](https://docs.gitlab.com/runner/executors/README.html#compatibility-chart):\n\n\n```bash\n\nPlease enter the executor: ssh, docker+machine, docker-ssh+machine,\nkubernetes, docker, parallels, virtualbox, docker-ssh, shell:\n\ndocker+machine\n\n```\n\n\nYou’ll be asked which image to use for projects that don’t explicitly define\none. We’ll choose a basic, secure default:\n\n\n```bash\n\nPlease enter the Docker image (e.g. ruby:2.1):\n\nalpine:latest\n\n```\n\n\nNow you’re done configuring the core bastion runner! At this point it should\nappear within the GitLab Runner page of your GitLab admin settings, which we\naccessed to obtain the token.\n\n\nIf you encounter any issues with these steps, the [GitLab Runner\ndocumentation](https://docs.gitlab.com/runner/register/index.html) includes\noptions for troubleshooting.\n\n\n## Step 6: Configure Docker caching and Docker Machine\n\nTo speed up Droplet creation when the build queue is busy, we’ll leverage\nDocker’s caching tools on the Bastion Droplet to store the images for your\ncommonly used containers on DigitalOcean Spaces.\n\n\nTo do so, upgrade Docker Machine on your SSH shell using the following\ncommand:\n\n\n```bash\n\ncurl -L\nhttps://github.com/docker/machine/releases/download/v0.14.0/docker-machine-`uname\n-s`-`uname -m` >/tmp/docker-machine && sudo install /tmp/docker-machine\n/usr/local/bin/docker-machine\n\n```\n\n\nWith Docker Machine upgraded, we can move on to setting up our access tokens\nfor GitLab Runner to use.\n\n\n## Step 7: Gather DigitalOcean credentials\n\n\nNow we need to create the credentials that GitLab Runner will use to create\nnew Droplets using your DigitalOcean account.\n\n\nVisit your DigitalOcean [dashboard](https://cloud.digitalocean.com) and\nclick **API**. On the next screen, look for **Personal access tokens** and\nclick **Generate New Token**.\n\n\nGive the new token a name you will recognize such as `GitLab Runner Access`\nand ensure that both the read and write scopes are enabled, as we need the\nDroplet to create new machines without human intervention.\n\n\nCopy the token somewhere safe as we’ll use it in the next step. You can’t\nretrieve this token again without regenerating it, so be sure it’s stored\nsecurely.\n\n\n## Step 8: Edit GitLab Runner configuration files\n\nTo bring all of these components together, we need to finish configuring our\nbastion Droplet to communicate with your DigitalOcean account.\n\n\nIn your SSH connection to your bastion Droplet, use your favorite text\neditor, such as nano, to open the GitLab Runner configuration file for\nediting:\n\n\n```bash\n\nnano /etc/gitlab-runner/config.toml\n\n```\n\n\nThis configuration file is responsible for the rules your CI setup uses to\nscale up and down on demand. To configure the bastion to autoscale on\ndemand, you need to add the following lines:\n\n\n```bash\n\nconcurrent = 50   # All registered Runners can run up to 50 concurrent\nbuilds\n\n\n[[runners]]\n  url = \"https://example.digitalocean.com\"\n  token = \"existinggitlabtoken\"             # Note this is different from the registration token used by `gitlab-runner register`\n  name = \"example-runner\"\n  executor = \"docker+machine\"        # This Runner is using the 'docker+machine' executor\n  limit = 10                         # This Runner can execute up to 10 builds (created machines)\n  [runners.docker]\n    image = \"alpine:latest\"               # Our secure image\n  [runners.machine]\n    IdleCount = 1                    # The amount of idle machines we require for CI if build queue is empty\n    IdleTime = 600                   # Each machine can be idle for up to 600 seconds, then destroyed\n    MachineName = \"gitlab-runner-autoscale-%s\"    # Each machine will have a unique name ('%s' is required and generates a random number)\n    MachineDriver = \"digitalocean\"   # Docker Machine is using the 'digitalocean' driver\n    MachineOptions = [\n        \"digitalocean-image=coreos-stable\", # The DigitalOcean system image to use by default\n        \"digitalocean-ssh-user=core\", # The default SSH user\n        \"digitalocean-access-token=DO_ACCESS_TOKEN\", # Access token from Step 7\n        \"digitalocean-region=nyc3\", # The data center to spawn runners in\n        \"digitalocean-size=1gb\", # The size (and price category) of your spawned runners\n        \"digitalocean-private-networking\" # Enable private networking on runners\n    ]\n  [runners.cache]\n    Type = \"s3\"   # The Runner is using a distributed cache with the S3-compatible Spaces service\n    ServerAddress = \"nyc3.spaces.digitaloceanspaces.com\"\n    AccessKey = \"YOUR_SPACES_KEY\"\n    SecretKey = \"YOUR_SPACES_SECRET\"\n    BucketName = \"your_bucket_name\"\n    Insecure = true # We do not have a SSL certificate, as we are only running locally\n```\n\n\nOnce you’ve added the new lines, customize the access token, region and\nDroplet size based on  your setup. For the purposes of this tutorial, we’ve\nused the smallest Droplet size of 1GB and created our Droplets in NYC3. Be\nsure to use the information that is relevant in your case.\n\n\nYou also need to customize the cache component, and enter your Space’s\nserver address from the infrastructure configuration step, access key,\nsecret key and the name of the Space that you created.\n\n\nWhen completed, restart GitLab Runner to make sure the configuration is\nbeing used:\n\n\n```bash\n\ngitlab-runner restart\n\n```\n\n\nIf you would like to learn about more all available options, including\noff-peak hours, you can read [GitLab’s advanced\ndocumentation](https://docs.gitlab.com/runner/configuration/autoscale.html).\n\n\n## Step 9 — Test Your GitLab Runner\n\n\nAt this point, our GitLab Runner bastion Droplet is configured and is able\nto create DigitalOcean Droplets on demand, as the CI queue fills up. We’ll\nneed to test it to be sure it works by heading to your GitLab instance and\nthe project we imported in Step 1.\n\n\nTo trigger a build, edit the `readme.md` file by clicking on it, then\nclicking **edit**, and add any relevant testing text to the file, then click\n**Commit changes**.\n\n\nNow a build will be automatically triggered, which can be found under the\nproject’s **CI/CD** option in the left navigation.\n\n\nOn this page you should see a pipeline entry with the status of **running**.\nIn your DigitalOcean account, you’ll see a number of Droplets automatically\ncreated by GitLab Runner in order to build this change.\n\n\nCongratulations! Your CI pipeline is cloud scalable and now manages its own\nresource usage. After the specified idle time, the machines should be\nautomatically destroyed, but we recommend verifying this manually to ensure\nyou aren’t unexpectedly billed.\n\n\n## Troubleshooting\n\n\nIn some cases, GitLab may report that the runner is unreachable and as a\nresult perform no actions, including deploying new runners. You can\ntroubleshoot this by stopping GitLab Runner, then starting it again in debug\nmode:\n\n\n```bash\n\ngitlab-runner stop\n\ngitlab-runner --debug start\n\n```\n\n\nThe output should throw an error, which will be helpful in determining which\nconfiguration is causing the issue.\n\n\nIf your configuration creates too many machines, and you wish to remove them\nall at the same time, you can run this command to destroy them all:\n\n\n```bash\n\ndocker-machine rm $(docker-machine ls -q)\n\n```\n\nFor more troubleshooting steps and additional configuration options, you can\nrefer to [GitLab’s documentation](https://docs.gitlab.com/runner/).\n\n\n## Conclusion\n\n\nYou've successfully set up an automated CI/CD pipeline using GitLab Runner\nand Docker. From here, you could configure higher levels of caching with\nDocker Registry to optimize performance or explore the use of tagging code\nbuilds to specific GitLab code runners.\n\n\nFor more on GitLab Runner, [see the detailed\ndocumentation](https://docs.gitlab.com/runner/), or to learn more, you can\nread [GitLab’s series of blog posts](https://docs.gitlab.com/ee/ci/) on how\nto make the most of your continuous integration pipeline.\n\n\n[This post was originally published by\nDigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-autoscale-gitlab-continuous-deployment-with-gitlab-runner-on-digitalocean)\nand is licensed under [CC BY-NC-SA\n4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).\n\n{: .note}\n",[785,9],"CI",{"slug":787,"featured":6,"template":696},"autoscale-continuous-deployment-gitlab-runner-digital-ocean","content:en-us:blog:autoscale-continuous-deployment-gitlab-runner-digital-ocean.yml","Autoscale Continuous Deployment Gitlab Runner Digital Ocean","en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean.yml","en-us/blog/autoscale-continuous-deployment-gitlab-runner-digital-ocean",{"_path":793,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":794,"content":800,"config":808,"_id":810,"_type":13,"title":811,"_source":15,"_file":812,"_stem":813,"_extension":18},"/en-us/blog/aws-fargate-codebuild-build-containers-gitlab-runner",{"title":795,"description":796,"ogTitle":795,"ogDescription":796,"noIndex":6,"ogImage":797,"ogUrl":798,"ogSiteName":683,"ogType":684,"canonicalUrls":798,"schema":799},"Building containers with GitLab Runner & AWS Fargate executor","Build containers with the AWS Fargate Custom Executor for GitLab Runner and AWS CodeBuild","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667132/Blog/Hero%20Images/build-container-image-runner-fargate-codebuild-cover.jpg","https://about.gitlab.com/blog/aws-fargate-codebuild-build-containers-gitlab-runner","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to build containers with the AWS Fargate Custom Executor for GitLab Runner and AWS CodeBuild\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Elliot Rushton\"}],\n        \"datePublished\": \"2020-07-31\",\n      }",{"title":801,"description":796,"authors":802,"heroImage":797,"date":804,"body":805,"category":739,"tags":806},"How to build containers with the AWS Fargate Custom Executor for GitLab Runner and AWS CodeBuild",[803],"Elliot Rushton","2020-07-31","AWS Fargate does not allow containers to run in privileged mode. This means\nDocker-in-Docker (DinD), which enables the building and running of container\nimages inside of containers, does not work with the [AWS Fargate Custom\nExecutor driver for GitLab\nRunner](https://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/fargate).\nThe good news is that users don't have to be blocked by this and may use a\ncloud-native approach to build containers, effectively leveraging a seamless\nintegration with AWS CodeBuild in the [CI/CD pipeline](/topics/ci-cd/).\n\n\nWe provide in-depth instructions on how to autoscale GitLab CI on AWS\nFargate in [GitLab Runner's\ndocumentation](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws_fargate/index.html).\nIn this blog post, we explain how to instrument CI containers and source\nrepositories to trigger AWS CodeBuild and use it to build container images.\n\n\n## Architecture overview\n\n\n![AWS Fargate + CodeBuild: a cloud-native approach to build containers with\nGitLab\nRunner](https://about.gitlab.com/images/blogimages/build-container-image-runner-fargate-codebuild.png)\n\nHow distinct CI workloads run on Fargate.\n\n{: .note.text-center}\n\n\nThe picture above illustrates distinct GitLab CI workloads running on\nFargate. The container identified by `ci-coordinator (001)` is running a\ntypical CI job which does not build containers, so it does not require\nadditional configuration or dependencies. The second container,\n`ci-coordinator (002)`, illustrates the problem to be tackled in this post:\nThe CI container includes the AWS CLI in order to send content to an Amazon\nS3 Bucket, trigger the AWS CodeBuild job, and fetch logs.\n\n\n## Prerequisites\n\n\nOnce these prerequisites are configured, you can dive into the six-step\nprocess to configure CI containers and source repositories to trigger AWS\nCodeBuild and use it to build container images.\n\n\n- The [AWS Fargate Custom Executor driver for GitLab\nRunner](https://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/fargate)\nmust be set-up appropriately.\n\n- Ensure the AWS IAM user permissions include the ability to create and\nconfigure S3 and CodeBuild resources.\n\n- AWS IAM user or service role with permissions to upload files to S3, start\nCodeBuild jobs, and read CloudWatch Logs.\n\n- AWS IAM user with permissions to create and configure IAM Policies and\nUsers.\n\n\n## Step 1: Create an AWS S3 bucket\n\n\n1. In the top menu of [AWS Management\nConsole](https://aws.amazon.com/console/) click Services.\n\n1. In the Storage section, select `S3`.\n\n1. Click `Create bucket`.\n\n1. Choose a descriptive name (`ci-container-build-bucket` will be used as\nexample) and select your preferred region.\n\n1. Leave all other fields with default values and click `Create bucket`.\n\n1. In the Buckets list, click the name of the bucket you created.\n\n1. Click `Create folder`.\n\n1. Give it the `gitlab-runner-builds` name.\n\n1. Click `Save`.\n\n\n## Step 2: Create an AWS CodeBuild Project\n\n\n1. Using the AWS Console, click `Services` in the top menu\n\n1. Select `CodeBuild` in the Developer Tools section\n\n1. Click `Create build project`\n\n1. In `Project Name` enter `ci-container-build-project`\n\n1. In `Source provider` select `Amazon S3`\n\n1. In `Bucket` select the `ci-container-build-bucket` created in step one\n\n1. In S3 object key or S3 folder enter `gitlab-runner-builds/build.zip`\n\n1. In `Environment image`, select `Managed image`\n\n1. For `Operating system` select your preferred OS from the available\noptions\n\n1. For `Runtime(s)`, choose `Standard`.\n\n1. For `Image`, select `aws/codebuild/standard:4.0`\n\n1. For `Image version`, select `Always use the latest image for this runtime\nversion`\n\n1. For `Environment type` select `Linux`\n\n1. Check the `Privileged` flag\n\n1. For the `Service role` select `New service role` and note the sugggested\n`Role name`\n\n1. For `Build specifications` select `Use a buildspec file`\n\n1. Scroll down to the bottom of the page and click \"Create build project\"\n\n\n## Step 3: Build the CI container image\n\n\nAs stated in Autoscaling GitLab CI on AWS Fargate, a [custom container is\nrequired](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws_fargate/index.html#step-1-prepare-a-base-container-image-for-the-aws-fargate-task)\nto run GitLab CI jobs on Fargate. Since the solution relies on communicating\nwith S3 and CodeBuild, you'll need to [have the AWS CLI\ntool](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)\navailable in the CI container.\n\n\nInstall the `zip` tool to make S3 communication smoother. As an example of a\nUbuntu-based container, the lines below must be added to the CI container's\n`Dockerfile`:\n\n\n```dockerfile\n\nRUN apt-get update -qq -y \\\n    && apt-get install -qq -y curl unzip zip \\\n    && curl -Lo awscliv2.zip https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip \\\n    && unzip awscliv2.zip \\\n    && ./aws/install\n```\n\n\n## Step 4: Add CodeBuild configuration to the repository\n\n\nBy default, CodeBuild looks for a file named `buildspec.yml` in the build\nsource. This file will instruct CodeBuild on how to build and publish the\nresulting container image. Create this file with the content below and\ncommit it to the git repository (_if you changed the **Buildspec name** when\nconfiguring the CodeBuild project [in Step 2](#buildspec), please create the\nfile accordingly_):\n\n\n```yaml\n\nversion: 0.2\n\n\nphases:\n  install:\n    commands:\n      - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2&\n      - timeout 15 sh -c \"until docker info; do echo .; sleep 1; done\"\n  build:\n    commands:\n      - echo Build started on `date`\n      - docker -v\n      - docker build -t \u003CIMAGE-TAG> .\n      - echo Build completed on `date`\n```\n\n\n## Step 5: Set up the GitLab CI job\n\n\nNow we will set up the GitLab CI job that will pull everything together.\n\n\n### Interacting with CodeBuild through the AWS CLI\n\n\nThe CI job will need to interact with AWS Cloud to start CodeBuild jobs,\npoll the status of the jobs, and fetch logs. Commands such as `aws\ncodebuild` and `aws logs` help to tackle this, so let's use them in a\nscript, `codebuild.sh`:\n\n\n```bash\n\n#!/bin/bash\n\n\nbuild_project=ci-container-build-project\n\nbuild_id=$(aws codebuild start-build --project-name $build_project --query\n'build.id' --output text)\n\nbuild_status=$(aws codebuild batch-get-builds --ids $build_id --query\n'builds[].buildStatus' --output text)\n\n\nwhile [ $build_status == \"IN_PROGRESS\" ]\n\ndo\n    sleep 10\n    build_status=$(aws codebuild batch-get-builds --ids $build_id --query 'builds[].buildStatus' --output text)\ndone\n\n\nstream_name=$(aws codebuild batch-get-builds --ids $build_id --query\n'builds[].logs.streamName' --output text)\n\ngroup_name=$(aws codebuild batch-get-builds --ids $build_id --query\n'builds[].logs.groupName' --output text)\n\n\naws logs get-log-events --log-stream-name $stream_name --log-group-name\n$group_name --query 'events[].message' --output text\n\necho Codebuild completed with status $build_status\n\n```\n\n\n### Add a job to build the resulting container\n\n\nOnce the steps one through five are complete, the source repository will be\nstructured as follows:\n\n\n```plaintext\n\n/sample-repository\n  ├── .gitlab-ci.yml\n  ├── buildspec.yml\n  ├── codebuild.sh\n  ├── Dockerfile\n  ├── \u003CAPPLICATION-FILES>\n```\n\n\nThe final step to build the container is to add a job to `.gitlab-ci.yml`:\n\n\n```yaml\n\ndockerbuild:\n  stage: deploy\n  script:\n    - zip build.zip buildspec.yml Dockerfile \u003CAPPLICATION-FILES>\n    - aws configure set default.region \u003CREGION>\n    - aws s3 cp build.zip s3://ci-container-build-bucket/gitlab-runner-builds/build.zip\n    - bash codebuild.sh\n```\n\n\nBelow are some definitions from terms in the script:\n\n\n- `\u003CAPPLICATION-FILES>` is a placeholder for the files that will be required\nto successfully build the resulting container image using the `Dockerfile`,\ne.g., `package.json` and `app.js` in a Node.js application\n\n- `Dockerfile` is used to build the resulting image. _Note: It is not the\nsame file used to build the CI container image, mentioned in [Step 3: Build\nthe CI container image](#step-3-build-the-ci-container-image)_\n\n- Zip and AWS CLI must be installed in the CI container to make the script\nwork – refer to [Step 3: Build the CI container\nimage](#step-3-build-the-ci-container-image) for details\n\n\n## Step 6: Set up AWS credentials\n\n\nThe final step is to set up the AWS credentials. As we already mentioned,\nthe CI job will interact with AWS through the AWS CLI to perform a number of\noperations, and to do that, the AWS CLI needs to authenticate as an IAM user\nwith the permissions listed below. We recommend you create a new user and\ngrant it minimal privileges instead of using your personal AWS user account.\nFor the sake of simplicity, we suggest this approach to complete this\nwalk-through guide.\n\n\nThis AWS user only needs programmatic access and do not forget to make note\nof its Access key ID and Secret access key – they will be needed later. A\nsimple way to grant only the minimal privileges for the new user is to\ncreate a customer managed policy since it can be directly attached to the\nuser. A group might also be used to grant the same privileges for more\nusers, but it is not mandatory for running the sample workflow.\n\n\n- S3\n\n  ```json\n  {\n    \"Effect\": \"Allow\",\n    \"Action\": \"s3:PutObject\",\n    \"Resource\": \"arn:aws:s3:::ci-container-build-bucket/gitlab-runner-builds/*\"\n  }\n  ```\n\n- CodeBuild\n\n  ```json\n  {\n    \"Effect\": \"Allow\",\n    \"Action\": [\"codebuild:StartBuild\", \"codebuild:BatchGetBuilds\"],\n    \"Resource\": \"arn:aws:codebuild:\u003CREGION>:\u003CACCOUNT-ID>:project/ci-container-build-project\"\n  }\n  ```\n\n- CloudWatch Logs\n\n  ```json\n  {\n    \"Effect\": \"Allow\",\n    \"Action\": \"logs:GetLogEvents\",\n    \"Resource\": \"arn:aws:logs:\u003CREGION>:\u003CACCOUNT-ID>:log-group:/aws/codebuild/ci-container-build-project:log-stream:*\"\n  }\n  ```\n\nThe access credentials can be provided to AWS CLI through GitLab CI\nenvironment variables. Please go to your GitLab Project's **CI/CD\nSettings**, click **Expand** in the **Variables** section, add\n`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` with the values you got from\nthe AWS Management Console after creating the IAM user. See the image below\nfor the result you can expect:\n\n\n![Providing AWS credentials for GitLab\nRunner](https://about.gitlab.com/images/blogimages/build-container-image-runner-fargate-codebuild-credentials.png)\n\n\nUsing an IAM Role and [Amazon ECS temporary/unique security\ncredentials](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html)\nis also possible, but not covered in this tutorial.\n\n{: .note.text-center}\n\n\n## Step 7: It's showtime\n\n\nWith all configurations in place, commit the changes and trigger a new\npipeline to watch the magic happen!\n\n\n### Just need the highlights?\n\n\n1. The CI job script added in [Step\n5](#add-a-job-to-build-the-resulting-container) compresses the resulting\ncontainer image build files into `build.zip`\n\n1. `build.zip` is then uploaded to the S3 Bucket we created in [Step 1:\nCreate an Amazon S3 Bucket](#step-1-create-an-amazon-s3-bucket)\n\n1. Next, `codebuild.sh` starts a CodeBuild job based on the project created\nin [Step 2: Create an AWS CodeBuild\nProject](#step-2-create-an-aws-codebuild-project) (Note: that project has an\nS3 object as its source provider)\n\n1. Finally, the CodeBuild job downloads `gitlab-runner-builds/build.zip`\nfrom S3, decompresses it and – from `buildspec.yml`– builds the resulting\ncontainer image\n\n\nA sample repository, demonstrating everything described in the article is\navailable\n[here](https://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/codebuild-on-fargate-example/).\n\n\n## Cleanup\n\n\nIf you want to perform a cleanup after testing the custom executor with AWS\nFargate and CodeBuild, you should remove the following objects:\n\n\n- AWS S3 bucket created in [Step 1](#step-1-create-an-amazon-s3-bucket)\n\n- AWS CodeBuild project created in [Step\n2](#step-2-create-an-aws-codebuild-project)\n\n- `RUN` command added to the CI container image in [Step\n3](#step-3-build-the-ci-container-image)\n\n- The `buildspec.yml` file created in [Step\n4](#step-4-add-codebuild-configuration-to-the-repository)\n\n- The `codebuild.sh` file created in [Step\n5](#step-5-set-up-the-gitlab-ci-job)\n\n- The `dockerbuild` job added to `.gitlab-ci.yml` in [Step\n5](#step-5-set-up-the-gitlab-ci-job)\n\n- IAM policy, user (and maybe group) created in [Step\n6](#step-6-set-up-aws-credentials)\n\n- GitLab CI/CD variables in [Step 6](#step-6-set-up-aws-credentials)\n\n\nRead more about GitLab and AWS:\n\n-[How autoscaling GitLab CI works on AWS\nFargate](/blog/introducing-autoscaling-gitlab-runners-on-aws-fargate/)\n\n-[GitLab 12.10 released with Requirements Management and Autoscaling CI on\nAWS Fargate](/releases/2020/04/22/gitlab-12-10-released/)\n\n-[Announcing 32/64-bit Arm Runner Support for AWS\nGraviton2](/blog/gitlab-arm-aws-graviton2-solution/)\n\n\nCover image by [Lucas van Oort](https://unsplash.com/@switch_dtp_fotografie)\non [Unsplash](https://unsplash.com)\n\n{: .note}\n",[108,9,807],"tutorial",{"slug":809,"featured":6,"template":696},"aws-fargate-codebuild-build-containers-gitlab-runner","content:en-us:blog:aws-fargate-codebuild-build-containers-gitlab-runner.yml","Aws Fargate Codebuild Build Containers Gitlab Runner","en-us/blog/aws-fargate-codebuild-build-containers-gitlab-runner.yml","en-us/blog/aws-fargate-codebuild-build-containers-gitlab-runner",{"_path":815,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":816,"content":822,"config":828,"_id":830,"_type":13,"title":831,"_source":15,"_file":832,"_stem":833,"_extension":18},"/en-us/blog/aws-lambda-usage-stats",{"title":817,"description":818,"ogTitle":817,"ogDescription":818,"noIndex":6,"ogImage":819,"ogUrl":820,"ogSiteName":683,"ogType":684,"canonicalUrls":820,"schema":821},"AWS Lambda usage survey results","The results of our quick AWS Lambda usage survey","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664102/Blog/Hero%20Images/gitlab-values-cover.png","https://about.gitlab.com/blog/aws-lambda-usage-stats","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"AWS Lambda usage survey results\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Viktor Nagy\"}],\n        \"datePublished\": \"2019-11-27\",\n      }",{"title":817,"description":818,"authors":823,"heroImage":819,"date":825,"body":826,"category":691,"tags":827},[824],"Viktor Nagy","2019-11-27","\nThis blog post was originally published on the GitLab Unfiltered blog. It was reviewed and republished on 2019-12-03.\n{: .alert .alert-info .note}\n\nIn early October, I asked the community to [share your AWS Lambda tooling habits](https://forms.gle/9xhjaPxKdZsHDs2V9), so we can better serve your needs from within GitLab. This blog post presents the results of that survey. The survey was shared on Reddit, some Facebook Groups, and on the GitLab Twitter and Facebook channels. All told we received 58 responses which makes the results thought-provoking, but certainly not conclusive. \n\n## Intro\n\nSo, what did I ask you about? I had a few assumptions in mind when I put together the survey.\n\n- Lambda is mostly used by developers, but - at least in the enterprise - ops people might be involved too, because of monitoring or security.\n- There are differences between hobby and professional usage, and I wanted to be able to try to filter out hobby users.\n- Serverless has an adoption path in the enterprise. This might result in it being used only for backoffice scripts at first. So I wanted to know if it's used in production or backoffice scripting only.\n\nBesides testing these assumptions, I wanted to learn about usage habits with respect to:\n\n- Frameworks used (if any)\n- Testing tools and approaches used\n- CI/CD tools used\n- Monitoring and debugging tools and approaches followed\n\nWho answered the survey?\n{: .note.text-center}\n\n![User role](https://about.gitlab.com/images/blogimages/aws-lambda-survey-2019/aws-population.png)\n\n## How do we write code for AWS Lambda\n\nThe first interesting topic was what frameworks were being used for AWS Lambda. It was possible to select multiple options and responders could even provide a free text answer.\n\n![Company size](https://about.gitlab.com/images/blogimages/aws-lambda-survey-2019/aws-frameworks.png){: .small.left.wrap-text}\n\nAs many responders chose more than just a single option, we should look a bit behind the data to understand more. From that you can see that the [serverless framework](/topics/serverless/) is popular with these respondents and its use is  wide-spread. The *Other* section is quite scattered and there are no other big players; responses included Zappa, Chalice, Netlify function, etc. \n\nI thought that there might be differences once I controlled for the company size. I expected more Terraform and less CLI usage as the company size increases. I didn't look into statistical significance, but a simple eye-ball test shows that SMBs are going heads down with tech stacks. They are the strongest users of both serverless and Terraform. I'd say that enterprise users try to follow along, but have a quite big direct usage of AWS CLI too. Why might this be true? A few scenarios come to mind that can think about:\n\n- Enterprises are lagging in terms of technology adoption, thus their Terraform usage is lower\n- They use AWS CLI more extensively as the serverless framework can't fulfill all their use cases\n- Possibly we don't have enough data and with a stronger analysis it would turn out that there are no differences\n\n## What about testing\n\nWhen asked about the challenges serverless technologies pose one topic repeatedly arose: the lack of good testing infrastructure.\n\nAt GitLab we strive to provide outstanding CI/CD capabilities for testing. We also work hard to spread best practices. \n\nI asked the community about the current approaches they take to CI/CD and testing. Here again, multiple answers were allowed.\n\n![Company size](https://about.gitlab.com/images/blogimages/aws-lambda-survey-2019/aws-testing.png){: .small.right.wrap-text}\n\nThis pie chart is filtered to show only non-hobby projects. Even here, almost every fifth project has no testing at all! Otherwise, we can barely speak about test pyramids here as the majority of the projects either don't run any tests or run only unit tests.\n\nGetting into the data by company size, we see what we would expect: as the company size grows, testing becomes more important.\n\n## CI/CD bias\n\nThe survey also contained a question about which CI/CD tools are being used. I skipped the analysis here. As the survey was mostly shared by GitLab team members, and through GitLab channels, clearly the majority of responders use GitLab. A wise choice! \n\n## Monitoring\n\nAlongside developing and deploying software, thinking about its operational health in production is just as important. This led me to ask a few questions on Lambda monitoring habits.\n\n![Company size](https://about.gitlab.com/images/blogimages/aws-lambda-survey-2019/aws-monitoring.png){: .small.left.wrap-text}\n\nEven given the small sample size, I was surprised the vast majority choose AWS CloudWatch. I expected most production environments would use more advanced instrumentation, and I was wrong.\n\nA related question I asked is, \"What metrics are you  most interested in?\" This was a free-text answer. There were no surprises here with \"error rates\" coming out as the clear winner.\n\n## Conclusion\n\nBased on the survey it became clear that even today, GitLab can be used very well with AWS lambda. To make getting started easy, we've created a project template that uses GitLab Pages to host the frontend of your app, and AWS Lambda for your backend needs. Besides the basic hosting needs, our templates have `serverless-offline` support added, so you can start writing tests against it without any additional setup needed. You can easily begin by starting a [new project using the Serverless Framework/JS template](https://gitlab.com/projects/new).\n\n![Easy getting started with project templates](https://about.gitlab.com/images/blogimages/aws-lambda-survey-2019/aws-project-template.png){: .medium}\n\nThese were the insights I gathered about the data. Because this data was provided by the community, I'm making it available to everyone. You can [download the responses as a csv](/images/blogimages/aws-lambda-survey-2019/aws-lambda-survey-responses.csv). In case you are serious about Serverless usage in production, I'd love to hear your insights! Feel free to [reach out to me](https://gitlab.com/nagyv.gitlab)!\n",[266,693,9],{"slug":829,"featured":6,"template":696},"aws-lambda-usage-stats","content:en-us:blog:aws-lambda-usage-stats.yml","Aws Lambda Usage Stats","en-us/blog/aws-lambda-usage-stats.yml","en-us/blog/aws-lambda-usage-stats",{"_path":835,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":836,"content":842,"config":852,"_id":854,"_type":13,"title":855,"_source":15,"_file":856,"_stem":857,"_extension":18},"/en-us/blog/cloudhealth-and-gitlab-reducing-overruns",{"title":837,"description":838,"ogTitle":837,"ogDescription":838,"noIndex":6,"ogImage":839,"ogUrl":840,"ogSiteName":683,"ogType":684,"canonicalUrls":840,"schema":841},"How to prevent deployments from overrunning your budget","Guest authors from VMware share how to include budget and resource checking into your continuous deployment with Cloudhealth and GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670389/Blog/Hero%20Images/gitlab-cloud-journey.png","https://about.gitlab.com/blog/cloudhealth-and-gitlab-reducing-overruns","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to prevent deployments from overrunning your budget\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Davis\"},{\"@type\":\"Person\",\"name\":\"Bahubali (Bill) Shetti\"}],\n        \"datePublished\": \"2019-08-26\",\n      }",{"title":837,"description":838,"authors":843,"heroImage":839,"date":846,"body":847,"category":848,"tags":849},[844,845],"Tim Davis","Bahubali (Bill) Shetti","2019-08-26","\n\nManaging deployments is a complex task and DevOps admins generally consider it a victory when a deployment is\nachieved and somewhat repeatable. Unfortunately this process doesn't give DevOps admins time to\nconsider the impact of the outcome on the larger operations pipeline. We know the importance of\n[Continuous Verification](https://thenewstack.io/continuous-verification-the-missing-link-to-fully-automate-your-pipeline/)\n– it's just one of several day-two operations and best practices that need to be brought into the\ncontinuous deployment (CD) process to achieve efficiencies. But we also need to look at the budget.\n\n## Adding budget and resource checking into your CD\n\nMost developers and DevOps admins don't consider the impact of their deployment on the budget. They\nalso don't generally check if sufficient resources in AWS exist prior to deployment because, after\nall, aren't there \"unlimited\" resources on AWS?\n\nAdding the proper budget and resource checks into the pipeline helps avoid:\n\n* Potential rollbacks and clean-up actions\n* Redeployment (\"lift and shift\") into other regions in AWS\n* Long analysis to pinpoint budget overruns\n\nNot having to deal with these tasks improves the DevOps admin's metrics, such as mean time to change (MTTC),\ndeployment time, etc., and subsequently efficiency goes up.\n\n## Understanding the policy\n\nPrior to implementing any of these checks, it’s important to understand the \"policy.\" While every\norganization is different, and the iterations of \"policy\" are endless, there are some basic checks\nthat should always be implemented:\n\n* Ensure the project-specific budget is not already overrun\n* Will this deployment exceed the project budget?\n* Is the project already over project-specific limits and restrictions? (i.e. cannot use RDS, or\ncan't have more than 10 EC2 instances in a deployment)\n* Will this deployment exceed the project-specific resource policy?\n\nWith these basic checks in place, at least some initial sanity is achieved during a pipeline execution.\nMore and more complex iterations can be added as more is learned about the project and processes are improved.\n\n## How do you do it?\n\nRegardless of the policy complexity, implementing these checks can be easily accomplished with\nstandard off-the-shelf tools like [CloudHealth by VMware](https://cloudhealthtech.com) and [GitLab](/).\n\n* CloudHealth by VMware allows you to define \"perspectives\" specific to your project, create governance\nrules, and access this information through an API for easy integration into any CI/CD tool.\n* GitLab allows you to easily add in scripts and/or pre-built code (containers) enabling\nany possible check against any potential external system.\n\nIn order to highlight how to implement this type of check into the CI/CD pipeline, we've\ndelivered an [example configuration](https://cloudjourney.io/articles/multicloudops/budget_check_cicd-td/)\nusing both CloudHealth and GitLab. We hope this provides a nice baseline to build from.\n\n![CD WITH A CH check from GitLab CI/CD pipelines](https://about.gitlab.com/images/blogimages/glcdpipeline.png){: .shadow.medium.center}\n\n## In summary\n\nAlthough we've provided a baseline that we hope can be used for more complex policy checks in CD,\nconvincing DevOps admins to implement this is another problem. Improving metrics should provide\nan incentive for DevOps admins but it is not sufficient for them to simply add budget and resource checks.\nWhile every enterprise has its own process and metrics, we recommend adding a budgetary efficiency\nmetric for DevOps admins.\n\nUsing the configuration above, it’s easy to add in CloudHealth to continuously check the project's\nbudget and utilization, and adding a DevOps budget metric will not only ensure that these checks\nare deployed but will also lead to more efficient deployments.\n\nIf you have any questions regarding this or any other issue, feel free to reach out\nto us [@cloudjourneyio](https://twitter.com/cloudjourneyio) on Twitter!\n\n### About the guest authors\n\n_Bahubali (Bill) Shetti is the director of public cloud solutions for VMware Cloud Services at VMware.\nHe leads a team of cloud architects that evangelize and develop solutions for improving public cloud\noperations (AWS/Azure/GCP). Bahubali was part of the initial team that developed and launched\nVMware Cloud Services. Previous to VMware, he was director of product management at VCE\n(now Dell) for Cloud Management Products. Between 2011-2014, Bahubali lead operations at Cumulus\nNetworks, lead AWS cloud operations at several startups, and headed an open source routing\nsoftware project. Between 2008-2010, Bahubali lead the cloud investment practice at Storm Ventures.\nHe spent 9 years at Cisco in product management and business development. He holds an M.S. in\nInformation Networking from Carnegie Mellon and a B.S. in Electrical Engineering from Rutgers._\n\n_Tim Davis is a cloud advocate at VMware where he focuses on public cloud operations and cloud native\napplications. He provides consulting guidance to a wide range of customers on these topics and\nprovides a bridge between customers and product teams at VMware. He also works to evangelize\nnative cloud usage including AWS, Azure and GCP. Prior to his current role, he was a specialist systems\nengineer focused on VMware’s Networking and Security product line. Before VMware, Tim worked as a\nconsultant and VMware architect at Dell Services, which wasone of the largest contracts held at\nthe time. His background is in operations/management and architecture. He holds numerous\nindustry certifications including from VMware and Amazon Web Services._\n","insights",[108,850,851,9],"cloud native","DevOps",{"slug":853,"featured":6,"template":696},"cloudhealth-and-gitlab-reducing-overruns","content:en-us:blog:cloudhealth-and-gitlab-reducing-overruns.yml","Cloudhealth And Gitlab Reducing Overruns","en-us/blog/cloudhealth-and-gitlab-reducing-overruns.yml","en-us/blog/cloudhealth-and-gitlab-reducing-overruns",{"_path":859,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":860,"content":866,"config":873,"_id":875,"_type":13,"title":876,"_source":15,"_file":877,"_stem":878,"_extension":18},"/en-us/blog/conan-c-cpp-package-management-integration",{"title":861,"description":862,"ogTitle":861,"ogDescription":862,"noIndex":6,"ogImage":863,"ogUrl":864,"ogSiteName":683,"ogType":684,"canonicalUrls":864,"schema":865},"Modern C and C++: How Conan integration works in GitLab","Conan is a leading C and C++ package manager and it is now available in GitLab. Store and share packages easily with your teams or publicly.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666262/Blog/Hero%20Images/default-blog-image.png","https://about.gitlab.com/blog/conan-c-cpp-package-management-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Modern C and C++: How Conan integration works in GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jordi Mon\"}],\n        \"datePublished\": \"2020-03-31\",\n      }",{"title":861,"description":862,"authors":867,"heroImage":863,"date":869,"body":870,"category":739,"tags":871},[868],"Jordi Mon","2020-03-31","\n\nAs a single application for all the software development and delivery lifecycle, GitLab strives to support all the different software workflows and pipelines. Regardless of how complex this cycle might be (I’m looking at you C++), what we want to do is soothe these pains for C and C++ GitLab users. Following up on this metaphor, as doctors we would like to listen to the patient first: It all started with our community explaining their symptoms and chipping in the first ideas [here](https://gitlab.com/gitlab-org/gitlab-foss/issues/54747). This became even more relevant for GitLab when clients in C++ reliant industries like finance, robotics or embedded software added their interest to supporting package management for C++.\n\n### Conan is now available on GitLab\n\nThe C and C++ ecosystems have a ton of legacy tooling. It is what it is: they’ve been around for a long time and the community is, in a way, very DIY-driven. For example, many C++ libraries are advertised as “Zero deps inside.” This badge is intended as a sign of quality, and is even a bit of a status symbol for the devs and maintainers. That's fine for C/C++ developer but what about the users of such libs? Regardless of the actual quality of the lib’s code, if you wanted to use any of them, you’d better have a local, updated copy of them in a Git submodule. This is especially relevant for head-only monsters like Boost, the most popular set of libs in C++. In other words, in order to make use of them (that’s why they were created in the first place, I guess), you basically have to download the [source code](/solutions/source-code-management/), build it yourself (good luck with that), compile it and include the resulting binary in your project. This process can be time consuming and, if build processes are not well documented or supported, it can be exasperating. All of this can become a real nightmare if transitive dependencies are present, or if different [version control systems](/topics/version-control/) have been used. It's also tricky when deciding upon static or dynamic binaries, static or dynamic linking, single or multi-threaded, 32-bit or 64-bit…\n\n### How to build C and C++ packages in GitLab the Conan way\n\nThe GitLab Conan integration allows Conan users to set GitLab as the remote registry for their packages. Users will be able to set the remote and upload and install packages from GitLab’s registry. Think of it this way: you still use the same CLI to work with your Conan packages, but GitLab is on the receiving end. In doing so, GitLab creates the unique opportunity to have the code and package generated from the code living in the same place, freeing users from having to manage multiple services to store packages and code separately and still have them working together. This allows users to share private packages within an organization that is already using GitLab, publish public packages for general or open source use, and will open up many possibilities in utilizing GitLab’s CI pipelines to build and consume these packages automatically.\n\nCheck out a full demo:\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/2VVmrKNpC_0\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n or a speedrun of Conan performed by the team in charge of the integration:\n\n \u003C!-- blank line -->\n \u003Cfigure class=\"video_container\">\n   \u003Ciframe src=\"https://www.youtube.com/embed/7NYgJWg-w5w\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n \u003C/figure>\n \u003C!-- blank line -->\n\nIf you need more help you can always refer to the [Conan docs](https://docs.conan.io/en/latest/).\n\n### The future of C and C++ in GitLab: Game development workflows!\n\nWhat’s coming next? In tradition with GitLab’s value of iteration, the initial release of Conan is a bare-bones API that allows you to publish and consume packages within GitLab. Next up will be a UI that displays much of the commonly referenced metadata for a given package, pre-written CI templates for automatic package publishing and consuming, less strict package naming conventions with remotes scoped to the group and project level within GitLab, and the list goes on.\n\n* [Conan Repository User Interface](https://gitlab.com/gitlab-org/gitlab/issues/33892)\n* [Project and Group level support for Conan Repository](https://gitlab.com/gitlab-org/gitlab/issues/11679)\n\nIf you are interested in package management at large, find a list of publicly available issues about the topic [here](https://gitlab.com/gitlab-org/gitlab/issues?label_name=Package+Repositories). Also, please note that if game development is your interest, large file support, partial clone and many other features that make game development possible with Git, will soon be available in GitLab. All the heavy lifting required for those massive binaries, engines, and animations will feel like feathers when we release those features. Stay tuned to know more about it in our newsletter.\n\n",[742,9,693,872],"workflow",{"slug":874,"featured":6,"template":696},"conan-c-cpp-package-management-integration","content:en-us:blog:conan-c-cpp-package-management-integration.yml","Conan C Cpp Package Management Integration","en-us/blog/conan-c-cpp-package-management-integration.yml","en-us/blog/conan-c-cpp-package-management-integration",{"_path":880,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":881,"content":887,"config":893,"_id":895,"_type":13,"title":896,"_source":15,"_file":897,"_stem":898,"_extension":18},"/en-us/blog/congratulations-to-hashicorp",{"title":882,"description":883,"ogTitle":882,"ogDescription":883,"noIndex":6,"ogImage":884,"ogUrl":885,"ogSiteName":683,"ogType":684,"canonicalUrls":885,"schema":886},"Congratulations to HashiCorp! Enjoy the cake!","We’re thrilled to see our open source and tech partner HashiCorp join us in the public market. Public companies like HashiCorp, MongoDB, Confluent, and GitLab show that with the right business models, open source can be highly profitable. Here’s a look at HashiCorp’s history, our partnership, and a nod to the future.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663383/Blog/Hero%20Images/tanuki-bg-full.png","https://about.gitlab.com/blog/congratulations-to-hashicorp","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Congratulations to HashiCorp! Enjoy the cake!\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab\"}],\n        \"datePublished\": \"2021-12-09\",\n      }",{"title":882,"description":883,"authors":888,"heroImage":884,"date":890,"body":891,"category":848,"tags":892},[889],"GitLab","2021-12-09","![Cake with message reading \"Congrats on your IPO!\"](https://about.gitlab.com/images/blogimages/hashicorp-cake.jpg)\n\nFrom one open source DevOps company to another, we want to congratulate HashiCorp on becoming a public company! In celebration of your debut in the public markets we sent you a cake!\n\nGitLab and HashiCorp have been partners since 2019. And not only do we work well together, we have a lot in common: both companies have strong business models that are open-core providing both open-source and proprietary features for DevOps practitioners enabling them to create safer software faster. We may solve very different problems in the DevOps ecosystem, but that’s what makes us great partners.\n\n## HashiCorp: always ahead of the curve\n\nAlthough co-founder Mitchell Hashimoto didn’t officially incorporate HashiCorp (named after him) until 2012, he was making contributions to the open source community [from the time he was a teen](https://thenewstack.io/new-stack-makers-mitchell-hashimoto-vagrant-containers-growing-open-source/). And it’s clear Mitchell and team approached the business with a fresh perspective: HashiCorp’s Vagrant was the first automated provisioning of developer environments, which was very useful for onboarding and demos. When Docker became more popular, Vagrant added a Docker provider, making it more usable, even with Docker and Docker Compose later around.\n\nThe team made another bold move in 2014, rolling out the HashiCorp configuration language (HCL) as an alternative to YAML. The step got developers talking and taking sides, but also thinking about what might work best.\n\nAll of those efforts led to perhaps the most ground-breaking part of HashiCorp’s strategy: Vault. The company’s solution that safely stores and controls access to tokens, secrets, API keys, and more, is not just successful, it’s revolutionary. HashiCorp has turned the idea of secrets keeping on its head, by not just allowing companies to store secrets away, but to also have to renew them regularly, kind of like changing the locks on your door on a regular schedule, rather than giving out lots of keys. Clearly this is a paradigm shift for security.\n\n## HashiCorp and GitLab together\n\nVault’s a breakthrough technology for HashiCorp (don’t forget you can use GitLab with Vault to set up [GitLab OpenID connect for authentication](https://docs.gitlab.com/ee/integration/vault.html) or access your [secrets securely in CI](https://docs.gitlab.com/ee/ci/secrets/) as variables) but it’s just one of many that we integrate with.\n\n### Terraform and the GitLab DevOps Platform\n\n[Terraform](https://www.terraform.io) plays a critical role in GitLab’s GitOps/Infrastructure as Code (IaC) workflows, lowering the barriers to entry for teams to adopt Terraform while enabling them to use more stages on the DevOps platform. GitLab’s Terraform integration allows teams to manage the Terraform state in GitLab without external configuration backends.\n\nWe have created the [GitLab Terraform Provider](https://docs.gitlab.com/ee/user/infrastructure/iac/#the-gitlab-terraform-provider) to manage resources on your GitLab instance like groups, projects, users, and more to improve productivity by eliminating an engineer’s dependence on provisioning requests.\n\nA merge request is the center of all collaboration on the DevOps platform. It is important to verify how changes will affect your infrastructure, taking advantage of the [Terraform integration with merge requests](https://docs.gitlab.com/ee/user/infrastructure/iac/mr_integration.html). You can see the planned changes to your infrastructure without leaving the scope of a merge request review at the same time.\n\nUsing GitLab as a [Terraform Module Registry](https://docs.gitlab.com/ee/user/packages/terraform_module_registry/) allows you to publish and reference private Terraform modules in your project’s infrastructure registry, ensuring it’s possible to reuse modules across projects securely. Along with our [IaC security scanning](https://about.gitlab.com/releases/2021/11/22/gitlab-14-5-released/#introducing-infrastructure-as-code-iac-security-scanning) as part of the verify stage, you can safely maintain your infrastructure with ease.\n\n### Terraform and GitLab.com\n\nTerraform is used to manage all the environments of [GitLab.com’s infrastructure](https://gitlab.com/gitlab-com/gitlab-com-infrastructure/) in a single project, allowing collaboration across the entire engineering organization. It is also playing a critical role in our ongoing [migration to Kubernetes](https://about.gitlab.com/handbook/engineering/infrastructure/production/kubernetes/gitlab-com/). Want to deploy a stateful application quickly? GitLab’s [five-minute production app](https://gitlab.com/gitlab-org/5-minute-production-app/deploy-template) template leverages the power of Terraform to get you from idea to production in minutes.\n\n## We’re all-remote\n\nHashiCorp is a remote-first, distributed organization and publicly shares [proven principles](https://works.hashicorp.com) for everyone to learn. GitLab shares this passion for expanding access to opportunity, bolstering global communities, and building more inclusive workplaces where everyone can contribute.\n\n## We see the promise of the future\n\nThe successes of companies like GitLab and HashiCorp, as well as MongoDB and Confluent, on the open market show providing a free tier and commercial offering can be a highly profitable business model for open source technologies and we believe the DevOps market potential is just starting to be tapped.\n\nIn the [words of Dave Bullock](https://about.gitlab.com/blog/wag-labs-blog-post/), former Director of engineering at Wag!: “_We use GitLab with Terraform to test, review, save, and deploy all of our infrastructure as well as the application…The original idea was to just use GitLab as our CI platform. But as we built that out, we started using it for more and more tasks, and ended up using it for our full CI/CD pipeline._”  This is an example of the power of the DevOps Platform. GitLab’s partnership with HashiCorp has made it easier for customers to use more stages of the DevOps Platform. \n\nWe’re joining the global chorus in wishing HashiCorp the best of luck with its public offering.",[851,693,9],{"slug":894,"featured":6,"template":696},"congratulations-to-hashicorp","content:en-us:blog:congratulations-to-hashicorp.yml","Congratulations To Hashicorp","en-us/blog/congratulations-to-hashicorp.yml","en-us/blog/congratulations-to-hashicorp",{"_path":900,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":901,"content":907,"config":914,"_id":916,"_type":13,"title":917,"_source":15,"_file":918,"_stem":919,"_extension":18},"/en-us/blog/connecting-gitlab-and-pantheon-streamline-wordpress-drupal-workflows",{"title":902,"description":903,"ogTitle":902,"ogDescription":903,"noIndex":6,"ogImage":904,"ogUrl":905,"ogSiteName":683,"ogType":684,"canonicalUrls":905,"schema":906},"Streamlining Drupal and WordPress with GitLab and Pantheon","Our guest author, a Developer Programs Engineer at Pantheon, shares how to automate WordPress deployments using GitLab CI/CD.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680516/Blog/Hero%20Images/gitlab-pantheon.png","https://about.gitlab.com/blog/connecting-gitlab-and-pantheon-streamline-wordpress-drupal-workflows","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to connect GitLab and Pantheon to streamline Drupal and WordPress workflows\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Andrew Taylor\"}],\n        \"datePublished\": \"2019-03-26\",\n      }",{"title":908,"description":903,"authors":909,"heroImage":904,"date":911,"body":912,"category":739,"tags":913},"How to connect GitLab and Pantheon to streamline Drupal and WordPress workflows",[910],"Andrew Taylor","2019-03-26","As a member of the developer relations team at\n[Pantheon](https://pantheon.io), I’m always looking for new ways to help\nWordPress and Drupal developers solve workflow problems with automation. To\nthis end, I love exploring new tools and how they can be used effectively\ntogether.\n\n\n### One frequent problem I see teams facing is the dreaded single staging\nserver.\n\n\nIt’s not fun to wait in line for your turn to use the staging server or to\nsend clients a URL and tell them to review some work but ignore other,\nincomplete pieces.\n\n\n[Multidev environments](https://pantheon.io/docs/multidev/), one of\nPantheon’s advanced developer tools, solves this issue by allowing\nenvironments matching Git branches to be created on demand. Each multidev\nenvironment has its own URL and database, making independent work, QA, and\napproval possible without developers stepping on each other's toes.\n\n\nHowever, Pantheon doesn’t provide source control management (SCM) or\ncontinuous integration and continuous deployment (CI/CD) tooling. Instead,\nthe platform is flexible enough to be integrated with your preferred tools.\n\n\n### The next problem I see consistently is teams using different tools to\nmanage development work and to build and deploy that work.\n\n\nFor example, using one tool for SCM and something else for CI/CD. Having to\njump between tools to edit code and diagnose failing jobs is cumbersome.\n\n\n[GitLab](/) solves this problem by providing a full suite of development\nworkflow tools, such as SCM, with features like issues and merge requests,\nbest-in-class CI/CD, and a container registry, to name a few. I haven't come\nacross another application that is so complete to manage development\nworkflow.\n\n\nAs someone who loves automation, I explored connecting Pantheon to GitLab so\nthat commits to the master branch on GitLab deploy to the main dev\nenvironment on Pantheon. Additionally, merge requests on GitLab can create\nand deploy code to Pantheon multidev environments.\n\n\nThis tutorial will walk you through setting up the connection between GitLab\nand Pantheon so you, too, can streamline your WordPress and Drupal workflow.\n\n\nThis can be done with [GitLab repository\nmirroring](https://docs.gitlab.com/ee/user/project/repository/repository_mirroring.html),\nbut we will be setting it up manually to get some experience with [GitLab\nCI](https://docs.gitlab.com/ee/ci/) and have the ability to expand beyond\njust deployment in the future.\n\n\n## Background\n\n\nFor this post, you need to know that Pantheon breaks each site down into\nthree components: code, database, and files.\n\n\nThe code portion of a Pantheon site includes the CMS files, such as\nWordPress core, plugins and themes. These files are managed in a [Git\nrepository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository)\nhosted by Pantheon, which means we can deploy code from GitLab to Pantheon\nwith Git.\n\n\nWhen Pantheon refers to files, it is the media files, such as images, for\nyour site. These are typically uploaded by site users and are ignored in\nGit.\n\n\nYou can [create a free account](https://pantheon.io/register), learn more\nabout the [Pantheon workflow](https://pantheon.io/docs/pantheon-workflow),\nor [sign up for a live demo](https://pantheon.io/live-demo) on pantheon.io.\n\n\n## Assumptions\n\n\nMy project is named `pantheon-gitlab-blog-demo`, both on Pantheon and\nGitLab. You should use a unique project name. This tutorial uses a WordPress\nsite. Drupal can be substituted, but some modification will be needed.\n\n\nI'll also be using the [Git command\nline](https://git-scm.com/book/en/v2/Getting-Started-The-Command-Line) but\nyou can substitute a [graphical\ninterface](https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Graphical-Interfaces)\nif you prefer.\n\n\n## Create the projects\n\n\nFirst up, create a [new GitLab\nproject](https://docs.gitlab.com/ee/user/project/working_with_projects.html#create-a-project)\n– we'll come back to this in a little bit.\n\n\nNow, [create a new WordPress site on\nPantheon](https://pantheon.io/docs/launch-wordpress/). After your new site\nis created, you will need to install WordPress for the site dashboard.\n\n\n_You might be tempted to make some changes, such as adding or removing\nplugins, but please refrain. We haven't connected the site to GitLab yet and\nwant to make sure all code changes, e.g. adding or removing plugins, go\nthrough GitLab._\n\n\nAfter WordPress is installed, go back to the Pantheon site dashboard and\nchange the development mode to Git.\n\n\n![Pantheon\nDashboard](https://about.gitlab.com/images/blogimages/pantheon-dashboard-after-fresh-wordpress-install.png){:\n.shadow.medium.center}\n\n\n## Initial commit to GitLab\n\n\nNext, we need to get the starting WordPress code from the Pantheon site over\nto GitLab. In order to do this, we will clone the code from the Pantheon\nsite Git repository locally, then push it to the GitLab repository.\n\n\nTo make this easier, and more secure, [add an SSH key to\nPantheon](https://pantheon.io/docs/ssh-keys/) to avoid entering your\npassword when cloning Pantheon Git repository. While you're at it, [add an\nSSH key to GitLab](https://docs.gitlab.com/ee/ssh/) as well.\n\n\nTo do this, clone the Pantheon site locally by copying the command in the\nClone with Git drop-down field from the site dashboard.\n\n\n![CPantheon git\nconnection](https://about.gitlab.com/images/blogimages/pantheon-git-connection-info.png){:\n.shadow.center}\n\n\n_If you need help, see the [Pantheon Start With\nGit](https://pantheon.io/docs/git/#clone-your-site-codebase) documentation._\n\n\nNext, we want to change the `git remote origin` to point to GitLab, instead\nof Pantheon. This can be done with the [`git remote`\ncommand](https://git-scm.com/docs/git-remote).\n\n\nHead over to your GitLab project and grab the repository URL, which can be\nfound at in the Clone drop-down of the project details screen. Be sure to\nuse the Clone with SSH variant of the GitLab repository URL, since we set up\nan SSH key earlier.\n\n\n![Gitlab git\nconnection](https://about.gitlab.com/images/blogimages/gitlab-git-connection-info.png){:\n.shadow.medium.center}\n\n\nThe default `git remote` for the local copy of our code repository is\n`origin`. We can change it with `git remote set-url origin [GitLab\nrepository URL]`, replacing `[GitLab repository URL]` with your actual\nGitLab repository URL.\n\n\nFinally, run `git push origin master --force` to send the WordPress code\nfrom the Pantheon site to GitLab.\n\n\n_The --force flag is only needed as part of this one-time step. Subsequent\n`git push` commands to GitLab won't need it._\n\n\n## Set up credentials and variables\n\n\nRemember how we added an SSH key locally to authorize with Pantheon and\nGitLab? Well, an SSH token can also be used to authorize GitLab and\nPantheon.\n\n\nGitLab has some great documentation, and we will be looking at the [SSH keys\nwhen using the Docker executor section of the Using SSH keys with GitLab\nCI/CD\ndoc](https://docs.gitlab.com/ee/ci/ssh_keys/#ssh-keys-when-using-the-docker-executor).\n\n\nAt this point, we will need to do the first two steps: _Create a new SSH key\npair locally with ssh-keygen and Add the private key as a variable to your\nproject._\n\n\nWhen done, `SSH_PRIVATE_KEY` should be set as a [GitLab CI/CD Environment\nVariables](https://docs.gitlab.com/ee/ci/variables/) in the project\nsettings.\n\n\nTo take care of the third and fourth steps, create `.gitlab-ci.yml` file\nwith the following contents:\n\n\n```\n\nbefore_script:\n  # See https://docs.gitlab.com/ee/ci/ssh_keys/\n  - eval $(ssh-agent -s)\n  - echo \"$SSH_PRIVATE_KEY\" | tr -d '\\r' | ssh-add - > /dev/null\n  - mkdir -p $HOME/.ssh && echo \"StrictHostKeyChecking no\" >> \"$HOME/.ssh/config\"\n  - git config --global user.email \"$GITLAB_USER_EMAIL\"\n  - git config --global user.name \"Gitlab CI\"\n  ```\n\nDon't commit the `.gitlab-ci.yml` file just yet, we will be adding more to\nit in the next section.\n\n\nNow, we need to take care of step 5, _add the public key from the one you\ncreated in the first step to the services that you want to have an access to\nfrom within the build environment._\n\n\nIn our case, the service we want to access from GitLab is Pantheon. Follow\nthe Pantheon doc to [Add Your SSH Key to\nPantheon](https://pantheon.io/docs/ssh-keys/#add-your-ssh-key-to-pantheon)\nto complete this step.\n\n\n_Be sure that the private SSH key is in GitLab and the public key is on\nPantheon_\n\n\nWe will also need to set some additional environment variables. The first\none should be named PANTHEON_SITE, and the value will be the machine name of\nyour `Pantheon site`. and the value will be the *machine name* of your\nPantheon site.\n\n\nYou can get the machine name from the end of the Clone with Git command.\nSince you already cloned the site locally, it will be the directory name of\nyour local repository.\n\n\n![wordpress machine\nname](https://about.gitlab.com/images/blogimages/pantheon-machine-name.png){:\n.shadow.medium.center}\n\n\nThe next GitLab CI environment variable to set is `PANTHEON_GIT_URL`, which\nwill be the Git repository URL of the Pantheon site that we used earlier.\n\n\n_Enter just the SSH repository URL, leaving off `git clone` and the site\nmachine name at the end._\n\n\nPhew! Now that setup is done, we can move on to finishing our\n`.gitlab-ci.yml` file.\n\n\n## Create the deployment job\n\n\nWhat we will be doing with GitLab CI initially is very similar to what we\ndid with Git repositories earlier. This time though, we will add the\nPantheon repository as a second Git remote and then push the code from\nGitLab to Pantheon.\n\n\nTo do this, we will set up a\n[stage](https://docs.gitlab.com/ee/ci/yaml/#stages) named `deploy` and a\n[job](https://docs.gitlab.com/ee/ci/jobs/) named `deploy:dev`, as it will\ndeploy to the dev environment on Pantheon. The resulting `.gitlab-ci.yml`\nfile should look like this:\n\n\n```\n\nstages:\n\n- deploy\n\n\nbefore_script:\n  # See https://docs.gitlab.com/ee/ci/ssh_keys/\n  - eval $(ssh-agent -s)\n  - echo \"$SSH_PRIVATE_KEY\" | tr -d '\\r' | ssh-add - > /dev/null\n  - mkdir -p $HOME/.ssh && echo \"StrictHostKeyChecking no\" >> \"$HOME/.ssh/config\"\n  - git config --global user.email \"$GITLAB_USER_EMAIL\"\n  - git config --global user.name \"Gitlab CI\"\n\ndeploy:dev:\n  stage: deploy\n  environment:\n    name: dev\n    url: https://dev-$PANTHEON_SITE.pantheonsite.io/\n  script:\n    - git remote add pantheon $PANTHEON_GIT_URL\n    - git push pantheon master --force\n  only:\n    - master\n```\n\n\n`SSH_PRIVATE_KEY`, `PANTHEON_SITE`, and `PANTHEON_GIT_URL` should all look\nfamiliar - they are the environment variables we set up earlier. Having\nenvironment variables will allow us to re-use the values multiple times in\nour `.gitlab-ci.yml` file, while having one place to update them, should\nthey change in the future.\n\n\nFinally, add, commit, and push the `.gitlab-ci.yml` file to send it to\nGitLab.\n\n\n## Verify the deployment\n\n\nIf everything was done correctly, the `deploy:dev` job run on GitLab CI/CD,\nsucceed and send the `.gitlab-ci.yml` commit to Pantheon. Let's take a look!\n\n\n![deploy\njob](https://about.gitlab.com/images/blogimages/gitlab-deploy-dev-job.png){:\n.shadow.center}\n\n\n![deploy job\npassing](https://about.gitlab.com/images/blogimages/gitlab-deploy-dev-job-passed.png){:\n.shadow.center}\n\n\n![gitlab commit on pantheon\ndev](https://about.gitlab.com/images/blogimages/gitlab-commits-on-pantheon-dev.png){:\n.shadow.center}\n\n\n## Sending merge request branches to Pantheon\n\n\nThis next section makes use of my favorite Pantheon feature,\n[multidev](https://pantheon.io/docs/multidev), which allows you to create\nadditional Pantheon environments on demand associated with Git branches.\n\n\nThis section is entirely optional as [multidev access is\nrestricted](https://pantheon.io/docs/multidev-faq/), however, if you do have\nmultidev access, having GitLab merge requests automatically create multidev\nenvironments on Pantheon is a huge workflow improvement.\n\n\nWe will start by making a new Git branch locally with `git checkout -b\nmultidev-support`. Now, let's edit `.gitlab-ci.yml` again.\n\n\nI like to use the merge request number in the Pantheon environment name. For\nexample, the first merge request would be `mr-1`, the second would be\n`mr-2`, and so on.\n\n\nSince the merge request changes, we need to define these Pantheon branch\nnames dynamically. GitLab makes this easy by providing [predefined\nenvironment](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)\nvariables.\n\n\nWe can use `$CI_MERGE_REQUEST_IID`, which provides the merge request number.\nLet's put that to use, along with our global environment variables from\nearlier, and add a new deploy:multidev job to the end of our\n`.gitlab-ci.yml` file.\n\n\n```\n\ndeploy:multidev:\n  stage: deploy\n  environment:\n    name: multidev/mr-$CI_MERGE_REQUEST_IID\n    url: https://mr-$CI_MERGE_REQUEST_IID-$PANTHEON_SITE.pantheonsite.io/\n  script:\n    # Checkout the merge request source branch\n    - git checkout $CI_COMMIT_REF_NAME\n    # Add the Pantheon git repository as an additional remote\n    - git remote add pantheon $PANTHEON_GIT_URL\n    # Push the merge request source branch to Pantheon\n    - git push pantheon $CI_COMMIT_REF_NAME:mr-$CI_MERGE_REQUEST_IID --force\n  only:\n    - merge_requests\n```\n\n\nThis should look very similar to our `deploy:dev` job, only pushing a branch\nto Pantheon instead of `master`.\n\n\nAfter you add and commit the updated `.gitlab-ci.yml` file, push this new\nbranch to GitLab with `git push -u origin multidev-support`.\n\n\nNext, let's create a new merge request from our `multidev-support` branch by\nfollowing the _Create merge request_ prompt.\n\n\n![create merge\nrequest](https://about.gitlab.com/images/blogimages/gitlab-create-merge-request-prompt.png){:\n.shadow.medium.center}\n\n\nAfter creating the merge request, look for the  CI/CD job `deploy:multidev`\nto run.\n\n\n![multidev deploy\nsuccess](https://about.gitlab.com/images/blogimages/multidev-branch-deploy-success.png){:\n.shadow.medium.center}\n\n\nLook at that – a new branch was sent to Pantheon. However, when we go to the\nmultidev section of the site dashboard on Pantheon there isn't a new\nmultidev environment.\n\n\n![multidev\nbranch](https://about.gitlab.com/images/blogimages/pantheon-no-multidev-environments.png){:\n.shadow.medium.center}\n\n\nLet's look at the _Git_ Branches section.\n\n\n![mr\nbranch](https://about.gitlab.com/images/blogimages/pantheon-mr-1-branch.png){:\n.shadow.medium.center}\n\n\nOur `mr-1` branch did make it to Pantheon after all. Go ahead and create an\nenvironment from the `mr-1` branch.\n\n\n![create\nmultidev](https://about.gitlab.com/images/blogimages/pantheon-mr-1-multidev-creation.png){:\n.shadow.medium.center}\n\n\nOnce the multidev environment has been created, head back to GitLab and look\nat the _Operations > Environments_ section. You will notice entries for\n`dev` and `mr-1`.\n\n\nThis is because we added an `environment` entry with `name` and `url` to our\nCI/CD jobs. If you click on the open environment icon, you will be taken to\nthe URL for the multidev on Pantheon.\n\n\n## Automating multidev creation\n\n\nWe _could_ stop here and try to remember to create a multidev environment\neach time there is a new merge request, but we can automate that process as\nwell!\n\n\nPantheon has a command line tool,\n[Terminus](https://pantheon.io/docs/terminus/), that allows you to interact\nwith the platform in an automated fashion. Terminus will allow us to\nprovision our multidev environments from the command line – perfect for use\nin [GitLab CI](https://docs.gitlab.com/ee/ci/).\n\n\nWe will need a new merge request to test this, so let's create a new branch\nwith `git checkout -b auto-multidev-creation`.\n\n\nIn order to use Terminus in GitLab CI/CD jobs we will need a machine token\nto authenticate with Terminus and a container image with Terminus available.\n\n\n[Create a Pantheon machine\ntoken](https://pantheon.io/docs/machine-tokens/#create-a-machine-token),\nsave it to a safe place, and add it as a global GitLab environment variable\nnamed `PANTHEON_MACHINE_TOKEN`.\n\n\n_If you don't remember how to add GitLab environment variables, scroll up to\nwhere we defined `PANTHEON_SITE` earlier in the tutorial._\n\n\n## Building a Dockerfile with Terminus\n\n\nIf you don't have Docker or aren't comfortable working with `Dockerfile`\nfiles, you can use my image\n`registry.gitlab.com/ataylorme/pantheon-gitlab-blog-demo:latest` and skip\nthis section.\n\n\n[GitLab has a container\nregistry](https://docs.gitlab.com/ee/user/packages/container_registry/index.html)\nthat allows us to build and host a Dockerfile for use in our project. Let's\ncreate a Dockerfile that has Terminus available, so we can interact with\nPantheon.\n\n\nTerminus is a PHP-based command line tool, so we will start with a PHP\nimage. I prefer to install Terminus via Composer so I'll be using [the\nofficial Docker Composer image](https://hub.docker.com/_/composer) as a\nbase. Create a `Dockerfile` in your local repository directory with the\nfollowing contents:\n\n\n```\n\n# Use the official Composer image as a parent image\n\nFROM composer:1.8\n\n\n# Update/upgrade apk\n\nRUN apk update\n\nRUN apk upgrade\n\n\n# Make the Terminus directory\n\nRUN mkdir -p /usr/local/share/terminus\n\n\n# Install Terminus 2.x with Composer\n\nRUN /usr/bin/env COMPOSER_BIN_DIR=/usr/local/bin composer -n\n--working-dir=/usr/local/share/terminus require\npantheon-systems/terminus:\"^2\"\n\n```\n\nFollow the _Build and push images_ section of the [container registry\ndocumentation](https://gitlab.com/help/user/project/container_registry#build-and-push-images)\nto build an image from the `Dockerfile` and upload it to GitLab.\n\n\nVisit the _Registry_ section of your GitLab project. If things went\naccording to plan you will see your image listed. Make a note of the image\ntag link, as we will need to use that in our `.gitlab-ci.yml` file.\n\n\n![container\nregistry](https://about.gitlab.com/images/blogimages/gitlab-container-registry.png){:\n.shadow.center}\n\n\nThe `script` section of our `deploy:multidev` job is starting to get long,\nso let's move it to a dedicated file. Create a new file\n`private/multidev-deploy.sh` with the following contents:\n\n\n```\n\n#!/bin/bash\n\n\n# Store the mr- environment name\n\nexport PANTHEON_ENV=mr-$CI_MERGE_REQUEST_IID\n\n\n# Authenticate with Terminus\n\nterminus auth:login --machine-token=$PANTHEON_MACHINE_TOKEN\n\n\n# Checkout the merge request source branch\n\ngit checkout $CI_COMMIT_REF_NAME\n\n\n# Add the Pantheon Git repository as an additional remote\n\ngit remote add pantheon $PANTHEON_GIT_URL\n\n\n# Push the merge request source branch to Pantheon\n\ngit push pantheon $CI_COMMIT_REF_NAME:$PANTHEON_ENV --force\n\n\n# Create a function for determining if a multidev exists\n\nTERMINUS_DOES_MULTIDEV_EXIST()\n\n{\n    # Stash a list of Pantheon multidev environments\n    PANTHEON_MULTIDEV_LIST=\"$(terminus multidev:list ${PANTHEON_SITE} --format=list --field=id)\"\n\n    while read -r multiDev; do\n        if [[ \"${multiDev}\" == \"$1\" ]]\n        then\n            return 0;\n        fi\n    done \u003C\u003C\u003C \"$PANTHEON_MULTIDEV_LIST\"\n\n    return 1;\n}\n\n\n# If the mutltidev doesn't exist\n\nif ! TERMINUS_DOES_MULTIDEV_EXIST $PANTHEON_ENV\n\nthen\n    # Create it with Terminus\n    echo \"No multidev for $PANTHEON_ENV found, creating one...\"\n    terminus multidev:create $PANTHEON_SITE.dev $PANTHEON_ENV\nelse\n    echo \"The multidev $PANTHEON_ENV already exists, skipping creating it...\"\nfi\n\n```\n\n\nThe script is in the `private` directory as [it is not web accessible on\nPantheon](https://pantheon.io/docs/private-paths/). Now that we have a\nscript for our multidev logic, update the `deploy:multidev` section of\n`.gitlab-ci.yml` so that it looks like this:\n\n\n```\n\ndeploy:multidev:\n  stage: deploy\n  environment:\n    name: multidev/mr-$CI_MERGE_REQUEST_IID\n    url: https://mr-$CI_MERGE_REQUEST_IID-$PANTHEON_SITE.pantheonsite.io/\n  script:\n    # Run the multidev deploy script\n    - \"/bin/bash ./private/multidev-deploy.sh\"\n  only:\n    - merge_requests\n```\n\n\nIn order to make sure our jobs run with the custom image created earlier,\nadd an `image` definition with the registry URL to `.gitlab-ci.yml`. My\ncomplete `.gitlab-ci.yml` file now looks like this:\n\n\n```\n\nimage: registry.gitlab.com/ataylorme/pantheon-gitlab-blog-demo:latest\n\n\nstages:\n\n- deploy\n\n\nbefore_script:\n  # See https://docs.gitlab.com/ee/ci/ssh_keys/\n  - eval $(ssh-agent -s)\n  - echo \"$SSH_PRIVATE_KEY\" | tr -d '\\r' | ssh-add - > /dev/null\n  - mkdir -p $HOME/.ssh && echo \"StrictHostKeyChecking no\" >> \"$HOME/.ssh/config\"\n  - git config --global user.email \"$GITLAB_USER_EMAIL\"\n  - git config --global user.name \"Gitlab CI\"\n\ndeploy:dev:\n  stage: deploy\n  environment:\n    name: dev\n    url: https://dev-$PANTHEON_SITE.pantheonsite.io/\n  script:\n    - git remote add pantheon $PANTHEON_GIT_URL\n    - git push pantheon master --force\n  only:\n    - master\n\ndeploy:multidev:\n  stage: deploy\n  environment:\n    name: multidev/mr-$CI_MERGE_REQUEST_IID\n    url: https://mr-$CI_MERGE_REQUEST_IID-$PANTHEON_SITE.pantheonsite.io/\n  script:\n    # Run the multidev deploy script\n    - \"/bin/bash ./private/multidev-deploy.sh\"\n  only:\n    - merge_requests\n```\n\n\nAdd, commit, and push `private/multidev-deploy.sh` and `.gitlab-ci.yml`.\nNow, head back to GitLab and wait for the CI/CD job to finish. The multidev\ncreation takes a few minutes, so be patient.\n\n\nWhen it is finished, go check out the multidev list on Pantheon. Voila! The\n`mr-2` multidev is there.\n\n\n![mr-2](https://about.gitlab.com/images/blogimages/pantheon-mr-2-multidev.png){:\n.shadow.medium.center}\n\n\n## Conclusion\n\n\nOpening a merge request and having an environment spin up automatically is a\npowerful addition to any team's workflow.\n\n\nBy leveraging the powerful tools offered by both GitLab and Pantheon, we can\nconnect GitLab to Pantheon in an automated fashion.\n\n\nSince we used GitLab CI/CD, there is room for growth in our workflow as\nwell. Here are a few ideas to get you started:\n\n* Add a build step.\n\n* Add automated testing.\n\n* Add a job to enforce coding standards.\n\n* Add [dynamic application security\ntesting](https://docs.gitlab.com/ee/user/application_security/dast/).\n\n\nDrop me a line with any thoughts you have on GitLab, Pantheon, and\nautomation.\n\n\nP.S. Did you know Terminus, Pantheon’s command line tool, [is extendable via\nplugins](https://pantheon.io/docs/terminus/plugins/)?\n\n\nOver at Pantheon, we have been hard at work on version 2 of our [Terminus\nBuild Tools\nPlugin](https://github.com/pantheon-systems/terminus-build-tools-plugin/),\ncomplete with GitLab support. If you don't want to do all this setup for\neach project, I encourage you to check it out and help us test the v2 beta.\nThe terminus `build:project:create` command just needs a Pantheon token and\nGitLab token. From there, it will spin up one of our example projects,\ncomplete with Composer and automated testing, create a new project on\nGitLab, a new site on Pantheon, and connect the two by setting up\nenvironment variables and SSH keys.\n\n\n### About the guest author\n\n\nAndrew Taylor is a Developer Programs Engineer at\n[Pantheon](https://pantheon.io/).\n",[851,9,266,872],{"slug":915,"featured":6,"template":696},"connecting-gitlab-and-pantheon-streamline-wordpress-drupal-workflows","content:en-us:blog:connecting-gitlab-and-pantheon-streamline-wordpress-drupal-workflows.yml","Connecting Gitlab And Pantheon Streamline Wordpress Drupal Workflows","en-us/blog/connecting-gitlab-and-pantheon-streamline-wordpress-drupal-workflows.yml","en-us/blog/connecting-gitlab-and-pantheon-streamline-wordpress-drupal-workflows",{"_path":921,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":922,"content":928,"config":935,"_id":937,"_type":13,"title":938,"_source":15,"_file":939,"_stem":940,"_extension":18},"/en-us/blog/continuous-machine-learning-development-with-gitlab-ci",{"title":923,"description":924,"ogTitle":923,"ogDescription":924,"noIndex":6,"ogImage":925,"ogUrl":926,"ogSiteName":683,"ogType":684,"canonicalUrls":926,"schema":927},"How machine learning ops works with GitLab and continuous machine learning","We share different machine learning use cases for CML projects using GitLab CI.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681802/Blog/Hero%20Images/gitlab_cml_dvc_banner.png","https://about.gitlab.com/blog/continuous-machine-learning-development-with-gitlab-ci","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How machine learning ops works with GitLab and continuous machine learning\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Dr. Elle O'Brien\"}],\n        \"datePublished\": \"2020-12-01\",\n      }",{"title":923,"description":924,"authors":929,"heroImage":925,"date":931,"body":932,"category":763,"tags":933},[930],"Dr. Elle O'Brien","2020-12-01","Continuous integration (CI) is standard practice in software development for\nspeeding up development cycles, and for keeping them short and painless. CI\nmeans making small commits, often, and automating tests so every commit is a\nrelease candidate.\n\n\nWhen a project involves machine learning (ML), though, new challenges arise:\nTraditional [version control systems](/topics/version-control/) (like Git)\nthat are key to CI struggle to manage large datasets and models.\n\nFurthermore, typical pass-fail tests are too coarse for understanding ML\nmodel performance – you might need to consider how several metrics, like\naccuracy, sensitivity, and specificity, are affected by changes in your code\nor data.\n\nData visualizations like confusion matrices and loss plots are needed to\nmake sense of the high-dimensional and often unintuitive behavior of models.\n\n\n## Continuous machine learning: an introduction\n\n\n[Iterative.ai](https://iterative.ai), the team behind the popular open\nsource version control system for ML projects [DVC](https://dvc.org) (short\nfor Data Version Control),\n\nhas recently released another open source project called\n[CML](https://cml.dev), which stands for continuous machine learning.\n\nCML is our approach to adapting powerful CI systems like GitLab CI to common\ndata science and ML use cases, including:\n\n\n- Automatic model training\n\n- Automatic model and dataset testing\n\n- Transparent and rich reporting about models and datasets (with data viz\nand metrics) in a merge request (MR)\n\n\n## Your first continuous machine learning report\n\n\nCML helps you put tables, data viz, and even sample outputs from models into\ncomments on your MRs, so you can review datasets and models like code.\n\nLet's see how to produce a basic report – we'll train an ML model using\nGitLab CI, and then report a model metric and confusion matrix in our MR.\n\n\n![Confusion\nMatrix](https://about.gitlab.com/images/blogimages/cml_confusion_matrix.jpg){:\n.shadow.medium.center}\n\nConfusion matrix\n\n{: .note.text-center}\n\n\nTo make this report, our `.gitlab-ci.yml` contains the following workflow:\n\n\n```\n\n# .gitlab-ci.yml\n\nstages:\n    - cml_run\n\ncml:\n    stage: cml_run\n    image: dvcorg/cml-py3:latest\n\n    script:\n        - pip3 install -r requirements.txt\n        - python train.py\n\n        - cat metrics.txt >> report.md\n        - echo >> report.md\n        - cml-publish confusion_matrix.png --md --title 'confusion-matrix' >> report.md\n        - cml-send-comment report.md\n\n```\n\n\nThe entire [project repository is available\nhere](https://gitlab.com/iterative.ai/cml-base-case/).\n\nThe steps consist of the following:\n\n\n- **Train**: This is a classic training step where we install requirements\n(like `pip` packages) and run the training script.\n\n- **Write a CML report**: Produced metrics are appended to a markdown\nreport.\n\n- **Publish a CML report**: CML publishes an image of the confusion matrix\nwith the embedded metrics to your GitLab MR.\n\n\nNow, when you and your teammates are deciding if your changes have had a\npositive effect on your modeling goals,\n\nyou have a dashboard of sorts to review. Plus, this report is linked by Git\nto your exact project version (data and code) and the runner used for\ntraining and the logs from that run.\n\n\nThis is the simplest use case for achieving continuous machine learning with\nCML and GitLab. In the next section we'll look at a more complex use case.\n\n\n## CML with DVC for data version control\n\n\nIn machine learning projects, you need to track changes in your datasets as\nwell as changes in your code.\n\nSince Git is frequently a poor fit for managing large files, we can use\n[DVC](https://dvc.org) to link remote datasets to your CI system.\n\n\n```\n\n# .gitlab-ci.yml\n\nstages:\n  - cml_run\n\ncml:\n  stage: cml_run\n  image: dvcorg/cml-py3:latest\n  script:\n    - dvc pull data\n\n    - pip install -r requirements.txt\n    - dvc repro\n\n    # Compare metrics to master\n    - git fetch --prune\n    - dvc metrics diff --show-md master >> report.md\n    - echo >> report.md\n\n    # Visualize loss function diff\n    - dvc plots diff\n      --target loss.csv --show-vega master > vega.json\n    - vl2png vega.json | cml-publish --md >> report.md\n    - cml-send-comment report.md\n```\n\n\nThe entire [project is available\nhere](https://gitlab.com/iterative.ai/cml-dvc-case).\n\nIn this workflow, we have additional steps that use DVC to pull a training\ndataset, run an experiment, and then use CML to publish the report in your\nMR.\n\n\n![CML with DVC](https://about.gitlab.com/images/blogimages/cml_dvc.jpg){:\n.shadow.medium.center}\n\nCML with DVC\n\n{: .note.text-center}\n\n\nFor more details about ML data versioning and tracking, check out the [DVC\ndocumentation](https://dvc.org/doc).\n\n\n## Summary\n\n\nWe made CML to adapt CI to machine learning, so data science teams can enjoy\nbenefits such as:\n\n\n- Your code, data, models, and training infrastructure (hardware and\nsoftware environment) will be Git versioned.\n\n- You’re automating work, testing frequently, and getting fast feedback\n(with visual reports if you use CML). In the long run, this will almost\ncertainly speed up your project’s development.\n\n- CI systems make your work visible to everyone on your team. No one has to\nsearch very hard to find the code, data, and model from your best run.\n\n\n### About the guest author\n\n\n_Dr. Elle O'Brien is a Ph.D data scientist at iterative.ai and co-creator of\n[CML](https://cml.dev) project. She is also a lecturer at\n[UMSI](https://www.si.umich.edu/)._\n",[108,266,9,693,934],"AI/ML",{"slug":936,"featured":6,"template":696},"continuous-machine-learning-development-with-gitlab-ci","content:en-us:blog:continuous-machine-learning-development-with-gitlab-ci.yml","Continuous Machine Learning Development With Gitlab Ci","en-us/blog/continuous-machine-learning-development-with-gitlab-ci.yml","en-us/blog/continuous-machine-learning-development-with-gitlab-ci",{"_path":942,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":943,"content":949,"config":955,"_id":957,"_type":13,"title":958,"_source":15,"_file":959,"_stem":960,"_extension":18},"/en-us/blog/crowdin-localization-for-agile-projects",{"title":944,"description":945,"ogTitle":944,"ogDescription":945,"noIndex":6,"ogImage":946,"ogUrl":947,"ogSiteName":683,"ogType":684,"canonicalUrls":947,"schema":948},"Automate your localization with GitLab + Crowdin","Complete your development workflow by integrating GitLab with Crowdin to help your product speak the same language as the people it’s built for.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680247/Blog/Hero%20Images/gitlab-crowdin-cover.png","https://about.gitlab.com/blog/crowdin-localization-for-agile-projects","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Automate your localization with GitLab + Crowdin\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Khrystyna Humenna\"}],\n        \"datePublished\": \"2018-02-06\",\n      }",{"title":944,"description":945,"authors":950,"heroImage":946,"date":952,"body":953,"category":739,"tags":954},[951],"Khrystyna Humenna","2018-02-06","\n\nWhen developing products like web apps, games, and alike, you have to face the fact that you enter the international market the moment your product is first mentioned on the web. Once you decide to promote your product internationally and expand its reach, you should add localization to your workflow. Crowdin's integration with GitLab means you can seamlessly automate your localization process.\n\n\u003C!-- more -->\n\nA developer needs roughly 15 minutes to add some new texts. If a product is to be translated into, let’s say, 10 languages, the deployment is delayed for at least a week, as after the code is built, translators need time to make the translations. If several developers work on the product updates simultaneously, translations for those would delay each deployment even more. In this scenario, any team is quite unlikely to stay Agile.\n\n## Do localization in an Agile way with the GitLab + Crowdin integration\n\nTo be able to constantly ship minimum viable changes, localization should be a part of the development process. Crowdin is a localization management platform that completes your workflow by synchronizing translatable and translated files between your GitLab repository and your Crowdin localization project. This way multiple translators and developers can work simultaneously to deliver great results in less time.\n\n### Integrate Crowdin with your repository\n\nFirst of all, log into [crowdin.com](https://crowdin.com/) (you can use your GitLab account for this as well), then create a localization project or integrate an existing one. In the Crowdin project settings, you will be able to set up this integration and define whether the translatable texts should be uploaded to Crowdin from the master branch or from the development branches.\n\nThen select the file path for translations, as once they are made in Crowdin, they will be automatically added to your GitLab repository in a merge request. Each time the automatic file sync is completed the merge request in GitLab will be updated with new translations, or a new merge request will be created if the previous one was already merged.\n\nThis allows you to review translations before merging them to master and receive up-to-date translations in a few minutes after they are made, as the file sync is completed automatically. Read more details on [how to set up the GitLab + Crowdin integration](https://support.crowdin.com/gitlab-integration/).\n\n\u003Cimg src=\"/images/blogimages/gitlab_crowdin_integration.png\" alt=\"GitLab Crowdin integration\" style=\"width: 700px;\"/>{: .shadow}\n\n*\u003Csmall>A view of the integration with GitLab in Crowdin during automated synchronization.\u003C/small>*\n\n\n### Work with Agile translators\n\nWhether you decide to translate your project with the help of in-house translators or a translation agency, they should be Agile so they can make translations of different scope at any time, not just one project at a time.\n\nCrowdin project notification settings allow you to notify translators and other project members every time new texts are added to the project. This way they’ll be able to start making translations once new texts are synchronized with a project in Crowdin. You in your turn will be able to keep an eye on their contributions and overall project activity using Crowdin project reports.\n\n\u003Cimg src=\"/images/blogimages/crowdin_project_reports.png\" alt=\"Crowdin project reports\" style=\"width: 700px;\"/>{: .shadow}\n\n*\u003Csmall>Use project reports in Crowdin to easily track the main activities such as translations and approvals.\u003C/small>*\n\n## Key points to remember about localization\n\n### Localization is a continuous process\n\nIf your product changes and evolves often you should keep the localized versions up to date as well. Each time you add some new functionality, scheduled update, or a small change, the new texts should be localized as well.\n\n### The product’s UI should be flexible\n\nMake sure to use responsive design, as the same phrase in different languages might take up more or less space than the primary language of your product.\n\n### Consistency is important\n\nCreating a style guide, glossary, and using a Translation Memory is a great idea if you want to speed up the translation process and receive consistent translations at the same time.\n\nCrowdin comes with a free 10-day trial and is free of charge for open source projects. [Give it a try!](https://crowdin.com/join)\n",[9],{"slug":956,"featured":6,"template":696},"crowdin-localization-for-agile-projects","content:en-us:blog:crowdin-localization-for-agile-projects.yml","Crowdin Localization For Agile Projects","en-us/blog/crowdin-localization-for-agile-projects.yml","en-us/blog/crowdin-localization-for-agile-projects",{"_path":962,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":963,"content":969,"config":977,"_id":979,"_type":13,"title":980,"_source":15,"_file":981,"_stem":982,"_extension":18},"/en-us/blog/debug-web-apps-quickly-within-gitlab",{"title":964,"description":965,"ogTitle":964,"ogDescription":965,"noIndex":6,"ogImage":966,"ogUrl":967,"ogSiteName":683,"ogType":684,"canonicalUrls":967,"schema":968},"Debug Web apps quickly within GitLab","Jam for GitLab, a browser extension, creates GitLab issues with critical context such as browser info, console/network logs, and reproduction steps - in one click.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099168/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945%20%2810%29_arHGAEPyRHF7euCvaxE0S_1750099168482.png","https://about.gitlab.com/blog/debug-web-apps-quickly-within-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Debug Web apps quickly within GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Ivanha Paz\"}],\n        \"datePublished\": \"2024-05-08\",\n      }",{"title":964,"description":965,"authors":970,"heroImage":966,"date":972,"body":973,"category":739,"tags":974},[971],"Ivanha Paz","2024-05-08","***Editor's note: From time to time, we invite members of the community to contribute to the GitLab Blog. Thanks to [Jam.dev](https://jam.dev/gitlab) for co-creating with us.***\n\nDebugging a Web app takes a village but gathering information about bugs as they happen can be challenging. Jam.dev launched the Jam for GitLab browser extension (available for Google Chrome, Arc, Opera, and Edge) that enables all DevSecOps team members to create comprehensive debugging reports, complete with instant replays of the bug, with a single click. \n\nThe reports, which are spun up as GitLab issues, include the context engineers need to find and fix bugs, including internet speed, browser information, console/network logs, and reproduction steps. Jam also parses GraphQL requests for errors which can be copied as cURL.\n\nJam for GitLab was built using GitLab's API so it is fully integrated with the DevSecOps platform. Here’s how Jam for GitLab works:\n\n1. Click on the Jam browser extension to record your screen and take a screenshot or replay a bug that just happened. \n\n![Create issue - gif 2](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099178/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750099177866.gif)\n\n2. Jam automatically generates a GitLab issue with all the technical debugging context.\n\n![Info collected - gif 1](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099178/Blog/Content%20Images/Blog/Content%20Images/Jam_for_GitLab_debugging_aHR0cHM6_1750099177867.gif)\n\n## Why we created Jam for GitLab\nLike so many of you, we are huge fans of GitLab. A lot of Jam users love and engage with the GitLab developer community. It’s one of Jam’s top 3 most requested integrations! And with their API, GitLab makes it easy for startups like us to build new tools in the GitLab ecosystem. Building for the GitLab community is an important milestone for the Jam team. \n\nJust like GitLab values efficiency, we want to make developers’ lives easier. We believe the best way to do it is by removing a lot of unnecessary barriers for collaboration between engineering and product. We share this vision with GitLab and all of you using it to improve the lives of your customers; and quite literally build the future. \n\nLike my teammate and Jam engineer, Arég, says, “The worst part of the job is trying to debug an existing system to understand why it’s not behaving the way people expect. But you can use Jam, and maybe it’ll be less terrible, and you’ll have more time to do the best part: building something new.”\n\nGitLab is where product teams come together to build what’s next. Not just engineers, but everyone involved in the software development lifecycle. It takes a powerful platform to enable this level of collaboration. We love what GitLab stands for, and it’s truly an honor to contribute to our shared mission by making debugging easier and faster.\n\nFrom all of us at Jam, thank you to the GitLab team for being such awesome people to work with and building a product we and millions around the world love.\n\n> Ready to dramatically cut your debugging time? [Get started with Jam today.](https://jam.dev/gitlab)\n\n*Paz is DevRel lead at Jam.*\n",[9,975,976],"code review","DevSecOps",{"slug":978,"featured":6,"template":696},"debug-web-apps-quickly-within-gitlab","content:en-us:blog:debug-web-apps-quickly-within-gitlab.yml","Debug Web Apps Quickly Within Gitlab","en-us/blog/debug-web-apps-quickly-within-gitlab.yml","en-us/blog/debug-web-apps-quickly-within-gitlab",{"_path":984,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":985,"content":991,"config":999,"_id":1001,"_type":13,"title":1002,"_source":15,"_file":1003,"_stem":1004,"_extension":18},"/en-us/blog/deploy-a-nodejs-express-app-with-gitlabs-cloud-run-integration",{"title":986,"description":987,"ogTitle":986,"ogDescription":987,"noIndex":6,"ogImage":988,"ogUrl":989,"ogSiteName":683,"ogType":684,"canonicalUrls":989,"schema":990},"Deploy a NodeJS Express app with GitLab's Cloud Run integration","This tutorial will show you how to use NodeJS and Express to deploy an application to Google Cloud. This step-by-step guide will have you up and running in less than 10 minutes with the Cloud Run integration.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097892/Blog/Hero%20Images/Blog/Hero%20Images/speedlights_speedlights.png_1750097891963.png","https://about.gitlab.com/blog/deploy-a-nodejs-express-app-with-gitlabs-cloud-run-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Deploy a NodeJS Express app with GitLab's Cloud Run integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sarah Matthies\"},{\"@type\":\"Person\",\"name\":\"Noah Ing\"}],\n        \"datePublished\": \"2025-01-13\",\n      }",{"title":986,"description":987,"authors":992,"heroImage":988,"date":995,"body":996,"category":739,"tags":997},[993,994],"Sarah Matthies","Noah Ing","2025-01-13","Are you looking to deploy your NodeJS app to Google Cloud with the least\nmaintenance possible? This tutorial will show you how to utilize GitLab’s\nGoogle Cloud integration to deploy your NodeJS app in less than 10 minutes.\n\n\nTraditionally, deploying an application often requires assistance from\nproduction or DevOps engineers. This integration now empowers developers to\nhandle deployments independently. Whether you’re a solo developer or part of\na large team, this setup gives everyone the ability to deploy their\napplications efficiently.\n\n\n## Overview\n\n\n- Create a new project in GitLab\n\n- Set up your NodeJS application\n\n- Use the Google Cloud integration to create a Service account\n\n- Use the Google Cloud integration to configure Cloud Run via Merge Request\n\n- Enjoy your newly deployed NodeJS app\n\n- Follow the cleanup guide\n\n\n## Prerequisites\n\n- Owner access on a Google Cloud Platform project\n\n- Working knowledge of JavaScript/TypeScript (not playing favorites here!)\n\n- Working knowledge of GitLab CI\n\n- 10 minutes \n\n\n## Step-by-step guide\n\n\n### 1. Create a new project in GitLab\n\n\nWe decided to call our project `nodejs–express-cloud-run` for simplicity.\n\n\n![Create a new\nproject](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097905106.png)\n\n\n### 2. Upload your NodeJS app or use this example to get started.\n\n\n[Demo](https://gitlab.com/demos/templates/nodejs-cloud-run)\n\n\n**Note:** Make sure to include the `cloud-run` [CI\ntemplate](https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library/-/raw/main/gcp/cloud-run.gitlab-ci.yml)\nwithin your project.\n\n\n![cloud-run CI template\ninclude](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image6_aHR0cHM6_1750097905107.png)\n\n\n### 3. Use the Google Cloud integration to create a Service account.\n\n\nNavigate to __Operate > Google Cloud > Create Service account__.\n\n\n![Create Service account\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image10_aHR0cHM6_1750097905109.png)\n\n\nAlso configure the region you would like the Cloud Run instance deployed to.\n\n\n![Cloud Run instance deployment region\nselection](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750097905113.png)\n\n\n### 4. Go to the Deployments tab and use the Google Cloud integration to\nconfigure __Cloud Run via Merge Request__.\n\n\n![Deployments - Configuration of Cloud Run via Merge\nRequest](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750097905115.png)\n\n\nThis will open a merge request – immediately merge it.\n\n\n![Merge request for\ndeployment](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image8_aHR0cHM6_1750097905117.png)\n\n\n__Note:__ `GCP_PROJECT_ID`, `GCP_REGION`, `GCP_SERVICE_ACCOUNT`, and\n`GCP_SERVICE_ACCOUNT_KEY` will all be automatically populated from the\nprevious steps.\n\n\n![Variables\nlisting](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750097905118.png)\n\n\n### 5. Voila! Check your pipeline and you will see you have successfully\ndeployed to Google Cloud Run using GitLab CI.\n\n\n![Successful deployment to Google Cloud\nRun](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750097905119.png)\n\n\nClick the Service URL to view your newly deployed Node server.\n\n\n![View newly deployed Node\nserver](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image7_aHR0cHM6_1750097905120.png)\n\n\nIn addition, you can navigate to __Operate > Environments__ to see a list of\ndeployments for your environments.\n\n\n![Environments view of deployment\nlist](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image12_aHR0cHM6_1750097905121.png)\n\n\nBy clicking on the environment called `main`, you’ll be able to view a\ncomplete list of deployments specific to that environment.\n\n\n![Main view of deployments to specific\nenvironment](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image9_aHR0cHM6_1750097905122.png)\n\n\n### 6. Next steps\n\n\nTo get started with developing your Node application, try adding another\nendpoint. For instance, in your `index.js` file, you can add a **/bye**\nendpoint as shown below:\n\n\n```\n\napp.get('/bye', (req, res) => {\n  res.send(`Have a great day! See you!`);\n});\n\n\n```\n\n\nPush the changes to the repo, and watch the `deploy-to-cloud-run` job deploy\nthe updates. Once it’s complete, go back to the Service URL and navigate to\nthe **/bye** endpoint to see the new functionality in action.\n\n\n![Bye\nmessage](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097905/Blog/Content%20Images/Blog/Content%20Images/image11_aHR0cHM6_1750097905123.png)\n\n\n## Follow the cleanup guide\n\n\nTo prevent incurring charges on your Google Cloud account for the resources\nused in this tutorial, you can either delete the specific resources or\ndelete the entire Google Cloud project. For detailed instructions, refer to\nthe [cleanup guide\nhere](https://docs.gitlab.com/ee/tutorials/create_and_deploy_web_service_with_google_cloud_run_component/#clean-up).\n\n\n> Read more of these helpful [tutorials from GitLab solutions\narchitects](https://about.gitlab.com/blog/tags/solutions-architecture/).\n",[108,741,9,998,807],"solutions architecture",{"slug":1000,"featured":90,"template":696},"deploy-a-nodejs-express-app-with-gitlabs-cloud-run-integration","content:en-us:blog:deploy-a-nodejs-express-app-with-gitlabs-cloud-run-integration.yml","Deploy A Nodejs Express App With Gitlabs Cloud Run Integration","en-us/blog/deploy-a-nodejs-express-app-with-gitlabs-cloud-run-integration.yml","en-us/blog/deploy-a-nodejs-express-app-with-gitlabs-cloud-run-integration",{"_path":1006,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1007,"content":1013,"config":1020,"_id":1022,"_type":13,"title":1023,"_source":15,"_file":1024,"_stem":1025,"_extension":18},"/en-us/blog/deploy-remix-with-gitlab-and-cloudflare",{"title":1008,"description":1009,"ogTitle":1008,"ogDescription":1009,"noIndex":6,"ogImage":1010,"ogUrl":1011,"ogSiteName":683,"ogType":684,"canonicalUrls":1011,"schema":1012},"How to publish a Remix app to the edge with GitLab and Cloudflare","Learn how to deploy a Remix app with GitLab and Cloudflare Workers.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682517/Blog/Hero%20Images/ryoji-hayasaka-0UZj73PQVew-unsplash.jpg","https://about.gitlab.com/blog/deploy-remix-with-gitlab-and-cloudflare","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to publish a Remix app to the edge with GitLab and Cloudflare\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Janis Altherr\"}],\n        \"datePublished\": \"2022-11-21\",\n      }",{"title":1008,"description":1009,"authors":1014,"heroImage":1010,"date":1016,"body":1017,"category":739,"tags":1018},[1015],"Janis Altherr","2022-11-21","[Remix](https://remix.run) has had a significant impact in the frontend\nspace. \n\nAfter eons of backend frameworks providing some sort of frontend options\nthat are more or \n\nless hated by frontend engineers, followed by frontend frameworks that \n\nrequired a separate API for the most simple tasks that were a pain to \n\nmaintain, now suddenly there are frontend frameworks that you can write\n\nbackend code with.\n\n\nThis is ideal as an application scales: Remix offers the comfort of writing \n\nserver-side code, but should the business logic start to exceed the \n\ncapabilities of Remix, it's easy to move code to an API on a per-request\nbasis. \n\nThis comes without the need to rewrite the entire application logic, while \n\nstill retaining server-side-rendering or even pre-rendering capabilities!\n\n\nThe most performant way to deploy a Remix app is to the edge. This means \n\nthat small instances of your Remix app are run on a server close to the\nrequesting\n\nuser. An edge network consists of hundreds of \n\nservers all over the world, so you can be sure the network latency for the \n\nuser stays low.\n\n\nCurrently the most popular edge service capable of running Remix apps are \n\nCloudflare Workers. Not only does Cloudflare offer a generous free tier, \n\nWorkers are also extremely easy to deploy using GitLab CI/CD. \n\nHere's how to create a Remix app and then deploy it to Cloudflare Workers.\n\n\n## Create your Remix app\n\n\nCreate your Remix app locally using:\n\n\n```bash\n\nnpx create-remix@latest \u003Cmy-app-name>\n\n```\n\n\nThe CLI will now guide you through a series of questions. Some of those you \n\nmay answer as you prefer, but answer the following questions as indicated \n\nbelow:\n\n\n```text\n\n? What type of app do you want to create? \n\n> choose \"Just the Basics\"\n\n\n? Where do you want to deploy? [...]\n\n> choose \"Cloudflare Workers\"\n\n\n? Do you want me to run `npm install`?\n\n> answer \"Yes\"\n\n```\n\n\nInitialize the repository and add the first commit:\n\n\n```shell\n\ngit init\n\ngit add .\n\ngit commit -m \"initial commit\"\n\n```\n\n\n## Create the project in GitLab\n\n\nYou can't push the code as we have yet to set up the remote repository.\n\nVisit GitLab and create a new project. When asked, select \"Create blank \n\nproject.\"\n\n\nIn the project setup dialog, select `Edge Computing` as the `Deployment \n\ntarget`. Choose the visibility level however you like as this affects your \n\nsource code visibility.\n\n\nMake sure you unset the checkbox next to **Initialize repository with a \n\nREADME**, otherwise GitLab will begin a new Git history that you will have\nto reconcile\n\nwith your existing local one.\n\n\nOnce the project is set up, follow the instructions on how to add an \n\nexisting repository – if you've followed the above instructions to the\nletter \n\nyou don't have an existing remote yet, so you can run this simplified set\nof \n\ncommands:\n\n\n```shell\n\ngit remote add origin \u003Cgit-project-url>\n\ngit push -u origin main\n\n```\n\n\n## Configure Cloudflare\n\n\nNow set up your Cloudflare account to enable deployments from GitLab. \n\n[Login](https://dash.cloudflare.com/login) or [create an\naccount](https://dash.cloudflare.com/sign-up).\n\n\n### Subscribe to a Workers plan\n\n\nIf you are creating a Worker for the first time, you will have to sign up\nfor a Workers plan in Cloudflare.\n\n\nIn the Cloudflare dashboard's left sidebar click the entry **Workers**. Let \n\nCloudflare guide you through the setup.\n\n\n![Screenshot: Signing up for Workers in\nCloudflare](https://about.gitlab.com/images/blogimages/remix-cloudflare/workers_onboarding.png)\n\n\nOnce you're back to the Workers overview page, continue below.\n\n\n### Obtain an API token\n\n\nTo be able to deploy your Cloudflare Worker from a GitLab pipeline you will\nneed\n\nan API token. To do so, log in to the Cloudflare dashboard, then open the\n[API \n\ntokens page](https://dash.cloudflare.com/profile/api-tokens) (or find it \n\nmanually via the **user icon** > **My Profile** > **Api Tokens**).\n\n\nClick **Create Token**. Find **Edit Cloudflare Workers**, click **use \n\ntemplate**.\n\n\n![Screenshot: Select API Token template \"Edit Cloudflare\nWorkers\"](https://about.gitlab.com/images/blogimages/remix-cloudflare/api_token_template_selection.png)\n\n\nUnder **Account Resources** choose *Include* and your account name.\n\n\nUnder **Zone Resources** choose *Include*, *Specific Zone* and your site's \n\ndomain. If you haven't set up a domain, you can use a less specific rule \n\nsuch as *All zones from an account*, although we don't recommend doing this;\nthe API token could potentially be used beyond its scope if you add more\nzones to your Cloudflare account later.\n\n\n![Screenshot: API Token Account and Zone\nSettings](https://about.gitlab.com/images/blogimages/remix-cloudflare/api_token_rules.png)\n\n\n**Note:** If you have more than one account associated with the API token\nused \n\nduring deployment, you will have to update your project's `wrangler.toml`\nfile\n\nto use the correct account. [Read more in the Cloudflare\ndocumentation](https://developers.cloudflare.com/workers/wrangler/ci-cd/#account-id).\n\n\nOnce you're done setting up the API token, click **Continue to summary**, \n\nand verify your selections. It should look like this:\n\n\n![Screenshot: API Token Summary\nView](https://about.gitlab.com/images/blogimages/remix-cloudflare/api_token_summary.png)\n\n\nIf you're happy, click **Create Token**. Cloudflare will then show you the\nnew \n\ntoken. \n\n\nCopy the token and save it in GitLab: Open your project in GitLab, then \n\nvisit **Settings** > **CI/CD**. Find **Variables** and click **Expand**.\nClick \n\n**Add Variable**.\n\n\nIn the **Key** field, enter `CLOUDFLARE_API_TOKEN`.\n\nIn the **Value** field, paste the API token from Cloudflare.\n\n\nNow make sure your token isn't leaked in any logs: Check both **Protect** \n\nand **Mask**. When done, click **Add Variable**.\n\n\n![Adding a Variable in\nGitLab](https://about.gitlab.com/images/blogimages/remix-cloudflare/adding_cf_api_token_as_variable.gif)\n\n\n## Create the deployment pipeline\n\n\nThe last step is to create a GitLab pipeline. In your local repository root \n\nfolder, create a file named `.gitlab-ci.yml` and add the following content:\n\n\n```yaml\n\nstages:\n\n- deploy\n\n\ndeploy-worker:\n    image: node:lts\n    stage: deploy\n    environment: production\n    before_script:\n      # install dependencies\n      - npm ci\n    script:\n      - npm run deploy\n    rules:\n      # This rule triggers this job after any push to the default branch\n      - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH\n```\n\n\nTo learn more about how to configure your GitLab pipeline, read our \n\n[documentation](https://docs.gitlab.com/ee/ci/).\n\n\nNow add the file to the repository:\n\n\n```shell\n\ngit add .gitlab-ci.yml\n\ngit commit -m \"Add Deployment Pipeline\"\n\ngit push\n\n```\n\n\nThis last push will immediately run this pipeline. To monitor the pipeline \n\nprogress, open GitLab. In the left sidebar, find **CI/CD** > **Pipelines**. \n\nOnce the pipeline is marked as _passed_, your Remix site is live!\n\n\nIf you've used the create-app instructions from this blogpost, your app\nshould \n\nhave been configured to use the app name as the Worker's name. Check the \n\n`name` setting in your project's `wrangler.toml`.\n\n\nGo to `https://\u003Cworker-name>.\u003Ccloudflare-account-name>.workers.dev` to see \n\nyour Remix site in action. Congratulations!\n\n\nIn your Cloudflare dashboard, you can monitor your new app by selecting \n\n**Workers** from the left sidebar and then clicking on the Worker with the \n\nname of your app.\n\n\nFrom now on, any push to your repositories default branch will\nautomatically \n\nbe built and deployed to Cloudflare. \n\n\n### Use a custom Domain for your app\n\n\nIf you want to use your own domain, set up your website as a resource now.\n\n\nIn the left sidebar, click on **Websites**. In the main window, find and\nclick\n\nthe **Add Site** button.\n\n\n![Screenshot: Add a new site in\nCloudflare](https://about.gitlab.com/images/blogimages/remix-cloudflare/add_site.png)\n\n\nNow enter your site's domain. Select a plan that suits your needs.\n\nFollow the DNS setup instructions provided on the following pages.\n\n\nOnce you have set up your domain as a website in Cloudflare, go to the \n\nwebsite settings. (In the left sidebar click **Websites**, then select your \n\nsite).\n\n\n![Screenshot: Find your website on the Cloudflare\nDashboard](https://about.gitlab.com/images/blogimages/remix-cloudflare/add_route_step_1.png)\n\n\nThe left sidebar now shows the detail navigation for the selected website. \n\nClick **Workers Routes**, then click **Add Route**. \n\n\n![Screenshot: Add a new route to your\nSite](https://about.gitlab.com/images/blogimages/remix-cloudflare/add_route_step_2.png)\n\n\nIn the Add Route Modal you can add a dynamic pattern to let Cloudflare know\nwhich requests to route to your Worker. \n\nFor Remix apps that's usually all of them, so if your site's domain is \n\n`my-site.com`, use `my-site.com/*`. You can also redirect all subdomain \n\nrequests to the worker by using `*.my-site.com/*` (this is useful if you \n\nwould like to also serve your site at `www.my-site.com`).\n\n\nUnder **Service**, select your newly created Worker.\n\nUnder **Environment**, select **production**.\n\n\nClick \"Save\".\n\n\n![Screenshot: Add route\nmodal](https://about.gitlab.com/images/blogimages/remix-cloudflare/add_route_step_3.png)\n\n\nOnce the DNS servers are updated, your Remix site should be accessible with \n\nyour custom domain.\n\n\n\n## Read More\n\n\n- [Learn more about Cloudflare\nWorkers](https://developers.cloudflare.com/workers/wrangler/configuration/)\n\n- [Check out the Remix docs](https://remix.run/docs/en/v1)\n\n- [Learn about GitLab pipelines](https://docs.gitlab.com/ee/ci/)\n",[807,9,1019],"product",{"slug":1021,"featured":6,"template":696},"deploy-remix-with-gitlab-and-cloudflare","content:en-us:blog:deploy-remix-with-gitlab-and-cloudflare.yml","Deploy Remix With Gitlab And Cloudflare","en-us/blog/deploy-remix-with-gitlab-and-cloudflare.yml","en-us/blog/deploy-remix-with-gitlab-and-cloudflare",{"_path":1027,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1028,"content":1034,"config":1041,"_id":1043,"_type":13,"title":1044,"_source":15,"_file":1045,"_stem":1046,"_extension":18},"/en-us/blog/deprecating-the-cert-based-kubernetes-integration",{"title":1029,"description":1030,"ogTitle":1029,"ogDescription":1030,"noIndex":6,"ogImage":1031,"ogUrl":1032,"ogSiteName":683,"ogType":684,"canonicalUrls":1032,"schema":1033},"Deprecating cert-based Kubernetes integration in GitLab 14.5","Understand why we're deprecating this integration, how it might affect you, and get a closer look at GitLab Agent for Kubernetes.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670635/Blog/Hero%20Images/kubernetesterms.jpg","https://about.gitlab.com/blog/deprecating-the-cert-based-kubernetes-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"We are deprecating the certificate-based integration with Kubernetes in GitLab 14.5\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Viktor Nagy\"}],\n        \"datePublished\": \"2021-11-15\",\n      }",{"title":1035,"description":1030,"authors":1036,"heroImage":1031,"date":1037,"body":1038,"category":763,"tags":1039},"We are deprecating the certificate-based integration with Kubernetes in GitLab 14.5",[824],"2021-11-15","\n\nWe are deprecating the certificate-based Kubernetes integration with GitLab and all the features that\nrely on it. This is the legacy integration, [introduced](/releases/2018/01/22/gitlab-10-4-released/#gitlab-clusters-now-generally-available) early in 2018, in GitLab 10.4.\n\nIn September 2020, we started to build a more robust, secure, forthcoming, and reliable integration\nwith Kubernetes and released the [GitLab Agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/),\nwhich is the recommended methodology to connect clusters with GitLab.\n\nIn this post, we explain the reasons for the change of path, what to expect, and how this\naffects the features that rely on the certificate-based integration with Kubernetes.\n\n## What to expect\n\nThe deprecation of the certificate-based Kubernetes integration affects all the features\nthat require a cluster connected to GitLab through cluster certificates. All those features are deprecated. The certificate-based integrations will be switched off on gitlab.com starting with the GitLab 15.0 release. Self-managed users will be able to switch the features back until their final removal. [The final removal will happen](https://gitlab.com/gitlab-org/configure/general/-/issues/199) once all the collected, critical use-cases are supported with the agent and enough time was given for our users to migrate to the agent.\n\nIn regards to the existing features that rely on the certificate-based integration:\n\n- Some of the features will be migrated to use the GitLab Agent and we will\nprovide you with migration guides to help you follow along. We will communicate them\nthrough the following releases in our release posts, as usual.\n- If you already use features that depend on cluster certificates, you can keep using\nthem. But note that you might need to take extras steps in the future to migrate them\nto the Agent. However, we **do not** guarantee that we will migrate all the existing\ncertificate-based features to the Agent.\n- Existing users should not expect new functionality except for the developments required to support more recent Kubernetes versions, security and critical fixes, and community contributions. \n- If you currently do not use a deprecated feature and regardless decide to use it anyway,\nunderstand that there's a risk of having to migrate it to the Agent later, or, in the\nworst-case scenario, you might have to stop using the feature in the future.\n\nSee the updated list of the [affected features](https://docs.gitlab.com/ee/user/infrastructure/clusters/#deprecated-features) on the docs.\n\n## What this deprecation means\n\nThe deprecation means that we will not build more features on top of the existing features\nthat depend on cluster certificates. It doesn't mean that the features will stop working right now.\n\nNew features for Kubernetes clusters will be built on top of the connection between GitLab and\nyour cluster through the Agent rather than on top of the certificate-based connection.\n\nWe have [dedicated documentation](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html) to support you migrating from the certificate-based connections to agent-based connections.\n\n## What should you do for clusters not connected to GitLab yet\n\nTo connect new clusters with GitLab, use the [Agent](https://docs.gitlab.com/ee/user/clusters/agent/)\nso that you don't have to take extra steps to use the Agent later on.\n\n## Why we deprecated the certificate-based integration with Kubernetes\n\nThere were several reasons why we decided to rethink our approach to Kubernetes:\n\n- The certificate-based integration's biggest shortcoming is that it relies on direct\naccess to the Kubernetes API. Its exposure often comes with unacceptably high risk, especially for GitLab\nSaaS users.\n- The most valuable features within the integration required elevated privileges, often\nrequiring you to give cluster-admin rights to GitLab. At the same time, features that did\nnot need these privileges could not be restricted with more limited access. This means\nthat you had to grant full access to a rather simple feature, which could turn out as a liability.\n- Feedback from users implied that many of the features were never ready for production and\ncould be used only in limited situations.\n- The industry progressed, and pull-based deployments started to gain ground. And this approach\nwas mostly unknown when we built the integration.\n\nWe decided to address all these shortcomings with the GitLab Agent.\n\n## The advantages of the GitLab Agent\n\nThe integration with Kubernetes through the Agent provides many benefits compared to the\ncertificate-based integration, such as:\n\n- Security\n- Reliability\n- Scalability\n- Speed\n- Functionality\n\nCompared to the certificate-based integration, the Agent offers the following functionalities:\n\n- Configure your cluster through code. This enables a clear separation of duties and you can use well-known merge request workflows and approvals.\n- An agent can be configured using regular Kubernetes RBAC rules, maintaining access\nto your cluster safe.\n- Scaling to multiple environments is trivial as each agent connects to one environment.\n- An agent's connection to a cluster can be shared by other groups and projects to simplify\ncoordination and maintenance.\n- The Agent supports pull-based deployments, enabling modern GitOps approaches.\n- The Agent supports push-based deployments, enabling existing GitLab CI/CD workflows to\nremain functional.\n- Having a bi-directional channel between GitLab and the cluster enables a new set of integrations,\nlike surfacing container network security policy alerts and container scan results into GitLab.\n\n## What is next on the roadmap of the GitLab Agent\n\nWe identified a few high-value features on the list of deprecated features. Moreover, we know\nthat having some level of observability around the resources managed by the Agent is\nits biggest shortcoming. As a result, we are going to focus on the following three items first:\n\n- Provide [observability features for cluster resources](https://gitlab.com/groups/gitlab-org/-/epics/2493) so you can track your metrics and logs directly from GitLab.\n- [Auto DevOps and especially Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/stages.html#auto-deploy) can already by used on top of an Agent-based connection, but the setup is not easy. We will provide you with a solution soon.\n- [GitLab-Managed Clusters](https://docs.gitlab.com/ee/user/project/clusters/gitlab_managed_clusters.html#gitlab-managed-clusters-deprecated) are expected to work as they do today until we ship an equivalent or superior functionality\nbuilt around the Agent. Together with shipping this functionality, we will provide a migration guide if necessary.\n\n## We are listening\n\nPlease help us to help you. We need your feedback to help us prioritize the migration of the\ncurrent features to the Agent and to build new features based on the Agent. We are especially seeking\nfeed back around real-world, high-scale usage of the features built for using Kubernetes clusters with GitLab.\n\nIf you would be open to sharing your feedback, please start a new thread in [this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8). Feel free to mention `@nagyv-gitlab` in your comment to make sure that your comment is read and the information won't be missed.\n",[1040,9,764],"kubernetes",{"slug":1042,"featured":6,"template":696},"deprecating-the-cert-based-kubernetes-integration","content:en-us:blog:deprecating-the-cert-based-kubernetes-integration.yml","Deprecating The Cert Based Kubernetes Integration","en-us/blog/deprecating-the-cert-based-kubernetes-integration.yml","en-us/blog/deprecating-the-cert-based-kubernetes-integration",{"_path":1048,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1049,"content":1055,"config":1061,"_id":1063,"_type":13,"title":1064,"_source":15,"_file":1065,"_stem":1066,"_extension":18},"/en-us/blog/devops-on-the-edge-a-conversation-about-gitlab-and-arm",{"title":1050,"description":1051,"ogTitle":1050,"ogDescription":1051,"noIndex":6,"ogImage":1052,"ogUrl":1053,"ogSiteName":683,"ogType":684,"canonicalUrls":1053,"schema":1054},"DevOps on the edge: Upcoming collaborations between GitLab and Arm","Check out the latest news from the technical evangelist team about upcoming initiatives from GitLab and Arm.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682923/Blog/Hero%20Images/gitlab-arm-collaboration.jpg","https://about.gitlab.com/blog/devops-on-the-edge-a-conversation-about-gitlab-and-arm","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"DevOps on the edge: Upcoming collaborations between GitLab and Arm\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Priyanka Sharma\"}],\n        \"datePublished\": \"2019-10-08\",\n      }",{"title":1050,"description":1051,"authors":1056,"heroImage":1052,"date":1058,"body":1059,"category":691,"tags":1060},[1057],"Priyanka Sharma","2019-10-08","\nDevOps has moved from being a trend to an established cornerstone of the software development and delivery lifecycle. Today, the best practices of DevOps are being applied, in new and unique ways, to edge computing. As a board member of the Cloud Native Computing Foundation, I participate in open source communities regularly and over the years, I have collaborated with various folks from Arm because today where there is the edge, there is Arm.\n\nAs the technical evangelism leader at GitLab, I got involved with folks from the Arm project when collaborating on [CNCF.ci](http://cncf.ci). GitLab is a complete [DevOps platform](/solutions/devops-platform/), delivered as a single application. A key component of our product is our CI/CD pipeline that is well loved and used in the industry. Arm, through its market leadership in the mobile and embedded space, is now expanding into infrastructure space for edge-to-cloud applications. There is tremendous potential to grow within this emerging space and offer software developers a frictionless environment to develop innovative software at a rapid pace, securely.\nArm is having their annual conference [Arm TechCon 2019](https://www.armtechcon.com/) this week in San Jose, California, and I thought this is a great opportunity to highlight key projects and activities happening within the ecosystem involving Arm and GitLab:\n\n### GitLab for edge base research projects\n\nEric Van Hensbergen, R&D fellow from Arm's Research team, has been leading an effort to [use GitLab for edge base research projects](https://community.arm.com/developer/research/b/articles/posts/continuous-cross-architecture-integration-with-gitlab) creating multi-architecture images using Docker containers, including running GitLab’s 64-bit Runner on Arm instances on public cloud providers such as Packet Cloud and AWS. You can [access the runner](https://packages.gitlab.com/runner/gitlab-runner) for yourself too!\n\n### Stream processing on the edge\n\nLast month at [GitLab Commit Brooklyn](/blog/wrapping-up-commit/), GitLab’s first ever user conference, Eduardo Silva, principal engineer from Arm Treasure Data, [delivered a talk on the benefits of stream processing on the edge](https://gitlabcommit2019brooklyn.sched.com/event/TPDd/picking-up-speed-logging-stream-processing) in distributed systems using [Fluent Bit](https://fluentbit.io/) (a [Fluentd](https://www.fluentd.org/) open source sub-project).\n\n### Join the CNCF CI Working Group Monthly Meeting\n\nToday, all projects on [CNCF.CI](https://cncf.ci/) are being built and tested on both x86 and Arm architecture inside a Kubernetes test environment hosted on Packet’s bare metal infrastructure. For anyone interested, the working group hosts open meetings every month. More details are available in their [Monthly Meeting doc](https://docs.google.com/document/d/1NA4N6PvNEkHX1yzaDFr19Xlru-amRxNi2pliqudmYNA/edit). It’s a great group and I recommend people attend.\n\nThere are a lot of exciting activities happening in the edge-to-cloud and DevOps space. As a developer evangelist, I know the value Arm brings to the ecosystem and am excited to see the commencement of the GitLab and Arm partnership. More announcements to come in the near future. Stay tuned!",[108,850,9,266],{"slug":1062,"featured":6,"template":696},"devops-on-the-edge-a-conversation-about-gitlab-and-arm","content:en-us:blog:devops-on-the-edge-a-conversation-about-gitlab-and-arm.yml","Devops On The Edge A Conversation About Gitlab And Arm","en-us/blog/devops-on-the-edge-a-conversation-about-gitlab-and-arm.yml","en-us/blog/devops-on-the-edge-a-conversation-about-gitlab-and-arm",{"_path":1068,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1069,"content":1075,"config":1081,"_id":1083,"_type":13,"title":1084,"_source":15,"_file":1085,"_stem":1086,"_extension":18},"/en-us/blog/dotscience-mlops-integration",{"title":1070,"description":1071,"ogTitle":1070,"ogDescription":1071,"noIndex":6,"ogImage":1072,"ogUrl":1073,"ogSiteName":683,"ogType":684,"canonicalUrls":1073,"schema":1074},"Dotscience announces MLOps integration with GitLab","The combination of GitLab and Dotscience provides a fully integrated DevOps & MLOps platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680952/Blog/Hero%20Images/dotscience-gitlab.png","https://about.gitlab.com/blog/dotscience-mlops-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Dotscience announces MLOps integration with GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Chris Sterry, Dotscience\"}],\n        \"datePublished\": \"2019-12-18\",\n      }",{"title":1070,"description":1071,"authors":1076,"heroImage":1072,"date":1078,"body":1079,"category":298,"tags":1080},[1077],"Chris Sterry, Dotscience","2019-12-18","\n\nToday, I am proud to announce our new partnership with GitLab and [Dotscience](https://dotscience.com). GitLab and Dotscience are passionate about bringing [DevOps tools](/topics/devops/) and processes to the AI/ML ecosystem with the goal of achieving MLOps. The combination of GitLab and Dotscience provides a fully integrated DevOps & MLOps platform by combining source repository, issue tracking, and continuous integration. Together we can offer a machine learning environment that provides the ability to build, train, deploy, monitor, reproduce data, code, and models, and collaborate on notebooks.\n\n## Dotscience and GitLab integration\n\nThe integration highlights include the following:\n\n* Combine Dotscience and GitLab to achieve a complete DevOps & MLOps platform\n* Apply the same merge request workflow you know and love in GitLab to AI & ML projects with [Jupyter](https://jupyter.org) Notebooks, data, parameters & metrics with Dotscience\n* Customize the Docker images you build in Dotscience by implementing the Docker build step of deploying an ML model to production as a GitLab repo, custom Dockerfile + build pipeline\n\n## Let’s see it in action\n\n[Luke Marsden](https://uk.linkedin.com/in/luke-marsden-71b3789) and I sat down with [Tina Sturgis](/company/team/#TinaS), manager of partner marketing at GitLab, and provided a little overview of the integration.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/xIyoq6gnyEo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nReady to give it a spin? The easiest way to get started is to sign up for a free trial at Dotscience and read the integration [documentation](https://dotscience.com/partners/gitlab/).\n\nDotscience is also available on-prem, on AWS, Azure and Google Cloud, and in multi-cloud configurations.\n\nIf you have questions, please join our [Slack](https://join.slack.com/t/dotmesh-community/shared_invite/enQtMjU0NzczMTQ2MDgxLTY5MmMwZDdmZjVmOTQ3MjYxMjg3OGQwYzg5MTdiZDJmNTc3Y2I3ZWI2NTUzMGQxNTY3MDVlNTllOWJmNTE4NDQ) channel.\n",[266,9,763],{"slug":1082,"featured":6,"template":696},"dotscience-mlops-integration","content:en-us:blog:dotscience-mlops-integration.yml","Dotscience Mlops Integration","en-us/blog/dotscience-mlops-integration.yml","en-us/blog/dotscience-mlops-integration",{"_path":1088,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1089,"content":1095,"config":1101,"_id":1103,"_type":13,"title":1104,"_source":15,"_file":1105,"_stem":1106,"_extension":18},"/en-us/blog/effective-ci-cd-pipelines",{"title":1090,"description":1091,"ogTitle":1090,"ogDescription":1091,"noIndex":6,"ogImage":1092,"ogUrl":1093,"ogSiteName":683,"ogType":684,"canonicalUrls":1093,"schema":1094},"Want a more effective CI/CD pipeline? Try our pro tips","Here’s how to take your CI/CD pipeline to the next level with hands on advice about faster builds, better security and more.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681447/Blog/Hero%20Images/cicdpipelines.jpg","https://about.gitlab.com/blog/effective-ci-cd-pipelines","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Want a more effective CI/CD pipeline? Try our pro tips\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Valerie Silverthorne\"}],\n        \"datePublished\": \"2020-07-29\",\n      }",{"title":1090,"description":1091,"authors":1096,"heroImage":1092,"date":1098,"body":1099,"category":739,"tags":1100},[1097],"Valerie Silverthorne","2020-07-29","\n\nNow that your [CI/CD pipeline](/topics/ci-cd/) is up and running, it’s time to fine-tune the performance. This hands on guide will walk you through tweaks that will improve a CI/CD pipeline’s speed, functionality, security, and integration with other tools and platforms.\n\n## Built for speed\n\nCI/CD and DevOps promises faster releases and we know it’s true: Even a basic automated pipeline is much speedier than the old days of manual handoffs. But there are ways to make the CI/CD pipeline even zippier. One straightforward option that guarantees faster builds is to [autoscale runners](/blog/making-builds-faster-autoscaling-runners/). If you have 15 minutes to spare, you can link your GitLab CI pipeline to the [Google Kubernetes engine](/blog/gitlab-ci-on-google-kubernetes-engine/). And it doesn’t get much faster than using the [Auto DevOps option](/blog/guide-to-ci-cd-pipelines/) if you’re setting up a new pipeline from scratch.\n\n## Do more with less\n\nOnce a pipeline is humming along, it’s time to think about tinkering with what you have. This is one of our favorite things to do at GitLab – we even used our CI/D pipeline to [turn our group conversation into a podcast](/blog/group-conversation-podcast/). We had an [unconventional CI/CD journey](/blog/gitlab-journey-to-cicd/), which goes a long way to explaining our overall enthusiasm for this technology.\n\nOur best advice when it comes to an effective CI/CD pipeline is to think outside the box. Need build images? It’s [easy to do](/blog/building-build-images/) with your CI/CD pipeline. You can also [create a cross-project pipeline](/blog/cross-project-pipeline/), or [build a bridge between Rust and Firebase](/blog/python-rust-and-gitlab-ci/).\n\n## Make it secure\n\nIt’s fun to play around with CI/CD functionality, but it’s critical to make sure your pipeline is secure. Start by making sure you [know the threat landscape](/blog/defend-cicd-security/). If you store key data in secrets management service [Vault](https://www.vaultproject.io), here’s how GitLab [makes the integration process easier and safer](/blog/vault-integration-process/).\n\nAnd for Jenkins users, it’s simple to [create deterministic security jobs](https://docs.gitlab.com/ee/integration/jenkins.html) from within GitLab.\n\n## Work with what you have\n\nNo effective CI/CD pipeline exists in a vacuum and to get the most out of yours it’s important to seamlessly integrate with other platforms and tools.\n\nAWS users can [set up multi-account SAM deployments](/blog/multi-account-aws-sam-deployments-with-gitlab-ci/) or [autoscale GitLab CI](/blog/introducing-autoscaling-gitlab-runners-on-aws-fargate/) on Fargate.\n\nTeams working on Android projects can [can create a customized GitLab CI](/blog/setting-up-gitlab-ci-for-android-projects/) easily.\n\nAnd finally it’s possible to take advantage of Google’s Firebase, a backend-as-a-service tool, so you can enable [continuous deployment of database, serverless and apps](/blog/gitlab-ci-cd-with-firebase/).\n\n**Read more about CI/CD:**\n\n* [The four big benefits](/blog/positive-outcomes-ci-cd/) of CI/CD\n\n* [CI/CD challenges](/blog/modernize-your-ci-cd/) to consider\n\n* Everything you need to know about [Auto DevOps](/blog/auto-devops-explained/)\n\nCover image by [Jacek Dylag](https://unsplash.com/@dylu) on [Unsplash](https://www.unsplash.com)\n{: .note}\n",[108,851,9],{"slug":1102,"featured":6,"template":696},"effective-ci-cd-pipelines","content:en-us:blog:effective-ci-cd-pipelines.yml","Effective Ci Cd Pipelines","en-us/blog/effective-ci-cd-pipelines.yml","en-us/blog/effective-ci-cd-pipelines",{"_path":1108,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1109,"content":1115,"config":1121,"_id":1123,"_type":13,"title":1124,"_source":15,"_file":1125,"_stem":1126,"_extension":18},"/en-us/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"ogTitle":1110,"schema":1111,"ogImage":1112,"ogDescription":1113,"ogSiteName":683,"noIndex":6,"ogType":684,"ogUrl":1114,"title":1110,"canonicalUrls":1114,"description":1113},"Efficient DevSecOps workflows: Hands-on python-gitlab API automation","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Efficient DevSecOps workflows: Hands-on python-gitlab API automation\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Michael Friedrich\"}],\n        \"datePublished\": \"2023-02-01\",\n      }","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659883/Blog/Hero%20Images/post-cover-image.jpg","The python-gitlab library is a useful abstraction layer for the GitLab API. Dive into hands-on examples and best practices in this tutorial.","https://about.gitlab.com/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"title":1110,"description":1113,"authors":1116,"heroImage":1112,"date":1118,"body":1119,"category":739,"tags":1120},[1117],"Michael Friedrich","2023-02-01","A friend once said in a conference presentation, “Manual work is a bug.\"\nWhen there are repetitive tasks in workflows, I tend to [come back to this\nquote](https://twitter.com/dnsmichi/status/1574087419237916672), and try to\nautomate as much as possible. For example, by querying a REST API to do an\ninventory of settings, or calling API actions to create new comments in\nGitLab issues/merge requests. The interaction with the GitLab REST API can\nbe done in different ways, using HTTP requests with curl (or\n[hurl](/blog/how-to-continously-test-web-apps-apis-with-hurl-and-gitlab-ci-cd/))\non the command line, or by writing a script in a programming language. The\nlatter can become reinventing the wheel again with raw HTTP requests code,\nand parsing the JSON responses.\n\n\nThanks to the wider GitLab community, many different languages are supported by API abstraction libraries. They provide support for all API attributes, add helper functions to get/create/delete objects, and generally aim to help developers focus. The [python-gitlab library](https://python-gitlab.readthedocs.io/en/stable/) is a feature-rich and easy-to-use library written in Python.\n\n\nIn this blog post, you will learn about the basic usage of the library by working with API objects, attributes, pagination and resultsets, and dive into more concrete use cases collecting data, printing summaries and writing data to the API to create comments and commits. There is a whole lot more to learn, with many of the use cases inspired by wider community questions on the forum, Hacker News, issues, etc.\n\n\nThis blog post is a long read, so feel free to stick with the beginner's tutorial or skip to the advanced [DevSecOps](https://about.gitlab.com/topics/devsecops/) use cases, development tips and code optimizations by navigating the table of contents:\n\n\n- [Getting started](#getting-started)\n\n- [Configuration](#configuration)\n\n- [Managing objects: The GitLab Object](#managing-objects-the-gitlab-object)\n    - [Objects managers and loading](#objects-managers-and-loading)\n    - [Pagination of results](#pagination-of-results)\n    - [Working with object relationships](#working-with-object-relationships)\n    - [Working with different object collection scopes](#working-with-different-object-collection-scopes)\n- [DevSecOps use cases for API read actions](#devsecops-use-cases-for-api-read-actions)\n    - [List branches by merged state](#list-branches-by-merged-state)\n    - [Print project settings for review: MR approval rules](#print-project-settings-for-review-mr-approval-rules)\n    - [Inventory: Get all CI/CD variables that are protected or masked](#inventory-get-all-cicd-variables-that-are-protected-or-masked)\n    - [Download a file from the repository](#download-a-file-from-the-repository)\n    - [Migration help: List all certificate-based Kubernetes clusters](#migration-help-list-all-certificate-based-kubernetes-clusters)\n    - [Team efficiency: Check if existing merge requests need to be rebased after merging a huge refactoring MR](#team-efficiency-check-if-existing-merge-requests-need-to-be-rebased-after-merging-a-huge-refactoring-mr)\n- [DevSecOps use cases for API write actions](#devsecops-use-cases-for-api-write-actions)\n    - [Move epics between groups](#move-epics-between-groups)\n    - [Compliance: Ensure that project settings are not overridden](#compliance-ensure-that-project-settings-are-not-overridden)\n    - [Taking notes, generate due date overview](#taking-notes-generate-due-date-overview)\n    - [Create issue index in a Markdown file, grouped by labels](#create-issue-index-in-a-markdown-file-grouped-by-labels)\n- [Advanced DevSecOps workflows](#advanced-devsecops-workflows)\n    - [Container images to run API scripts](#container-images-to-run-api-scripts)\n    - [CI/CD integration: Release and changelog generation](#cicd-integration-release-and-changelog-generation)\n    - [CI/CD integration: Pipeline report summaries](#cicd-integration-pipeline-report-summaries)\n- [Development tips](#development-tips)\n    - [Advanced custom configuration](#advanced-custom-configuration)\n    - [CI/CD code linting for different Python versions](#cicd-code-linting-for-different-python-versions)\n- [Optimize code and performance](#optimize-code-and-performance)\n    - [Lazy objects](#lazy-objects)\n    - [Object-oriented programming](#object-oriented-programming)\n- [More use cases](#more-use-cases)\n\n- [Conclusion](#conclusion)\n\n\n## Getting started\n\n\nThe python-gitlab documentation is a great resource for [getting started guides](https://python-gitlab.readthedocs.io/en/stable/api-usage.html), object types and their available methods, and combined workflow examples. Together with the [GitLab API resources documentation](https://docs.gitlab.com/ee/api/api_resources.html), which provides the object attributes that can be used, these are the best resources to get going.\n\n\nThe code examples in this blog post require Python 3.8+, and the `python-gitlab` library. Additional requirements are specified in the `requirements.txt` file – one example requires `pyyaml` for YAML config parsing. To follow and practice the use cases code, it is recommended to clone the project, install the requirements and run the scripts. Example with Homebrew on macOS:\n\n\n```shell\n\ngit clone https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python.git\n\n\ncd gitlab-api-python\n\n\nbrew install python\n\n\npip3 install -r requirements.txt\n\n\npython3 \u003Cscriptname>.py\n\n```\n\n\nThe scripts are intentionally not using a common shared library that provides generic functions for parameter reads, or additional helper functionality, for example. The idea is to show easy-to-follow examples that can be used stand-alone for testing, and only require installing the `python-gitlab` library as a dependency. Improving the code for production use is recommended. This can also help with building a maintained API tooling project that, for example, includes container images and CI/CD templates for developers to consume on a DevSecOps platform.\n\n\n## Configuration\n\n\nWithout configuration, python-gitlab will run unauthenticated requests against the default server `https://gitlab.com`. The most common configuration settings relate to the GitLab instance to connect to, and the authentication method by specifying access tokens. Python-gitlab supports different types of configuration: A configuration file or environment variables.\n\n\nThe [configuration file](https://python-gitlab.readthedocs.io/en/stable/cli-usage.html#cli-configuration) is available for the API library bindings, and the CLI (the CLI is not explained in this blog post). The configuration file supports [credential helpers](https://python-gitlab.readthedocs.io/en/stable/cli-usage.html#credential-helpers) to access tokens directly.\n\n\nEnvironment variables as an alternative configuration method provide an easy way to run the script on terminal, integrate into container images, and prepare them for running in CI/CD pipelines.\n\n\nThe configuration needs to be loaded into the Python script context. Start by importing the `os` library to fetch environment variables using the `os.environ.get()` method. The first parameter specifies the key, the second parameter sets the default value when the variable is not available in the environment.\n\n\n```python\n\nimport os\n\n\ngl_server = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n\nprint(gl_server)\n\n```\n\n\nThe parametrization on the terminal can happen directly for the command only, or exported into the shell environment.\n\n\n```shell\n\n$ GL_SERVER=’https://gitlab.company.com’ python3 script.py\n\n\n$ export GL_SERVER=’https://gitlab.company.com’\n\n$ python3 script.py\n\n```\n\n\nIt is recommended to add safety checks to ensure that all variables are set before continuing to run the program. The following snippet imports the required libraries, reads the `GL_SERVER` environment variable and expects the user to set the `GL_TOKEN` variable. If not, the script prints and throws errors, and calls `sys.exit(1)` indicating an error status.\n\n\n```python\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n```\n\n\nWe will look into a more detailed example now which creates a connection to the API and makes an actual data request.\n\n\n## Managing objects: The GitLab object\n\n\nAny interaction with the API requires the GitLab object to be instantiated. This is the entry point to configure the GitLab server to connect, authenticate using access tokens, and more global settings for pagination, object loading and more.\n\n\nThe following example runs an unauthenticated request against GitLab.com. It is possible to access public API endpoints and for example get a specific [.gitignore template for Python](https://python-gitlab.readthedocs.io/en/stable/gl_objects/templates.html#gitignore-templates).\n\n\n[python_gitlab_object_unauthenticated.py](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_object_unauthenticated.py)\n\n\n```python\n\nimport gitlab\n\n\ngl = gitlab.Gitlab()\n\n\n# Get .gitignore templates without authentication\n\ngitignore_templates = gl.gitignores.get('Python')\n\n\nprint(gitignore_templates.content)\n\n```\n\n\nThe next sections provide more insights into:\n\n\n- [Objects managers and loading](#objects-managers-and-loading)\n\n- [Pagination of results](#pagination-of-results)\n\n- [Working with object relationships](#working-with-object-relationships)\n\n- [Working with different object collection scopes](#working-with-different-object-collection-scopes)\n\n\n### Objects managers and loading\n\n\nThe python-gitlab library provides access to GitLab resources using so-called “[managers](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#managers)\". Each manager type implements methods to work with the datasets (list, get, etc.).\n\n\nThe script shows how to access subgroups, direct projects, all projects including subgroups, issues, epics and todos. These methods and API endpoint require authentication to access all attributes. The code snippet, therefore, uses variables to get the authentication token, and also uses the `GROUP_ID` variable to specify a main group at which to start searching.\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n# https://gitlab.com/gitlab-de/use-cases/\n\nGROUP_ID = os.environ.get('GL_GROUP_ID', 16058698)\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Main\n\nmain_group = gl.groups.get(GROUP_ID)\n\n\nprint(\"Sub groups\")\n\nfor sg in main_group.subgroups.list():\n    print(\"Subgroup name: {sg}\".format(sg=sg.name))\n\nprint(\"Projects (direct)\")\n\nfor p in main_group.projects.list():\n    print(\"Project name: {p}\".format(p=p.name))\n\nprint(\"Projects (including subgroups)\")\n\nfor p in main_group.projects.list(include_subgroups=True, all=True):\n     print(\"Project name: {p}\".format(p=p.name))\n\nprint(\"Issues\")\n\nfor i in main_group.issues.list(state='opened'):\n    print(\"Issue title: {t}\".format(t=i.title))\n\nprint(\"Epics\")\n\nfor e in main_group.issues.list():\n    print(\"Epic title: {t}\".format(t=e.title))\n\nprint(\"Todos\")\n\nfor t in gl.todos.list(state='pending'):\n    print(\"Todo: {t} url: {u}\".format(t=t.body, u=t.target_url\n```\n\n\nYou can run the script [`python_gitlab_object_manager_methods.py`](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_object_manager_methods.py) by overriding the `GROUP_ID` variable on GitLab.com SaaS for your own group to analyze. The `GL_SERVER` variable needs to be specified for self-managed instance targets. `GL_TOKEN` must provide the personal access token.\n\n\n```shell\n\nexport GL_TOKEN=xxx\n\n\nexport GL_SERVER=”https://gitlab.company.com”\n\n\nexport GL_SERVER=”https://gitlab.com”\n\n\nexport GL_GROUP_ID=1234\n\n\npython3 python_gitlab_object_manager_methods.py\n\n```\n\n\nGoing forward, the example snippets won’t show the Python headers and environment variable parsing to focus on the algorithm and functionality. All scripts are open source under the MIT license and available in [this project](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python).\n\n\n### Pagination of results\n\n\nBy default, the GitLab API does not return all result sets and requires the clients to use [pagination](https://docs.gitlab.com/ee/api/rest/index.html#pagination) to iterate through all result pages. The python-gitlab library [allows users to specify the settings](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#pagination) globally in the GitLab object, or on each `list()` call. By default, all result sets would fire API requests, which can slow down the script execution. The recommended way is using `iterator=True` which returns a generator object, and API calls are fired on-demand when accessing the object.\n\n\nThe following example searches for the group name `everyonecancontribute`, and uses keyset pagination with 100 results on each page. The iterator is set to true on `gl.groups.list(iterator=True)` to fetch new result sets on demand. If the searched group name is found, the loop breaks and prints a summary, including measuring the duration of the complete search request.\n\n\n```python\n\nSEARCH_GROUP_NAME=\"everyonecancontribute\"\n\n\n# Use keyset pagination\n\n# https://python-gitlab.readthedocs.io/en/stable/api-usage.html#pagination\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN,\n    pagination=\"keyset\", order_by=\"id\", per_page=100)\n\n# Iterate over the list, and fire new API calls in case the result set does not match yet\n\ngroups = gl.groups.list(iterator=True)\n\n\nfound_page = 0\n\nstart = timer()\n\n\nfor group in groups:\n    if SEARCH_GROUP_NAME == group.name:\n        # print(group) # debug\n        found_page = groups.current_page\n        break\n\nend = timer()\n\n\nduration = f'{end-start:.2f}'\n\n\nif found_page > 0:\n    print(\"Pagination API example for Python with GitLab{desc} - found group {g} on page {p}, duration {d}s\".format(\n        desc=\", the DevSecOps platform\", g=SEARCH_GROUP_NAME, p=found_page, d=duration))\nelse:\n    print(\"Could not find group name '{g}', duration {d}\".format(g=SEARCH_GROUP_NAME, d=duration))\n```\n\n\nExecuting `python_gitlab_pagination.py` found the [everyonecancontribute group](https://gitlab.com/everyonecancontribute) on page 5.\n\n\n```shell\n\n$ python3 python_gitlab_pagination.py\n\nPagination API example for Python with GitLab, the DevSecOps platform - found group everyonecancontribute on page 5, duration 8.51s\n\n```\n\n\n### Working with object relationships\n\n\nWhen working with object relationships – for example, collecting all projects in a given group – additional steps need to be taken. The returned project objects provide limited attributes by default. Manageable objects require an additional `get()` call which requests the full project object from the API in the background. This on-demand workflow helps to avoid waiting times and traffic by reducing the immediately returned attributes.\n\n\nThe following example illustrates the problem by looping through all projects in a group, and tries to call the `project.branches.list()` function, raising an exception in the try/except flow. The second example gets a manageable project object and tries the function call again.\n\n\n```python\n\n# Main\n\ngroup = gl.groups.get(GROUP_ID)\n\n\n# Collect all projects in group and subgroups\n\nprojects = group.projects.list(include_subgroups=True, all=True)\n\n\nfor project in projects:\n    # Try running a method on a weak object\n    try:\n       print(\"🤔 Project: {pn} 💡 Branches: {b}\\n\".format(\n        pn=project.name,\n        b=\", \".join([x.name for x in project.branches.list()])))\n    except Exception as e:\n        print(\"Got exception: {e} \\n ===================================== \\n\".format(e=e))\n\n    # Retrieve a full manageable project object\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n    manageable_project = gl.projects.get(project.id)\n\n    # Print a method available on a manageable object\n    print(\"🤔 Project: {pn} 💡 Branches: {b}\\n\".format(\n        pn=manageable_project.name,\n        b=\", \".join([x.name for x in manageable_project.branches.list()])))\n```\n\n\nThe exception handler in the python-gitlab library prints the error message, and also links to the documentation. It is helpful to take a debugging note that objects might not be available to manage whenever you cannot access object attributes or function calls.\n\n\n```shell\n\n$ python3 python_gitlab_manageable_objects.py\n\n\n🤔 Project: GitLab API Playground 💡 Branches: cicd-demo-automated-comments, docs-mr-approval-settings, main\n\n\nGot exception: 'GroupProject' object has no attribute 'branches'\n\n\n\u003Cclass 'gitlab.v4.objects.projects.GroupProject'> was created via a\n\nlist() call and only a subset of the data may be present. To ensure\n\nall data is present get the object using a get(object.id) call. For\n\nmore details, see:\n\n\nhttps://python-gitlab.readthedocs.io/en/v3.8.1/faq.html#attribute-error-list\n =====================================\n```\n\n\nThe full script is located [here](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_manageable_objects.py).\n\n\n### Working with different object collection scopes\n\n\nSometimes, the script needs to collect all projects from a self-managed instance, or from a group with subgroups, or from a single project. The latter is helpful for faster testing on the required attributes, and the group fetch helps with testing at scale later. The following snippet collects all project objects into the `projects` list, and appends objects from different incoming configuration. You will also see the manageable object pattern for project in groups again.\n\n\n```python\n    # Collect all projects, or prefer projects from a group id, or a project id\n    projects = []\n\n    # Direct project ID\n    if PROJECT_ID:\n        projects.append(gl.projects.get(PROJECT_ID))\n\n    # Groups and projects inside\n    elif GROUP_ID:\n        group = gl.groups.get(GROUP_ID)\n\n        for project in group.projects.list(include_subgroups=True, all=True):\n            # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n            manageable_project = gl.projects.get(project.id)\n            projects.append(manageable_project)\n\n    # All projects on the instance (may take a while to process)\n    else:\n        projects = gl.projects.list(get_all=True)\n```\n\n\nThe full example is located in [this script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_mr_approval_rules.py) for listing MR approval rules settings for specified project targets.\n\n\n## DevSecOps use cases for API read actions\n\n\nThe authenticated access token needs [`read_api` scope](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-token-scopes).\n\n\nThe following use cases are discussed:\n\n\n- [List branches by merged state](#list-branches-by-merged-state)\n\n- [Print project settings for review: MR approval rules](#print-project-settings-for-review-mr-approval-rules)\n\n- [Inventory: Get all CI/CD variables that are protected or masked](#inventory-get-all-cicd-variables-that-are-protected-or-masked)\n\n- [Download a file from the repository](#download-a-file-from-the-repository)\n\n- [Migration help: List all certificate-based Kubernetes clusters](#migration-help-list-all-certificate-based-kubernetes-clusters)\n\n- [Team efficiency: Check if existing merge requests need to be rebased after merging a huge refactoring MR](#team-efficiency-check-if-existing-merge-requests-need-to-be-rebased-after-merging-a-huge-refactoring-mr)\n\n\n### List branches by merged state\n\n\nA common ask is to do some Git housekeeping in the project, and see how many merged and unmerged branches are floating around. [A question on the GitLab community forum](https://forum.gitlab.com/t/python-gitlab-project-branch-list-filter/80257) about filtering branch listings inspired me look into writing a [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_branches_by_state.py) that helps achieve this goal. The `branches.list()` method returns all branch objects that are stored in a temporary list for later processing for two loops: Collecting merged branch names, and not merged branch names. The `merged` attribute on the `branch` object is a boolean value indicating whether the branch has been merged.\n\n\n```python\n\nproject = gl.projects.get(PROJECT_ID, lazy=False, pagination=\"keyset\", order_by=\"updated_at\", per_page=100)\n\n\n# Get all branches\n\nreal_branches = []\n\nfor branch in project.branches.list():\n    real_branches.append(branch)\n\nprint(\"All branches\")\n\nfor rb in real_branches:\n    print(\"Branch: {b}\".format(b=rb.name))\n\n# Get all merged branches\n\nmerged_branches_names = []\n\nfor branch in real_branches:\n    if branch.default:\n        continue # ignore the default branch for merge status\n\n    if branch.merged:\n        merged_branches_names.append(branch.name)\n\nprint(\"Branches merged: {b}\".format(b=\", \".join(merged_branches_names)))\n\n\n# Get un-merged branches\n\nnot_merged_branches_names = []\n\nfor branch in real_branches:\n    if branch.default:\n        continue # ignore the default branch for merge status\n\n    if not branch.merged:\n        not_merged_branches_names.append(branch.name)\n\nprint(\"Branches not merged: {b}\".format(b=\", \".join(not_merged_branches_names)))\n\n```\n\n\nThe workflow is intentionally a step-by-step read, you can practice optimizing the Python code for the conditional branch name collection.\n\n\n\n### Print project settings for review: MR approval rules\n\n\nThe following [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_mr_approval_rules.py) walks through all collected project objects, and checks whether approval rules are specified. If the list length is greater than zero, it loops over the list and prints the settings using a JSON pretty-print method.\n\n\n```python\n    # Loop over projects and print the settings\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/merge_request_approvals.html\n    for project in projects:\n        if len(project.approvalrules.list()) > 0:\n            #print(project) #debug\n            print(\"# Project: {name}, ID: {id}\\n\\n\".format(name=project.name_with_namespace, id=project.id))\n            print(\"[MR Approval settings]({url}/-/settings/merge_requests)\\n\\n\".format(url=project.web_url))\n\n            for ar in project.approvalrules.list():\n                print(\"## Approval rule: {name}, ID: {id}\".format(name=ar.name, id=ar.id))\n                print(\"\\n```json\\n\")\n                print(json.dumps(ar.attributes, indent=2)) # TODO: can be more beautiful, but serves its purpose with pretty print JSON\n                print(\"\\n```\\n\")\n\n```\n\n\n### Inventory: Get all CI/CD variables that are protected or masked\n\n\n[CI/CD variables](https://docs.gitlab.com/ee/ci/variables/) are helpful for pipeline parameterization, and can be configured globally on the instance, in groups and in projects. Secrets, passwords and otherwise sensitive information could be stored there, too. Sometimes it can be necessary to get an overview of all CI/CD variables that are either protected or masked to get a sense of how many variables need to be updated when rotating tokens for example.\n\n\nThe following [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_all_cicd_variables_masked_or_protected.py) gets all groups and projects and tries to collect the CI/CD variables from the global instance (requires admin permissions), groups and projects (requires maintainer/owner permissions). It prints all CI/CD variables that are either protected or masked, adding that a potential secret value is stored.\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\n# Helper function to evaluate secrets and print the variables\n\ndef eval_print_var(var):\n    if var.protected or var.masked:\n        print(\"🛡️🛡️🛡️ Potential secret: Variable '{name}', protected {p}, masked: {m}\".format(name=var.key,p=var.protected,m=var.masked))\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN') # token requires maintainer+ permissions. Instance variables require admin access.\n\nPROJECT_ID = os.environ.get('GL_PROJECT_ID') #optional\n\nGROUP_ID = os.environ.get('GL_GROUP_ID', 8034603) # https://gitlab.com/everyonecancontribute\n\n\nif not GITLAB_TOKEN:\n    print(\"🤔 Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Collect all projects, or prefer projects from a group id, or a project id\n\nprojects = []\n\n# Collect all groups, or prefer group from a group id\n\ngroups = []\n\n\n# Direct project ID\n\nif PROJECT_ID:\n    projects.append(gl.projects.get(PROJECT_ID))\n\n# Groups and projects inside\n\nelif GROUP_ID:\n    group = gl.groups.get(GROUP_ID)\n\n    for project in group.projects.list(include_subgroups=True, all=True):\n        # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n        manageable_project = gl.projects.get(project.id)\n        projects.append(manageable_project)\n\n    groups.append(group)\n\n# All projects/groups on the instance (may take a while to process, use iterators to fetch on-demand).\n\nelse:\n    projects = gl.projects.list(iterator=True)\n    groups = gl.groups.list(iterator=True)\n\nprint(\"# List of all CI/CD variables marked as secret (instance, groups, projects)\")\n\n\n# https://python-gitlab.readthedocs.io/en/stable/gl_objects/variables.html\n\n\n# Instance variables (if the token has permissions)\n\nprint(\"Instance variables, if accessible\")\n\ntry:\n    for i_var in gl.variables.list(iterator=True):\n        eval_print_var(i_var)\nexcept:\n    print(\"No permission to fetch global instance variables, continueing without.\")\n    print(\"\\n\")\n\n# group variables (maintainer permissions for groups required)\n\nfor group in groups:\n    print(\"Group {n}, URL: {u}\".format(n=group.full_path, u=group.web_url))\n    for g_var in group.variables.list(iterator=True):\n        eval_print_var(g_var)\n\n    print(\"\\n\")\n\n# Loop over projects and print the settings\n\nfor project in projects:\n    # skip archived projects, they throw 403 errors\n    if project.archived:\n        continue\n\n    print(\"Project {n}, URL: {u}\".format(n=project.path_with_namespace, u=project.web_url))\n    for p_var in project.variables.list(iterator=True):\n        eval_print_var(p_var)\n\n    print(\"\\n\")\n```\n\n\nThe script intentionally does not print the variable values, this is left as an exercise for safe environments. The recommended way of storing secrets is to [use external providers](https://docs.gitlab.com/ee/ci/secrets/).\n\n\n### Download a file from the repository\n\n\nThe [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/get_raw_file_content.py) goal is download a file path from a specified branch name, and store its content in a new file.\n\n\n```python\n\n# Goal: Try to download README.md from https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/README.md\n\nFILE_NAME = 'README.md'\n\nBRANCH_NAME = 'main'\n\n\n# Search the file in the repository tree and get the raw blob\n\nfor f in project.repository_tree():\n    print(\"File path '{name}' with id '{id}'\".format(name=f['name'], id=f['id']))\n\n    if f['name'] == FILE_NAME:\n        f_content = project.repository_raw_blob(f['id'])\n        print(f_content)\n\n# Alternative approach: Get the raw file from the main branch\n\nraw_content = project.files.raw(file_path=FILE_NAME, ref=BRANCH_NAME)\n\nprint(raw_content)\n\n\n# Store the file on disk\n\nwith open('raw_README.md', 'wb') as f:\n    project.files.raw(file_path=FILE_NAME, ref=BRANCH_NAME, streamed=True, action=f.write)\n```\n\n\n### Migration help: List all certificate-based Kubernetes clusters\n\n\nThe certificate-based integration of Kubernetes clusters into GitLab [was deprecated](https://docs.gitlab.com/ee/update/deprecations.html#self-managed-certificate-based-integration-with-kubernetes). To help with migration plans, the inventory of existing groups and projects can be automated using the GitLab API.\n\n\n\n```python\n\ngroups = [ ]\n\n\n# get GROUP_ID group\n\ngroups.append(gl.groups.get(GROUP_ID))\n\n\nfor group in groups:\n    for sg in group.subgroups.list(include_subgroups=True, all=True):\n        real_group = gl.groups.get(sg.id)\n        groups.append(real_group)\n\ngroup_clusters = {}\n\nproject_clusters = {}\n\n\nfor group in groups:\n    #Collect group clusters\n    g_clusters = group.clusters.list()\n\n    if len(g_clusters) > 0:\n        group_clusters[group.id] = g_clusters\n\n    # Collect all projects in group and subgroups and their clusters\n    projects = group.projects.list(include_subgroups=True, all=True)\n\n    for project in projects:\n        # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n        manageable_project = gl.projects.get(project.id)\n\n        # skip archived projects\n        if project.archived:\n            continue\n\n        p_clusters = manageable_project.clusters.list()\n\n        if len(p_clusters) > 0:\n            project_clusters[project.id] = p_clusters\n\n# Print summary\n\nprint(\"## Group clusters\\n\\n\")\n\nfor g_id, g_clusters in group_clusters.items():\n    url = gl.groups.get(g_id).web_url\n    print(\"Group ID {g_id}: {u}\\n\\n\".format(g_id=g_id, u=url))\n    print_clusters(g_clusters)\n\nprint(\"## Project clusters\\n\\n\")\n\nfor p_id, p_clusters in project_clusters.items():\n    url = gl.projects.get(p_id).web_url\n    print(\"Project ID {p_id}: {u}\\n\\n\".format(p_id=p_id, u=url))\n    print_clusters(p_clusters)\n```\n\n\nThe full script is available [here](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/list_cert_based_kubernetes_clusters.py).\n\n\n### Team efficiency: Check if existing merge requests need to be rebased after merging a huge refactoring MR\n\n\nThe [GitLab handbook](https://handbook.gitlab.com/handbook/) repository is a large monorepo with many merge requests created, reviewed, approved and merged. Some reviews take longer than others, and some merge requests touch multiple pages when renaming a string, or [all handbook pages](/handbook/about/#count-handbook-pages). The marketing handbook needed restructuring (think of code refactoring), and as such, many directories and paths were moved or renamed. [The issue tasks](https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/13991#tasks) grew over time, and I was worried that other merge requests would run into conflicts after merging the huge changes. I remembered that the python-gitlab can fetch all merge requests in a given project, including details on the Git branch, source paths changed and much more.\n\n\nThe resulting script configures a list of source paths that are touched by all merge requests, and checks against the merge request diff with `mr.diffs.list()` and comparing if a pattern matches against the value in `old_path`. If a match is found, the script logs it, and saves the merge request in the `seen_mr` dictionary for the summary later. There are additional attributes collected to allow printing a Markdown task list with URLs for easier copy-paste into [issue descriptions](https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/13991#additional-tasks). The full script is located [here](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/search_mr_contains_updated_path.py).\n\n\n\n```python\n\nPATH_PATTERNS = [\n    'path/to/handbook/source/page.md',\n]\n\n\n# Only list opened MRs\n\n# https://python-gitlab.readthedocs.io/en/stable/gl_objects/merge_requests.html#project-merge-requests\n\nmrs = project.mergerequests.list(state='opened', iterator=True)\n\n\nseen_mr = {}\n\n\nfor mr in mrs:\n    # https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs\n    real_mr = project.mergerequests.get(mr.get_id())\n    real_mr_id = real_mr.attributes['iid']\n    real_mr_url = real_mr.attributes['web_url']\n\n    for diff in real_mr.diffs.list(iterator=True):\n        real_diff = real_mr.diffs.get(diff.id)\n\n        for d in real_diff.attributes['diffs']:\n            for p in PATH_PATTERNS:\n                if p in d['old_path']:\n                    print(\"MATCH: {p} in MR {mr_id}, status '{s}', title '{t}' - URL: {mr_url}\".format(\n                        p=p,\n                        mr_id=real_mr_id,\n                        s=mr_status,\n                        t=real_mr.attributes['title'],\n                        mr_url=real_mr_url))\n\n                    if not real_mr_id in seen_mr:\n                        seen_mr[real_mr_id] = real_mr\n\nprint(\"\\n# MRs to update\\n\")\n\n\nfor id, real_mr in seen_mr.items():\n    print(\"- [ ] !{mr_id} - {mr_url}+ Status: {s}, Title: {t}\".format(\n        mr_id=id,\n        mr_url=real_mr.attributes['web_url'],\n        s=real_mr.attributes['detailed_merge_status'],\n        t=real_mr.attributes['title']))\n```\n\n\n\n## DevSecOps use cases for API write actions\n\n\nThe authenticated access token needs full [`api` scope](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-token-scopes).\n\n\nThe following use cases are discussed:\n\n\n- [Move epics between groups](#move-epics-between-groups)\n\n- [Compliance: Ensure that project settings are not overridden](#compliance-ensure-that-project-settings-are-not-overridden)\n\n- [Taking notes, generate due date overview](#taking-notes-generate-due-date-overview)\n\n- [Create issue index in a Markdown file, grouped by labels](#create-issue-index-in-a-markdown-file-grouped-by-labels)\n\n\n### Move epics between groups\n\n\nSometimes it is necessary to move epics, similar to issues, into a different group. A question in the GitLab marketing Slack channel inspired me to look into a [feature proposal for the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/12689), [quick actions](/blog/improve-your-gitlab-productivity-with-these-10-tips/), and later, thinking about writing an API script to automate the steps. The idea is simple: Move an epic from a source group to a target group, and copy its title, description and labels. Since epics allow to group issues, they need to be reassigned to the target epic, too. Parent-child epic relationships need to be taken into account to: All child epics of the source epics need to be reassigned to the target epic.\n\n\nThe following script looks up all source [epic attributes](https://python-gitlab.readthedocs.io/en/stable/gl_objects/epics.html) first, and then creates a new target epic with minimal attributes: title and description. The labels list is copied and the changes are persisted with the `save()` call. The issues assigned to the epic need to be re-created in the target epic. The `create()` call actually creates the relationship item, not a new issue object itself. The child epics move requires a different approach, since the relationship is vice versa: The `parent_id` on the child epic needs to be compared against the source epic ID, and if matching, updated to the target epic ID. After copying everything successfully, the source epic needs to be changed into the `closed` state.\n\n\n\n```python\n\n#!/usr/bin/env python\n\n\n# Description: Show how epics can be moved between groups, including title, description, labels, child epics and issues.\n\n# Requirements: python-gitlab Python libraries. GitLab API write access, and maintainer access to all configured groups/projects.\n\n# Author: Michael Friedrich \u003Cmfriedrich@gitlab.com>\n\n# License: MIT, (c) 2023-present GitLab B.V.\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n# https://gitlab.com/gitlab-de/use-cases/gitlab-api\n\nSOURCE_GROUP_ID = os.environ.get('GL_SOURCE_GROUP_ID', 62378643)\n\n# https://gitlab.com/gitlab-de/use-cases/gitlab-api/epic-move-target\n\nTARGET_GROUP_ID = os.environ.get('GL_TARGET_GROUP_ID', 62742177)\n\n# https://gitlab.com/groups/gitlab-de/use-cases/gitlab-api/-/epics/1\n\nEPIC_ID = os.environ.get('GL_EPIC_ID', 1)\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Main\n\n# Goal: Move epic to target group, including title, body, labels, and child epics and issues.\n\nsource_group = gl.groups.get(SOURCE_GROUP_ID)\n\ntarget_group = gl.groups.get(TARGET_GROUP_ID)\n\n\n# Create a new target epic and copy all its items, then close the source epic.\n\nsource_epic = source_group.epics.get(EPIC_ID)\n\n# print(source_epic) #debug\n\n\nepic_title = source_epic.title\n\nepic_description = source_epic.description\n\nepic_labels = source_epic.labels\n\nepic_issues = source_epic.issues.list()\n\n\n# Create the epic with minimal attributes\n\ntarget_epic = target_group.epics.create({\n    'title': epic_title,\n    'description': epic_description,\n})\n\n\n# Assign the list\n\ntarget_epic.labels = epic_labels\n\n\n# Persist the changes in the new epic\n\ntarget_epic.save()\n\n\n# Epic issues need to be re-assigned in a loop\n\nfor epic_issue in epic_issues:\n    ei = target_epic.issues.create({'issue_id': epic_issue.id})\n\n# Child epics need to update their parent_id to the new epic\n\n# Need to search in all epics, use lazy object loading\n\nfor sge in source_group.epics.list(lazy=True):\n    # this epic has the source epic as parent epic?\n    if sge.parent_id == source_epic.id:\n        # Update the parent id\n        sge.parent_id = target_epic.id\n        sge.save()\n\nprint(\"Copied source epic {source_id} ({source_url}) to target epic {target_id} ({target_url})\".format(\n    source_id=source_epic.id, source_url=source_epic.web_url,\n    target_id=target_epic.id, target_url=target_epic.web_url))\n\n# Close the old epic\n\nsource_epic.state_event = 'close'\n\nsource_epic.save()\n\nprint(\"Closed source epic {source_id} ({source_url})\".format(\n    source_id=source_epic.id, source_url=source_epic.web_url))\n\n```\n\n\n\n```shell\n\n$  python3 move_epic_between_groups.py\n\nCopied source epic 725341 (https://gitlab.com/groups/gitlab-de/use-cases/gitlab-api/-/epics/1) to target epic 725358 (https://gitlab.com/groups/gitlab-de/use-cases/gitlab-api/epic-move-target/-/epics/6)\n\nClosed source epic 725341 (https://gitlab.com/groups/gitlab-de/use-cases/gitlab-api/-/epics/1)\n\n```\n\n\n\nThe [target epic](https://gitlab.com/groups/gitlab-de/use-cases/gitlab-api/epic-move-target/-/epics/5) was created and shows the expected result: Same title, description, labels, child epic, and issues.\n\n\n![Target epic which has all attributes copied from the source epic: title, description, labels, child epics, issues](/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_moved_epic_with_all_attributes.png){: .shadow}\n\n\n**Exercise**: The script does not copy [comments](https://python-gitlab.readthedocs.io/en/stable/gl_objects/notes.html) and [discussion threads](https://python-gitlab.readthedocs.io/en/stable/gl_objects/discussions.html) yet. Research and help update the script – merge requests welcome!\n\n\n\n### Compliance: Ensure that project settings are not overridden\n\n\nProject and group settings may be accidentally changed by team members with maintainer permissions. Compliance requirements need to be met. Another use case is to manage configuration with Infrastructure as Code tools, and ensure that GitLab instance/group/project/etc. configuration is persisted and always the same. Tools like Ansible or Terraform can invoke an API script, or use the python-gitlab library to perform tasks to manage settings.\n\n\nThe following example only has the `main` branch protected.\n\n\n![GitLab project settings for repositories and protected branches, main branch](/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_protected_branches_settings_main.png){: .shadow}\n\n\nLet us assume that a new `production` branch has been added and should be protected, too. The following [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/enforce_protected_branches.py) defines the dictionary of protected branches and their access levels for push/merge permissions to maintainer level, and builds the comparison logic around the [python-gitlab protected branches documentation](https://python-gitlab.readthedocs.io/en/stable/gl_objects/protected_branches.html).\n\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\n\nGITLAB_SERVER = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n# https://gitlab.com/gitlab-de/use-cases/\n\nGROUP_ID = os.environ.get('GL_GROUP_ID', 16058698)\n\nGITLAB_TOKEN = os.environ.get('GL_TOKEN')\n\n\nPROTECTED_BRANCHES = {\n    'main': {\n        'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n        'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n    },\n    'production': {\n        'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n        'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n    },\n}\n\n\nif not GITLAB_TOKEN:\n    print(\"Please set the GL_TOKEN env variable.\")\n    sys.exit(1)\n\ngl = gitlab.Gitlab(GITLAB_SERVER, private_token=GITLAB_TOKEN)\n\n\n# Main\n\ngroup = gl.groups.get(GROUP_ID)\n\n\n# Collect all projects in group and subgroups\n\nprojects = group.projects.list(include_subgroups=True, all=True)\n\n\nfor project in projects:\n    # Retrieve a full manageable project object\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/groups.html#examples\n    manageable_project = gl.projects.get(project.id)\n\n    # https://python-gitlab.readthedocs.io/en/stable/gl_objects/protected_branches.html\n    protected_branch_names = []\n\n    for pb in manageable_project.protectedbranches.list():\n        manageable_protected_branch = manageable_project.protectedbranches.get(pb.name)\n        print(\"Protected branch name: {n}, merge_access_level: {mal}, push_access_level: {pal}\".format(\n            n=manageable_protected_branch.name,\n            mal=manageable_protected_branch.merge_access_levels,\n            pal=manageable_protected_branch.push_access_levels\n        ))\n\n        protected_branch_names.append(manageable_protected_branch.name)\n\n    for branch_to_protect, levels in PROTECTED_BRANCHES.items():\n        # Fix missing protected branches\n        if branch_to_protect not in protected_branch_names:\n            print(\"Adding branch {n} to protected branches settings\".format(n=branch_to_protect))\n            p_branch = manageable_project.protectedbranches.create({\n                'name': branch_to_protect,\n                'merge_access_level': gitlab.const.AccessLevel.MAINTAINER,\n                'push_access_level': gitlab.const.AccessLevel.MAINTAINER\n            })\n```\n\n\nRunning the script prints the existing `main` branch, and a note that `production` will be updated. The screenshot from the repository settings proves this action.\n\n\n```\n\n$ python3 enforce_protected_branches.py                                                ─╯\n\nProtected branch name: main, merge_access_level: [{'id': 67294702, 'access_level': 40, 'access_level_description': 'Maintainers', 'user_id': None, 'group_id': None}], push_access_level: [{'id': 68546039, 'access_level': 40, 'access_level_description': 'Maintainers', 'user_id': None, 'group_id': None}]\n\nAdding branch production to protected branches settings\n\n```\n\n\n![GitLab project settings for repositories and protected branches, main and production branch](/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_protected_branches_settings_main_production.png){: .shadow}\n\n\n\n### Taking notes, generate due date overview\n\n\nA [Hacker News discussion about note-taking tools](https://news.ycombinator.com/item?id=32155848) inspired me to take a look into creating a Markdown table overview, fetched from files that take notes, and sorted by the parsed due date. The script is located [here](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/generate_snippets_index_by_due_date.py) and more complex to understand.\n\n\n```\n\n# 2022-07-19 Notes\n\n\nHN topic about taking notes: https://news.ycombinator.com/item?id=32152935\n\n\n\u003C!--\n\n---\n\nTags: DevOps, Learn\n\nDue: 2022-08-01\n\n---\n\n-->\n\n\n```\n\n\n### Create issue index in a Markdown file, grouped by labels\n\n\nA similar Hacker News question inspired me to write a [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/generate_issue_index_grouped_by_label.py) that parses all issues in a GitLab project by labels, and creates or updates a Markdown index file in the same repository. The issues are grouped by label.\n\n\nFirst, the issues are fetched from the project, including all labels, and stored in the `index` dictionary.\n\n\n```python\n\np = gl.projects.get(PROJECT_ID)\n\n\nlabels = p.labels.list()\n\n\nindex={}\n\n\nfor i in p.issues.list():\n    for l in i.labels:\n        if l not in index:\n            index[l] = []\n\n        index[l].append(\"#{id} - {title}\".format(id=i.id, title=i.title))\n```\n\n\nThe second step is to create a Markdown formatted listing based on the collected index data, with the label name as key, holding a list of issue strings.\n\n\n```python\n\nindex_str = \"\"\"# Issue Overview\n\n_Grouped by issue labels._\n\n\"\"\"\n\n\nfor l_name, i_list in index.items():\n    index_str += \"\\n## {label} \\n\\n\".format(label=l_name)\n\n    for i in i_list:\n        index_str += \"- {title}\\n\".format(title=i)\n```\n\n\nThe last step is to create a new file in the repository, or update an existing one. This is a little tricky because the API expects you to define the action and will throw an error if you try to update a nonexistent file. The first condition checks whether the file path exists in the repository, and then defines the `action` attribute. The `data` dictionary gets built, with the final `commits.create()` method called.\n\n\n```python\n\n# Dump index_str to FILE_NAME\n\n# Create as new commit\n\n# See https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions\n\n# for actions detail\n\n\n# Check if file exists, and define commit action\n\nf = p.files.get(file_path=FILE_NAME, ref=REF_NAME)\n\nif not f:\n    action='create'\nelse:\n    action='update'\n\ndata = {\n    'branch': REF_NAME,\n    'commit_message': 'Generate new index, {d}'.format(d=date.today()),\n    'actions': [\n        {\n            'action': action,\n            'file_path': FILE_NAME,\n            'content': index_str\n        }\n    ]\n}\n\n\ncommit = p.commits.create(data)\n\n```\n\n\n## Advanced DevSecOps workflows\n\n\n- [Container images to run API scripts](#container-images-to-run-api-scripts)\n\n- [CI/CD integration: Release and changelog generation](#cicd-integration-release-and-changelog-generation)\n\n- [CI/CD integration: Pipeline report summaries](#cicd-integration-pipeline-report-summaries)\n\n\n### Container images to run API scripts\n\n\nInstalling the Python interpreter and dependent libraries into the operating system may not always work, or it may be a barrier to using the API scripts. A container image that can be pulled from the GitLab registry is a good first step towards more DevSecOps automation and future CI/CD integrations, and provides a tested environment. The python-gitlab project [provides container images](https://python-gitlab.readthedocs.io/en/stable/index.html#using-the-docker-images) which can be used for testing.\n\n\nThe cloned script repository can be mounted into the container, and the settings are configured using environment variables. Example with Docker CLI:\n\n\n```shell\n\n$ docker run -ti -v \"`pwd`:/app\" \\\n  -e \"GL_SERVER=http://gitlab.com\" \\\n  -e \"GL_TOKEN=$GITLAB_TOKEN\" \\\n  -e \"GL_GROUP_ID=16058698\" \\\nregistry.gitlab.com/python-gitlab/python-gitlab:slim-bullseye \\\n\npython /app/python_gitlab_manageable_objects.py\n\n```\n\n\n### CI/CD integration: Release and changelog generation\n\n\nCreating a Git tag and a release in GitLab often requires a changelog attached. This provides a summary into all Git commits, all merged merge requests, or something similar that is easier to consume for everyone interested in the changes in this new release. Automating the changelog generation in CI/CD pipelines is possible using the GitLab API. The simplest list uses the Git commit history shown in the [`create_simple_changelog_from_git_history.py`](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/create_simple_changelog_from_git_history.py) script below:\n\n\n\n```python\n\nproject = gl.projects.get(PROJECT_ID)\n\ncommits = project.commits.list(ref_name='main', lazy=True, iterator=True)\n\n\nprint(\"# Changelog\")\n\n\nfor commit in commits:\n    # Generate a markdown formatted list with URLs\n    print(\"- [{text}]({url}) ({name})\".format(text=commit.title, url=commit.web_url, name=commit.author_name))\n```\n\n\nExecuting the script on the [o11y.love project](https://gitlab.com/everyonecancontribute/observability/o11y.love) will print a Markdown list with URLs.\n\n\n```shell\n\n$ python3 create_changelog_from_git_history.py\n\n# Changelog\n\n- [Merge branch 'topics-ebpf-opentelemetry' into 'main'](https://gitlab.com/everyonecancontribute/observability/o11y.love/-/commit/75df97e13e0f429803dc451aac7fee080a51f44c) (Michael Friedrich)\n\n- [Move eBPF/OpenTelemetry into dedicated topics pages ](https://gitlab.com/everyonecancontribute/observability/o11y.love/-/commit/8fa4233630ff8c1d65aff589bd31c4c2f5df36cb) (Michael Friedrich)\n\n- [Merge branch 'workshop-add-k8s-o11y-toc' into 'main'](https://gitlab.com/everyonecancontribute/observability/o11y.love/-/commit/8b7949b19af6aa6bf25f73ca1ffe8616a7dbaa00) (Michael Friedrich)\n\n- [Add TOC for Kubesimplify Kubernetes Observability workshop ](https://gitlab.com/everyonecancontribute/observability/o11y.love/-/commit/63c8ad587f43e3926e6749a62c33ad0b6f229f47) (Michael Friedrich)\n\n\n...\n\n```\n\n\n**Exercise**: The script is not production ready yet but should get you going to group by commits by Git tag/release, filter merge commits, attach the changelog file or content into the [GitLab release details](https://docs.gitlab.com/ee/api/releases/), etc.\n\n\n### CI/CD integration: Pipeline report summaries\n\n\nWhen developing new API script in Python, a CI/CD integration with automated runs can be desired, too. My recommendation is to focus on writing and testing the script stand-alone on the command line first, and once it works reliably, adapt the code to run the script to perform actions in CI/CD, too. After writing a few scripts, and practicing a lot, you will have learned to write code that can be executed on the CLI, in containers and in CI/CD jobs.\n\n\nA good preparation for CI/CD is to focus on environment variables to configure the script. The environment variables can be defined as CI/CD variables, and there is no extra work with additional configuration files, or command line parameters involved. This keeps the CI/CD configuration footprint small and reusable, too.\n\n\nAn example integration to automatically create security summaries as markdown comment in a merge request was described in the [\"Fantastic Infrastructure-as-Code security attacks and how to find them\" blog post](/blog/fantastic-infrastructure-as-code-security-attacks-and-how-to-find-them/#integrations-into-cicd-and-merge-requests-for-review). This use case required research and testing before actually writing the full API script:\n\n\n1. Read the python-gitlab documentation to learn how [merge request comments (notes)](https://python-gitlab.readthedocs.io/en/stable/gl_objects/notes.html#project-notes) can be created.\n\n2. Create a test project and a test merge request for testing.\n\n3. Start writing code which instantiates the GitLab connection object, fetches the project object, and gets the merge request object from a pre-defined ID.\n\n4. Run `mr.notes.create({‘body’: ‘This is a test by dnsmichi’})`\n\n5. Iterate on the body content and pre-fill a string with a markdown table.\n\n6. Fetch pre-defined CI/CD variables to get the `CI_MERGE_REQUEST_ID` value which will be required to update as target.\n\n6. Verify the API permissions and learn that the CI job token is not sufficient.\n\n7. Implement the full algorithm, integrated CI/CD testing and add documentation.\n\n\nThe script runs continuously after security scans have been completed with a report. Another use case can be using [Pipeline schedules](https://docs.gitlab.com/ee/ci/pipelines/schedules.html) which provide synchronization capabilities, and the comments get posted to an issue summary.\n\n\n## Development tips\n\n\nCode and abstraction libraries are helpful but sometimes it can be hard to see the problem why an attribute or object does not provide the expected behavior. It is helpful to take a step back, and look into different ways to fetch data from the REST API, for example [using jq and curl](/blog/devops-workflows-json-format-jq-ci-cd-lint/). The [GitLab CLI](/blog/introducing-the-gitlab-cli/) can also be used to query the API and get immediate results.\n\n\nDeveloping scripts that interact with APIs can become a repetitive task, adding more needed attributes, and the need to learn about object relations, methods and how to store the retrieved data. Especially for larger datasets, it can be a good idea to use the JSON library to dump data structures into a file cache on disk, and provide a debug configuration option to read the data from that file, instead of firing the API requests again all the time. This also helps to mitigate potential rate limiting.\n\n\nAdding timing points to the code can help measure the performance, and efficiency of the algorithm used. The following snippet [measures the duration](https://stackoverflow.com/questions/7370801/how-do-i-measure-elapsed-time-in-python ) of requests to retrieve the merge request status. It is part of a script that was used to analyze a potential problem with the `detailed_merge_status` attribute in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/386661#note_1237757295).\n\n\n```\n\nmrs = project.mergerequests.list(state='opened', iterator=True, with_merge_status_recheck=True)\n\n\nfor mr in mrs:\n    start = timer()\n    #print(mr.attributes) #debug\n    # https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-request-diffs\n    real_mr = project.mergerequests.get(mr.get_id())\n\n    print(\"- [ ] !{mr_id} - {mr_url}+ Status: {s}, Title: {t}\".format(\n        mr_id=real_mr.attributes['iid'],\n        mr_url=real_mr.attributes['web_url'],\n        s=real_mr.attributes['detailed_merge_status'],\n        t=real_mr.attributes['title']))\n\n    end = timer()\n    duration = end - start\n    if duration > 1.0:\n        print(\"ALERT: > 1s \")\n    print(\"> Execution time took {s}s\".format(s=(duration)))\n```\n\n\nMore tips are discussed in the following sections:\n\n\n- [Advanced custom configuration](#advanced-custom-configuration)\n\n- [CI/CD code linting for different Python versions](#cicd-code-linting-for-different-python-versions)\n\n\n### Advanced custom configuration\n\n\nWhen you are developing a script that requires advanced custom configuration, choose a format that fits best into existing infrastructure and development guidelines. Python provides libraries for parsing YAML, JSON, etc. The following example configuration file and script showcase a YAML configuration option. It is based on [a script that automatically updates a list of issues/epics](https://gitlab.com/gitlab-de/gitlab-api-automated-commenter) with a comment, reminding responsible team members for a recurring update for a cross-functional initiative at GitLab.\n\n\n[python_gitlab_custom_yaml_config.yml](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_custom_yaml_config.yml)\n\n```yaml\n\ntasks:\n  - name: \"Backend\"\n    url: \"https://gitlab.com/group1/project2/-/issues/1\"\n  - name: \"Frontend\"\n    url: \"https://gitlab.com/group2/project4/-/issues/2\"\n```\n\n\n[python_gitlab_custom_script_config_yaml.py](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_custom_script_config_yaml.py)\n\n```python\n\nimport os\n\nimport yaml\n\n\nCONFIG_FILE = os.environ.get('GL_CONFIG_FILE', \"python_gitlab_custom_yaml_config.yml\")\n\n\n# Read config\n\nwith open(CONFIG_FILE, mode=\"rt\", encoding=\"utf-8\") as file:\n    config = yaml.safe_load(file)\n    #print(config) #debug\n\ntasks = []\n\nif \"tasks\" in config:\n    tasks = config['tasks']\n\n# Process the tasks\n\nfor task in tasks:\n    print(\"Task name: '{n}' Issue URL to update: {id}\".format(n=task['name'], id=task['url']))\n    # print(task) #debug\n```\n\n\n```shell\n\n$ python3 python_gitlab_custom_script_config_yaml.py                                     ─╯\n\nTask name: 'Backend' Issue URL to update: https://gitlab.com/group1/project2/-/issues/1\n\nTask name: 'Frontend' Issue URL to update: https://gitlab.com/group2/project4/-/issues/2\n\n```\n\n\n\n### CI/CD code linting for different Python versions\n\n\nAll code examples in this blog post have been tested with Python 3.8, 3.9, 3.10 and 3.11, using [parallel matrix builds in GitLab CI/CD](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/.gitlab-ci.yml) and pyflakes for code linting. Automating the tests helps focus on development, and ensuring that the target platforms support the language features. Some Linux distributions do not provide Python 3.11 yet for example, and Python language features cannot be used or may need an alternative implementation.\n\n\n```yaml\n\ninclude:\n  - template: Security/SAST.gitlab-ci.yml\n  - template: Dependency-Scanning.gitlab-ci.yml\n  - template: Secret-Detection.gitlab-ci.yml\n\nstages:\n  - lint\n  - test\n\n.python-req:\n  image: python:$VERSION\n  script:\n    - pip install -r requirements_dev.txt\n  parallel:\n    matrix:\n      - VERSION: ['3.8', '3.9', '3.10', '3.11']   # https://hub.docker.com/_/python\n\nlint-python:\n  extends: .python-req\n  stage: lint\n  script:\n    - !reference [.python-req, script]\n    - pyflakes .\n\nsast:\n  stage: test\n\n```\n\n\n## Optimize code and performance\n\n\n- [Lazy objects](#lazy-objects)\n\n- [Object-oriented programming](#object-oriented-programming)\n\n\n### Lazy objects\n\n\nWhen working with objects that do not immediately need all attributes loaded, you can specify the [`lazy=True`](https://python-gitlab.readthedocs.io/en/stable/api-usage.html#lazy-objects) attribute to not invoke an API call immediately. A follow-up method call will then invoke the required API calls.\n\n\n\n```python\n\n# Lazy object, no API call\n\nproject = gl.projects.get(PROJECT_ID, lazy=True)\n\n\ntry:\n    print(\"Trying to access 'snippets_enabled' on a lazy loaded project object. This will throw an exception that we capture.\")\n    print(\"Project settings: snippets_enabled={b}\".format(b=project.snippets_enabled))\nexcept Exception as e:\n    print(\"Accessing lazy loaded object failed: {e}\".format(e=e))\n\nproject.snippets_enabled = True\n\n\nproject.save() # This creates an API call\n\n\nprint(\"\\nLazy object was loaded after save() call.\")\n\nprint(\"Project settings: snippets_enabled={b}\".format(b=project.snippets_enabled))\n\n\n```\n\n\nExecuting the [`python_gitlab_lazy_objects.py`](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_lazy_objects.py) script shows that the lazy object did not fire an API call, thus throwing an exception when accessing the project setting `snippets_enabled`. To show that the object still can be managed, the code catches the exception to proceed with updating the setting locally, and calling `project.save()` to persist the change and call the API update.\n\n\n```shell\n\n$ python3 python_gitlab_lazy_objects.py                                                ─╯\n\nTrying to access 'snippets_enabled' on a lazy loaded project object. This will throw an exception that we capture.\n\nAccessing lazy loaded object failed: 'Project' object has no attribute 'snippets_enabled'\n\n\nIf you tried to access object attributes returned from the server,\n\nnote that \u003Cclass 'gitlab.v4.objects.projects.Project'> was created as\n\na `lazy` object and was not initialized with any data.\n\n\nLazy object was loaded after save() call.\n\nProject settings: snippets_enabled=True\n\n```\n\n\n### Object-oriented programming\n\n\nFor better code quality, it makes sense to follow object-oriented programming and create classes that store attributes, provide methods, and enable better unit testing. The [storage analyzer tool](https://gitlab.com/gitlab-de/gitlab-storage-analyzer) was developed to create a summary of projects that consume lots storage, for example CI/CD job artifacts. By inspecting the [Git history](https://gitlab.com/gitlab-de/gitlab-storage-analyzer/-/commits/main), you can learn from the different iterations to a first working version.\n\n\nThe following example is a trimmed version which shows how to initialize the class `GitLabUseCase`, add helper functions for logging and JSON pretty-printing, and print all project attributes.\n\n\n```python\n\n#!/usr/bin/env python\n\n\nimport gitlab\n\nimport os\n\nimport sys\n\nimport json\n\n\n# Print an error message with prefix, and exit immediately with an error code.\n\ndef error(text):\n    logger(\"ERROR\", text)\n    sys.exit(1)\n\n# Log a line with a given prefix (e.g. INFO)\n\ndef logger(prefix, text):\n    print(\"{prefix}: {text}\".format(prefix=prefix, text=text))\n\n# Return a pretty-printed JSON string with indent of 4 spaces\n\ndef render_json_output(data):\n    return json.dumps(data, indent=4, sort_keys=True)\n\n# Class definition\n\nclass GitLabUseCase(object):\n    # Initializer to set all required parameters\n    def __init__(self, verbose, gl_server, gl_token, gl_project_id):\n        self.verbose = verbose\n        self.gl_server = gl_server\n        self.gl_token = gl_token\n        self.gl_project_id = gl_project_id\n\n    # Debug logger, controlled via verbose parameter\n    def log_debug(self, text):\n        if self.verbose:\n            print(\"DEBUG: {d}\".format(d=text))\n\n    # Connect to the GitLab server and store the connection handle\n    def connect(self):\n        self.log_debug(\"Connecting to GitLab API at {s}\".format(s=self.gl_server))\n        # Supports personal/project/group access token\n        # https://docs.gitlab.com/ee/api/index.html#personalprojectgroup-access-tokens\n        self.gl = gitlab.Gitlab(self.gl_server, private_token=self.gl_token)\n\n    # Use the stored connection handle to fetch a project object by id,\n    # and print its attribute with JSON pretty-print.\n    def print_project_attributes(self):\n        project = self.gl.projects.get(self.gl_project_id)\n        print(render_json_output(project.attributes))\n\n\n## main\n\nif __name__ == '__main__':\n    # Fetch configuration from environment variables.\n    # The second parameter specifies the default value when not provided.\n    gl_verbose = os.environ.get('GL_VERBOSE', False)\n    gl_server = os.environ.get('GL_SERVER', 'https://gitlab.com')\n\n    gl_token = os.environ.get('GL_TOKEN')\n\n    if not gl_token:\n        error(\"Please specifiy the GL_TOKEN env variable\")\n\n    gl_project_id = os.environ.get('GL_PROJECT_ID', 42491852) # https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python\n\n    # Instantiate new object and run methods\n    gl_use_case = GitLabUseCase(gl_verbose, gl_server, gl_token, gl_project_id)\n    gl_use_case.connect()\n    gl_use_case.print_project_attributes()\n```\n\n\nRunning the [script](https://gitlab.com/gitlab-de/use-cases/gitlab-api/gitlab-api-python/-/blob/main/python_gitlab_oop_helpers.py) with the `GL_PROJECT_ID` environment variable pretty-prints the project attributes as JSON on the terminal.\n\n\n![Example script that pretty-prints the project object attributes as JSON](/images/blogimages/efficient-devsecops-workflows-python-gitlab-handson/python_gitlab_oop_example_terminal_output_project_attributes.png){: .shadow}\n\n\n## More use cases\n\n\nBetter performance with API requests can be achieved by looking into parallelization and threading in Python. Users have been testing the storage analyzer script, and provided feedback to optimize the performance for the single-threaded script by using tasks and [Python threading](https://realpython.com/intro-to-python-threading/), similar to [this community project](https://gitlab.com/thelabnyc/gitlab-storage-cleanup). I might follow up on this topic in a future blog post, there are many more great use cases to cover using python-gitlab.\n\n\nThere is so much more to learn, here are a few examples from the GitLab community forum that could not make it into this blog post:\n\n\n* [Fetch review app environment URL from Merge Request](https://forum.gitlab.com/t/fetch-review-app-environment-url-from-merge-request/71335/2)\n\n* [Project visibility, project features, permissions](https://forum.gitlab.com/t/project-visibility-project-features-permissions-settings-api/32242)\n\n* [Download GitLab CI/CD job artifacts using Python](https://forum.gitlab.com/t/download-gitlab-ci-jobs-artifacts-using-python/25436/$)\n\n\n## Conclusion\n\n\nThe python-gitlab library helps to abstract raw REST API calls, and to keep access to attributes, functions and objects short and relatively easy. There are many use cases that can be solved efficiently. Alternative programming language libraries for the GitLab REST API are available [in the API clients section here](/partners/technology-partners/#api-clients).\n\n\nThe [GitLab Community Forum](https://forum.gitlab.com/) is a great place to collaborate on use cases and questions about possible solutions or code snippets. We'd love to hear from you about your use cases and challenges using the python-gitlab library.\n\n\nShoutout to the python-gitlab maintainers and contributors, developing this fantastic API library for many years now! If this blog post and the python-gitlab library helped you get more efficient, please consider [contributing to python-gitlab](https://python-gitlab.readthedocs.io/en/stable/#contributing). When there is a GitLab API feature missing, look into [contributing to GitLab](https://about.gitlab.com/community/contribute/), too. Thank you!\n\n\n\nCover image by [David Clode](https://unsplash.com/@davidclode) on [Unsplash](https://unsplash.com/photos/cxMJYcuCLEA)\n\n{: .note}\n",[9,807,976,493],{"slug":1122,"featured":6,"template":696},"efficient-devsecops-workflows-hands-on-python-gitlab-api-automation","content:en-us:blog:efficient-devsecops-workflows-hands-on-python-gitlab-api-automation.yml","Efficient Devsecops Workflows Hands On Python Gitlab Api Automation","en-us/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation.yml","en-us/blog/efficient-devsecops-workflows-hands-on-python-gitlab-api-automation",{"_path":1128,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1129,"content":1135,"config":1141,"_id":1143,"_type":13,"title":1144,"_source":15,"_file":1145,"_stem":1146,"_extension":18},"/en-us/blog/eks-gitlab-integration",{"title":1130,"description":1131,"ogTitle":1130,"ogDescription":1131,"noIndex":6,"ogImage":1132,"ogUrl":1133,"ogSiteName":683,"ogType":684,"canonicalUrls":1133,"schema":1134},"Simple deployment to Amazon EKS","Amazon EKS is now GA! We’ve partnered with AWS to make sure GitLab support is available out of the gate. Here’s how you can take advantage.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666959/Blog/Hero%20Images/gitlab-aws-cover.png","https://about.gitlab.com/blog/eks-gitlab-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Simple deployment to Amazon EKS\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"William Chia\"}],\n        \"datePublished\": \"2018-06-06\",\n      }",{"title":1130,"description":1131,"authors":1136,"heroImage":1132,"date":1138,"body":1139,"category":763,"tags":1140},[1137],"William Chia","2018-06-06","\n\nUPDATE: As of GitLab 12.5 you can create EKS clusters from GitLab using the [EKS Integration](https://about.gitlab.com/releases/2019/11/22/gitlab-12-5-released/#easily-create-and-deploy-to-an-eks-cluster)\n{: .alert .alert-info .note} \n\nRecently, Amazon announced that Elastic Container Service for Kubernetes (EKS) is generally available. Previously only open to a few folks via request access, EKS is now available to everyone, allowing all users to get managed Kubernetes clusters on AWS. In light of this development, we’re excited to announce official support for EKS with GitLab.\n\nGitLab is designed for Kubernetes. While you can use GitLab to deploy anywhere, from bare metal to VMs, when you deploy to Kubernetes, you get access to the most powerful features. In this post, I’ll walk through our Kubernetes integration, highlight a few key features, and discuss how you can use the integration with EKS.\n\n## What’s EKS?\n\nManually setting up and managing Kubernetes can be a time-intensive process. The time it takes to install and operate Kubernetes is time you could be spending building software. Amazon EKS is a managed Kubernetes service, which means Amazon does the heavy lifting, such as provisioning, upgrades, and patching. EKS runs upstream Kubernetes and is Certified Kubernetes Conformant, so it’s compatible with existing plugins and tooling. And, of course, if you are an AWS user, EKS is the only Kubernetes service that lets you take advantage of tight integration with other AWS services and features.\n\n![Amazon EKS](https://about.gitlab.com/images/blogimages/eks-integration/amazon-eks-logo.png){: .medium.center}\n\n## Kubernetes integration\n\nGitLab’s tight [integration with Kubernetes](/solutions/kubernetes/) unlocks a set of powerful GitLab features along with the ability to [one-click install](https://docs.gitlab.com/ee/user/project/clusters/index.html#installing-applications) applications like Helm, Ingress, Prometheus, and GitLab Runner to your cluster. In this post, I’ll highlight a few key features: Auto DevOps, Deploy Boards, and Incremental Rollout. For a full list, check out the [Kubernetes integration docs](https://docs.gitlab.com/ee/user/project/clusters/index.html#what-you-can-get-with-the-kubernetes-integration).\n\n## Auto DevOps: Just commit and GitLab does the rest\n\nThe first GitLab feature that relies on Kubernetes is Auto DevOps. Auto DevOps automatically builds, tests, deploys, and monitors your application. It’s like an application PaaS without the scaling limitations.\n\n![GitLab Auto DevOps](https://about.gitlab.com/images/blogimages/eks-integration/gitlab-auto-devops.png){: .shadow.medium.center}\n\n## Deploy Boards: Get visibility into deployments\n\nDeploy Boards give you a live view of the current health and status of each environment running on Kubernetes, displaying the status of pods in deployment. You can watch as your software is deployed to each pod so you know what percentage of your application is running the new code and when a deployment is complete across your entire fleet.\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/eks-integration/gitlab-deploy-boards.png){: .shadow.medium.center}\n\n## Incremental rollout: Safeguard your users\n\nShipping a new production release always comes with a bit of anxiety. Even with rigorous testing, new code in production can end up doing weird things to your app that degrade the user experience. With incremental rollout, you can choose to deploy to only 10, 25, 50, or 100 percent of your fleet. Incremental rollouts allow you to monitor what’s going on, and if anything is amiss, you can roll back the changes before problems affect your entire user base.\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/eks-integration/gitlab-incremental-rollout.png){: .shadow.medium.center}\n\n## Getting started with GitLab and Amazon EKS\n\nYou can connect an Amazon EKS cluster to your GitLab project by logging into GitLab and heading to CI/CD > Kubernetes. For a step-by-step walkthrough, check out the [GitLab Amazon EKS docs](https://docs.gitlab.com/ee/user/project/clusters/add_eks_clusters.html).\n",[9,763],{"slug":1142,"featured":6,"template":696},"eks-gitlab-integration","content:en-us:blog:eks-gitlab-integration.yml","Eks Gitlab Integration","en-us/blog/eks-gitlab-integration.yml","en-us/blog/eks-gitlab-integration",{"_path":1148,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1149,"content":1155,"config":1162,"_id":1164,"_type":13,"title":1165,"_source":15,"_file":1166,"_stem":1167,"_extension":18},"/en-us/blog/elasticsearch-update",{"title":1150,"description":1151,"ogTitle":1150,"ogDescription":1151,"noIndex":6,"ogImage":1152,"ogUrl":1153,"ogSiteName":683,"ogType":684,"canonicalUrls":1153,"schema":1154},"Update: The challenge of enabling Elasticsearch on GitLab.com","How we got started with enabling Elasticsearch on the largest GitLab instance, GitLab.com.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666832/Blog/Hero%20Images/enable-global-search-elasticsearch.jpg","https://about.gitlab.com/blog/elasticsearch-update","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Update: The challenge of enabling Elasticsearch on GitLab.com\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Nick Thomas\"}],\n        \"datePublished\": \"2019-07-16\",\n      }",{"title":1150,"description":1151,"authors":1156,"heroImage":1152,"date":1158,"body":1159,"category":739,"tags":1160},[1157],"Nick Thomas","2019-07-16","\nBack in March, [Mario](/company/team/#mdelaossa) shared some of the [lessons we'd learned from our last attempt to enable\nElasticsearch](/blog/enabling-global-search-elasticsearch-gitlab-com/) on GitLab.com, an integration that would unlock both [Advanced Global Search](https://docs.gitlab.com/ee/user/search/advanced_search.html)\nand [Advanced Syntax Search](https://docs.gitlab.com/ee/user/search/advanced_search.html). Since then, we've been working hard to address problems with the integration and prepare for [another attempt](https://gitlab.com/groups/gitlab-org/-/epics/853).\n\n## Selective indexing\n\nAt the heart of our dilemma was a classic \"chicken and egg\" problem. We needed\nto gather more information about [Elasticsearch](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html) to make improvements to the total\nindex size, but without an active deployment, that information was very hard to\ngather. Customer feedback and small-scale testing in development environments\nall help, but [dogfooding](https://handbook.gitlab.com/handbook/values/#dogfooding)\nthe integration is the best way to get the information we require.\n\nTo resolve this, we prioritized changes to enable Elasticsearch integration on\nGitLab.com. Since the index size was a hard problem, this meant some kind of\nselective indexing was necessary, so we've added\n[per-project and per-group controls](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html).\n\nOn Jun. 24, 2019, we enabled the integration for the `gitlab-org` group on\nGitLab.com. Now, any searches at the group or project level will make use of the\nElasticsearch index, and the advanced features the integration unlocks will be available.\nWe figured, why not [give it a try](https://gitlab.com/search?search=gitlab-org+%28gitaly+%7C+ee%29&group_id=9970)?\n\nThe total index size for this group – which includes about 500 projects – is around 2.2\nmillion documents and 15GB of data, which is really easy to manage from the point of view of\nElasticsearch administration. The indexing operation itself didn't [go as smoothly as we hoped](https://gitlab.com/gitlab-com/gl-infra/production/issues/800), however!\n\n## Bug fixes\n\nAnother advantage to having selective Elasticsearch indexing enabled on GitLab.com\nis that our engineers need confidence that the feature is performant,\nthat it won't threaten the overall stability of GitLab.com, and that it is\nsubstantially bug-free. So we went through a [Production Readiness Review](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/64)\nbefore enabling it. The review uncovered a number of pre-existing bugs and new regressions, which have all been fixed in the\n[12.0 release](/releases/2019/06/22/gitlab-12-0-released/). Some of the bugs included:\n\n* [Elasticsearch was sometimes used for searches, even when disabled](https://gitlab.com/gitlab-org/gitlab-ee/issues/11795)\n* [Performance regression indexing database content](https://gitlab.com/gitlab-org/gitlab-ee/issues/11595)\n* [Regression searching for some projects at group level](https://gitlab.com/gitlab-org/gitlab-ee/issues/12091)\n* [Regression visiting page 2 of search results](https://gitlab.com/gitlab-org/gitlab-ee/issues/12254)\n* [Wiki indexing still relied on a shared filesystem](https://gitlab.com/gitlab-org/gitlab-ee/issues/11269)\n* [Searching snippets with Elasticsearch enabled still queries the database, not Elasticsearch](https://gitlab.com/gitlab-org/gitlab-ee/issues/10548)\n\nWe still can't claim to be bug-free, of course, but the picture is a lot rosier than if we'd attempted to roll out this feature without first using it ourselves.\n\nWe'd tested the new indexing code on our staging environment, but this was last\nrefreshed more than a year ago, and was significantly smaller than the group on\nGitLab.com, containing around 150 projects. As a result, some bugs and\nscalability issues were uncovered for the first time in production. We're\naddressing them with high priority in the 12.1 and 12.2 releases. The scaling issues include:\n\n* [Project imports unconditionally enqueue an ElasticCommitIndexerWorker](https://gitlab.com/gitlab-org/gitlab-ee/issues/12362)\n* [Allow maximum bulk request size to be configured](https://gitlab.com/gitlab-org/gitlab-ee/issues/12375)\n* [Intelligently retry bulk-insert failures when indexing](https://gitlab.com/gitlab-org/gitlab-ee/issues/12372)\n* [Note bulk indexing often fails due to statement timeout](https://gitlab.com/gitlab-org/gitlab-ee/issues/12402)\n* [Cannot index large snippets](https://gitlab.com/gitlab-org/gitlab-ee/issues/12111)\n* [Removing documents from the index can fail with a conflict error](https://gitlab.com/gitlab-org/gitlab-ee/issues/12114)\n\nOnce these issues are addressed, indexing at scale should be quick, easy, and\nreliable. Indexing at scale is invaluable from the point of view of an engineer trying out\nchanges to reduce total index size.\n\n## Administration\n\nAnother area for improvement is administering the indexing process\nitself. Although GitLab automatically creates, updates, and removes documents\nfrom the index when changes are made, backfilling existing data required manual\nintervention, running a set of complicated (and slow) rake tasks to get the\npre-existing data into the Elasticsearch index. Unless these instructions were\nfollowed correctly, search results would be incomplete. There was also no way\nto configure a number of important parameters for the indexes created by GitLab.\n\nWhen using the selective indexing feature, GitLab now automatically enqueues\n\"backfill\" tasks for groups and projects as they are added, and removes the\nrelevant records from the index when they are supposed to be removed. We've also made it possible to\n[configure the number of shards and replicas](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html)\nfor the Elasticsearch index directly in the admin panel, so when GitLab creates\nthe index for you, there's no need to manually change the parameters afterwards.\n\nPersonal snippets are the one type of document that won't be respected in the\nselective-indexing case. To ensure they show up in search results, you'll still\nneed to run the [`gitlab:elastic:index_snippets`](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html) rake task [for now](https://gitlab.com/gitlab-org/gitlab-ee/issues/12333).\n\nThere are also improvements if you're not using selective indexing – the admin\narea now has a \"Start indexing\" button. Right now, this only makes sense if\nstarting from an empty index, and doesn't index personal snippets either, but\nwe're hopeful we can [remove the rake tasks entirely](https://gitlab.com/gitlab-org/gitlab-ee/issues/11206)\nin the future.\n\n## What next?\n\nWe're really happy to have Elasticsearch enabled for the `gitlab-org` group, but\nthe eventual goal is to have it [enabled on all of GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/153).\nWe'll be rolling it out to more groups in the future.\n\nTo get there, we'll need to continue to improve the\n[administration experience](https://gitlab.com/groups/gitlab-org/-/epics/428) using Elasticsearch.\nFor instance, it's still difficult to see the indexing status of a group or\nproject at a glance, a function that would be really useful for our support team to answer\nqueries like \"Why isn't this search term returning the expected results?\"\n\n### Managing the Elasticsearch schema is also a challenge\n\nCurrently, we take the easy route of reindexing everything if we need to change some aspect of the\nschema, which doesn't scale well as the index gets larger. [Some\nwork on this is ongoing](https://gitlab.com/gitlab-org/gitlab-ee/issues/328),\nand the eventual goal is for GitLab to automatically manage changes to the\nElasticsearch index in the same way it does for the database.\n\n[Reducing the index size](https://gitlab.com/groups/gitlab-org/-/epics/429) is\nstill a huge priority, and we hope to make progress on this now that we\nhave an Elasticsearch deployment to iterate against.\n\n### We'd also like to improve the quality of search results\n\nFor example, we have\nreports of code search [failing to find certain identifiers](https://gitlab.com/gitlab-org/gitlab-ee/issues/10693) and we'd like to use the Elasticsearch index in more contexts, such as for\n[filtered search](https://gitlab.com/gitlab-org/gitlab-ee/issues/12082).\n\nThe Elasticsearch integration is progressing. Finally, responsibility for the Elasticsearch integration has been passed from\nthe [Plan stage](https://handbook.gitlab.com/handbook/product/categories/#plan-stage)\nto the [Editor group of the Create stage](https://handbook.gitlab.com/handbook/product/categories/#editor-group).\nI hope you'll join Mario and me in wishing [Kai](/company/team/#phikai),\n[Darva](/company/team/#DarvaSatcher), and the rest of the team the best of luck in tackling the remaining challenges for Elasticsearch. An up-to-date overview of their plans can always be found on\nthe [search strategy](/direction/global-search/) page.\n\nPhoto by [Benjamin Elliott](https://unsplash.com/photos/vc9u77c0LO4) on [Unsplash](https://unsplash.com/)\n{: .note}\n",[742,9,1161],"inside GitLab",{"slug":1163,"featured":6,"template":696},"elasticsearch-update","content:en-us:blog:elasticsearch-update.yml","Elasticsearch Update","en-us/blog/elasticsearch-update.yml","en-us/blog/elasticsearch-update",{"_path":1169,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1170,"content":1176,"config":1184,"_id":1186,"_type":13,"title":1187,"_source":15,"_file":1188,"_stem":1189,"_extension":18},"/en-us/blog/enable-slos-as-code",{"title":1171,"description":1172,"ogTitle":1171,"ogDescription":1172,"noIndex":6,"ogImage":1173,"ogUrl":1174,"ogSiteName":683,"ogType":684,"canonicalUrls":1174,"schema":1175},"Enable SLO-as-Code with Nobl9 and GitLab","Learn how to take advantage of a streamlined SLO process and maintain a single source of truth for SLO definitions within your DevOps platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669455/Blog/Hero%20Images/nobl9_1.jpg","https://about.gitlab.com/blog/enable-slos-as-code","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Enable SLO-as-Code with Nobl9 and GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Quan To\"},{\"@type\":\"Person\",\"name\":\"Jeremy Cooper\"},{\"@type\":\"Person\",\"name\":\"Ian Bartholomew\"}],\n        \"datePublished\": \"2022-05-09\",\n      }",{"title":1171,"description":1172,"authors":1177,"heroImage":1173,"date":1181,"body":1182,"category":763,"tags":1183},[1178,1179,1180],"Quan To","Jeremy Cooper","Ian Bartholomew","2022-05-09","\n\nNobl9 recently integrated with GitLab's CI to enable a consistent mechanism to publish Service Level Objectives (SLO) definitions from GitLab to Nobl9. With this SLO-as-Code integration, DevOps teams can take action when their error budgets are burning too fast or are about to be exhausted.\n\nIn today’s systems, 100% uptime isn’t realistic given the complex architectures and dependencies involved. SLOs enable you to define targets and have an error budget for tracking what's “good enough.” For example, you can target uptime of 99.9%, 99%, or even 95% because what truly matters is how much downtime or errors are acceptable before there is real customer impact.\n\nTypically when organizations think about SLO-as-Code, they must use separate products to ensure their SLO definitions are always in sync with whatever tool they are using. This usually includes running command-line tools manually or building custom integrations within their code repositories.    \n\nWith this CI configuration, every time you build your repo, GitLab will call [sloctl](https://docs.nobl9.com/sloctl-user-guide), our command-line tool, and push the SLO definition to Nobl9. Customers can continue using GitLab to version their SLO definitions and keep their SLOs consistent. This ensures your SLO definition will always be up to date with what’s in Nobl9 and removes any discrepancies over what the latest SLO definition actually is. SREs, engineers, and anyone using the SLOs can still debate what the targets need to be, but there will always be a definitive source of truth in your code repository on what the current definition is.\n\n## Getting started\n\nTo set this up in GitLab, follow these steps:\n\n**1.** Select Settings -> CI/CD, and click the Expand button next to Variables. \n\n![CICD_settings](https://about.gitlab.com/images/blogimages/nobl9_2.png)\n\n\n**2.** Add the following variables:\n\n- CLIENT_ID\n\n- CLIENT_SECRET\n\n- ACCESS_TOKEN\n\n- PROJECT \n\n- SLOCTL_YML\n\n\n**Note:** If you haven’t done so already, you’ll need to install sloctl. You can install the executable on your local machine by following the instructions in the [user guide](https://docs.nobl9.com/sloctl-user-guide#setting-up-sloctl). Once sloctl is installed, you can run the following command to retrieve your CLIENT_ID, CLIENT_SECRET, and ACCESS_TOKEN:\n\n\n    cat ~/.config/nobl9/config.toml\n\n\n    The PROJECT value is the name of the project inside Nobl9 that your SLO belongs \n    to.\n\n\n    The SLOCTL_YML value is the Nobl9 YAML file you want to push to Nobl9 on each \n    change.\n\n\n\n![install_sloctl](https://about.gitlab.com/images/blogimages/nobl9_3.png)\n\n\n\n**3.** Create the CI/CD job to apply the YAML, by going to CI/CD -> Jobs and clicking “Create CI/CD configuration file”. \n\n\n\n![create_config](https://about.gitlab.com/images/blogimages/nobl9_4.png)\n\n\n\nEnter the following code in the _.gitlab.ci.yml_ file:\n\n\n        variables:\n\n\n          CLIENT_ID: $NOBL9_CLIENT_ID\n\n\n          CLIENT_SECRET: $NOBL9_CLIENT_SECRET\n\n\n          ACCESS_TOKEN: $NOBL9_ACCESS_TOKEN\n\n\n          PROJECT: $NOBL9_PROJECT\n\n\n          SLOCTL_YML: $SLOCTL_YML\n\n\n        include:\n\n\n          - project: 'nobl9/nobl9-ci-template'\n\n\n            ref: main\n\n\n            file: '/nobl9.gitlab-ci.yml'\n\n\n\n\n**4.** Kick off a build. Any changes to the SLOCTL_YML file that you reference will now automatically be pushed to Nobl9 once the updates are committed.\n\nBy partnering with GitLab and providing a convenient CI script and a command-line tool for managing SLOs, Nobl9 has truly enabled SLO-as-Code. We encourage existing Nobl9 customers who use GitLab to give it a try. \n\nIf you haven’t experienced Nobl9 yet, you can sign up for a free 30-day trial at [nobl9.com/signup](http://nobl9.com/signup) to see all that it has to offer.\n\n_Quan To is Senior Director of Product Management, Jeremy Cooper is Senior Solutions Engineer, and Ian Bartholomew is SRE Manager at Nobl9._\n\nCover image by [Vardan Papikayan](https://unsplash.com/@varpap) on [Unsplash](https://unsplash.com/photos/JzE1dHEaAew)\n",[9,785,851],{"slug":1185,"featured":6,"template":696},"enable-slos-as-code","content:en-us:blog:enable-slos-as-code.yml","Enable Slos As Code","en-us/blog/enable-slos-as-code.yml","en-us/blog/enable-slos-as-code",{"_path":1191,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1192,"content":1197,"config":1204,"_id":1206,"_type":13,"title":1207,"_source":15,"_file":1208,"_stem":1209,"_extension":18},"/en-us/blog/enabling-global-search-elasticsearch-gitlab-com",{"title":1193,"description":1194,"ogTitle":1193,"ogDescription":1194,"noIndex":6,"ogImage":1152,"ogUrl":1195,"ogSiteName":683,"ogType":684,"canonicalUrls":1195,"schema":1196},"Lessons from implementing global code search on GitLab.com","Read about some of the dead ends we've encountered on the way to enabling global code search on GitLab.com, and how we're working on a way forward.","https://about.gitlab.com/blog/enabling-global-search-elasticsearch-gitlab-com","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Lessons from our journey to enable global code search with Elasticsearch on GitLab.com\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mario de la Ossa\"}],\n        \"datePublished\": \"2019-03-20\",\n      }",{"title":1198,"description":1194,"authors":1199,"heroImage":1152,"date":1201,"body":1202,"category":739,"tags":1203},"Lessons from our journey to enable global code search with Elasticsearch on GitLab.com",[1200],"Mario de la Ossa","2019-03-20","\nWe're [working hard to switch our search infrastructure on GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/153) to\ntake advantage of our [Elasticsearch integration](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html), which should allow us to improve global search and enable global code search for our users.\n\nEnabling this integration on GitLab.com is important to us because it will unlock better search performance and allow us\nto improve the relevance of results for our GitLab.com users – something our self-managed users have been able to take advantage of for a few years now.\nWe've been working on this for a while, and have hit many dead ends and pitfalls which maybe you can learn from too.\n\n## Our plan\n\nWe have two very important things that need to happen: we must reduce the Elasticsearch index size,\nand we must improve the administration of the Elasticsearch integration.\n\n## 1. Reduce index size\n\nCurrently, the Elasticsearch index utilizes approximately 66 percent of the space the repos use.\nThis is our biggest blocker, as this is the bare minimum amount of space required – this number goes up when you consider the need for replicas.\n\nWe've attempted multiple things to get the index size down, but all of them resulted in minimal (or no) changes at all,\nso due to the complexity of implementing the changes we've decided to ignore them (at least for now).\n\n### Things we've tried\n\n#### Force merges\n\nWhen you delete a document from Elasticsearch, it doesn't actually free up space right away.\nInstead it does a soft delete, and Elasticsearch will release the space used in the future via an operation called a [merge](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-merge.html).\n\nIn [gitlab-org/gitlab-ee#7611](https://gitlab.com/gitlab-org/gitlab-ee/issues/7611) we investigated the possibility of forcing Elasticsearch\nto reclaim this space periodically via an operation called a [forcemerge](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html).\nThis seemed like a very worthwhile thing to investigate as an Elasticsearch index could theoretically grow up to 50 percent more due to these soft deletions.\nIn the end though, we found out that a `forcemerge` is a blocking call, and causes extreme performance degradation while it runs –\nnot something you want in a production environment!\nSadly we were forced to abandon this, but we did learn a bit more about [how to tune Elasticsearch so merges are less painful, which we documented here](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html).\n\n#### NGram sizes\n\nIn order to allow users to search without using exact phrases (it would be annoying if a search for \"house\" didn't bring up \"houses\" for\nexample) we use what is called an [Edge NGram](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenizer.html)\nfilter for blobs (code files) and SHA1 strings (commit IDs).\n\nWe have our Edge NGram filters set to create a maximum length of 40.\nRight off the bat we knew we could not lower the maximum size for our SHA1 filter, since we want our users to be able to find commits no matter how many characters of the ID they give us, and the maximum is 40.\n\nWe could, however, play with the Edge NGram filter we use to analyze code, so we tested a few different scenarios in [gitlab-org/gitlab-ee#5585](https://gitlab.com/gitlab-org/gitlab-ee/issues/5585).\nWe came up with conflicting results, but the savings were between 7-15 percent.\nNot bad! We still haven't changed the maximum length though, as we still need to confirm that searching is not impacted unduly with such a change.\n\n#### Separate indexes\n\nCurrently, our Elasticsearch integration lumps all document types into the same index.\nThis is because, in order to only return results to which a user has access, we must check the Project the object belongs to for the user's access level, which would be very expensive to do if we had to do it result per result after Elasticsearch returns the results of the query.\n\nThat said, there was a chance that having separate indexes could improve our space usage, and it would definitely improve the re-indexing\nexperience, so in [gitlab-org/gitlab-ee#3217](https://gitlab.com/gitlab-org/gitlab-ee/issues/3217) we took a stab at it.\nWe learned that having separate indexes does nothing for space usage, which we already suspected since Elasticsearch 6.0 shipped with great support for [sparse fields](https://www.elastic.co/blog/minimize-index-storage-size-elasticsearch-6-0).\n\nWe're still looking into having separate indexes, as in testing we have discovered it [greatly improves indexing speed](https://gitlab.com/gitlab-org/gitlab-ee/issues/3217#note_130304358)\nand should also improve the experience of having to re-index certain models.\n\n## 2. Improve administration capabilities for Elasticsearch\n\nRight now, all administration related to Elasticsearch must be done on the Elasticsearch cluster directly.\nWe also currently require the Elasticsearch integration to be an all-or-nothing deal: you must enable it for all projects, or none of them.\nTo make matters worse, when we make a change to the index schema, we require a full re-index of the entire repo right away in order for the update to work.\nWe need to fix all these things and make Elasticsearch easier to administer from within GitLab if we want to have a fighting chance at\nenabling Elasticsearch support on GitLab.com.\n\nSome concrete things we're working on:\n\n### Better cluster visibility\n\nIn order to help the administration of Elasticsearch, we must enable better controls for it from within GitLab.\nIssues [gitlab-org/gitlab-ee#3072](https://gitlab.com/gitlab-org/gitlab-ee/issues/3072) and\n[gitlab-org/gitlab-ee#2973](https://gitlab.com/gitlab-org/gitlab-ee/issues/2973) aim to provide a simple, but functional, admin interface\nfor Elasticsearch within GitLab.\n\n### Graceful recovery\n\nCurrently, if some data fails to index, whether due to a Sidekiq outage or any other reason, the only solution is to\nre-index the full Elasticsearch cluster, which is painful! In [gitlab-org/gitlab-ee#5299](https://gitlab.com/gitlab-org/gitlab-ee/issues/5299)\nwe will be looking into ways to improve this.\n\n### Selective/progressive indexing\n\nIn [gitlab-org/gitlab-ee#3492](https://gitlab.com/gitlab-org/gitlab-ee/issues/3492) we will be taking a look at enabling\nElasticsearch on a project-by-project basis.\n\n### Allow disabling of code indexing\n\nIn [gitlab-org/gitlab-ee#7870](https://gitlab.com/gitlab-org/gitlab-ee/issues/7870) we're investigating making\ncode indexing optional. What this would mean is that global code search would not be available, but searching within a\nproject would work as it currently does, backed by direct Gitaly searches. This is attractive to us as it would bring\nsearch improvements to Projects, Groups, Issues, and Merge Requests. This will also be a very useful feature for self-managed\ninstances that want to have better search support for Issues/MRs/etc. but don't really need global code search. Indexing\nthe repos to enable global code search takes an incredible amount of time, so offering the choice of disabling it gives our\nself-managed users more choice.\n\n### Shard Elasticsearch per group\n\nIn [gitlab-org/gitlab-ee#10519](https://gitlab.com/gitlab-org/gitlab-ee/issues/10519) we're considering having separate Elasticsearch\nservers per group, similar to how Gitaly works, but on a group level instead of project level. Elasticsearch servers can become very large,\nreducing performance and making them less maintainable. By having a separate server per group we would also gain resiliency in case one\ncluster goes down, as only the group related to that cluster would be affected.\n\nWe're still investigating this approach as there are some concerns about how search would work if we had separate Elasticsearch servers per group.\n\n## The future\n\nWe haven't given up yet! We have high hopes that we'll find ways to lower usage enough to make better search available to all our users.\n\nMeanwhile, we're switching all our engineering time from lowering index usage to improving administration capabilities, as we feel that\nenabling things like selective indexing of projects will allow us to improve our Elasticsearch integration with more confidence, as we will\nbe dogfooding our changes in production.\n\nIf you'd like to follow along with us, feel free to check out the following epics: [gitlab-org&153](https://gitlab.com/groups/gitlab-org/-/epics/153),\n[gitlab-org&429](https://gitlab.com/groups/gitlab-org/-/epics/429), and [gitlab-org&428](https://gitlab.com/groups/gitlab-org/-/epics/428).\nIf you have any concerns, comments, etc. we'll be glad to hear them. Remember, everyone can contribute!\n\nPhoto by [Benjamin Elliott](https://unsplash.com/photos/vc9u77c0LO4) on [Unsplash](https://unsplash.com/)\n{: .note}\n",[742,9,1161],{"slug":1205,"featured":6,"template":696},"enabling-global-search-elasticsearch-gitlab-com","content:en-us:blog:enabling-global-search-elasticsearch-gitlab-com.yml","Enabling Global Search Elasticsearch Gitlab Com","en-us/blog/enabling-global-search-elasticsearch-gitlab-com.yml","en-us/blog/enabling-global-search-elasticsearch-gitlab-com",{"_path":1211,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1212,"content":1218,"config":1225,"_id":1227,"_type":13,"title":1228,"_source":15,"_file":1229,"_stem":1230,"_extension":18},"/en-us/blog/enhance-application-security-with-gitlab-hackerone",{"title":1213,"description":1214,"ogTitle":1213,"ogDescription":1214,"noIndex":6,"ogImage":1215,"ogUrl":1216,"ogSiteName":683,"ogType":684,"canonicalUrls":1216,"schema":1217},"Enhance application security with GitLab + HackerOne","Learn about the GitLab + HackerOne partnership and how to easily implement an integration that improves your organization’s application security posture.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097503/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945%20%2810%29_5ET24Q6i8ihqrAOkge7a1R_1750097503214.png","https://about.gitlab.com/blog/enhance-application-security-with-gitlab-hackerone","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Enhance application security with GitLab + HackerOne\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2025-04-03\",\n      }",{"title":1213,"description":1214,"authors":1219,"heroImage":1215,"date":1221,"body":1222,"category":716,"tags":1223},[1220],"Fernando Diaz","2025-04-03","Security can no longer be an afterthought in the development process.\nOrganizations need robust solutions that integrate security throughout the\nentire software development lifecycle. This is where the partnership between\nHackerOne and GitLab creates a compelling combination for modern application\ndevelopment teams.\n\n\nGitLab, the comprehensive, AI-powered DevSecOps platform, and HackerOne, the\nleading crowd-sourced security platform, have established a partnership that\nbrings together the best of both worlds: GitLab's streamlined DevSecOps\nworkflow and HackerOne's powerful vulnerability management capabilities.\n\n\nIn this tutorial, you'll learn how to enhance developer productivity and\nyour security posture by implementing HackerOne's GitLab integration.\n\n\n## An integration that empowers developers\n\n\nHackerOne's GitLab integration is remarkably straightforward, yet powerful.\nWhen security researchers discover vulnerabilities through HackerOne's\nplatform, these findings are automatically converted into GitLab issues.\nThis creates a seamless workflow where:\n\n\n* Security researchers identify vulnerabilities via HackerOne's platform  \n\n* Validated vulnerabilities are automatically converted into GitLab issues  \n\n* Development teams can address these issues directly within their existing\nworkflow  \n\n* Resolution status is synchronized between both platforms\n\n\nYou can start leveraging the benefits of GitLab and HackerOne by using the\n[integration](https://docs.hackerone.com/en/articles/8571227-gitlab-integration)\nto track GitLab issues as references on HackerOne. This integration provides\nbi-directional and seamless data syncing between your HackerOne report and\nGitLab issues, improving alignment between development and security teams\nwhile streamlining security vulnerability processing.\n\n\nTo configure the GitLab integration to sync information between your\nHackerOne report and your Gitlab issue, follow the instructions provided in\n[HackerOne's GitLab integration\ndocumentation](https://docs.hackerone.com/en/articles/10394699-gitlab-setup),\nwhich includes:\n\n\n1. [Setting up an OAuth 2.0\napplication](https://docs.gitlab.com/ee/integration/oauth_provider.html) for\nyour GitLab instance with the provided HackerOne settings  \n\n2. Connecting HackerOne to the newly created OAuth 2.0 on GitLab  \n\n3. Authorizing HackerOne to access the GitLab API  \n\n4. Configuring which GitLab project you would like to escalate HackerOne\nreports to  \n\n5. Selecting the HackerOne fields to map to corresponding GitLab fields  \n\n6. GitLab-to-HackerOne and HackerOne-to-GitLab event configuration\n\n\nOnce the integration is in place, you’ll be able to seamlessly sync data\nbi-directionally between both GitLab and HackerOne. This helps simplify\ncontext-switching and allows vulnerabilities to be tracked with ease\nthroughout both systems. The integration allows for the following features:\n\n\n* **Creating a GitLab Issue from HackerOne:** You can create new GitLab\nissues for reports you receive on HackerOne.  \n\n* **Linking HackerOne reports to existing GitLab tasks.**   \n\n* **Syncing updates from HackerOne to GitLab:** The following updates on a\nreport are synced as a comment to GitLab.  \n  * Report comments  \n  * State changes  \n  * Rewards  \n  * Assignee changes  \n  * Public disclosure  \n  * Close GitLab Issue  \n* **Syncing Updates from GitLab to HackerOne:** The following updates on\nGitLab will be reflected in HackerOne as an internal comment on the\nassociated report:  \n  * Comments  \n  * State changes  \n* **HackerOne severity to GitLab label mapping**: Allows you to set a custom\npriority when escalating a report to GitLab.  \n\n* **Due date mapping:** Allows you to automatically set a custom due date\nbased on the severity of a report.\n\n\n![GitLab + HackerOne adding comments or change the state of the report in\nGitLab](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097510/Blog/Content%20Images/Blog/Content%20Images/sync_aHR0cHM6_1750097509644.png)\n\n\nThese features improve alignment between development and security teams and\nstreamlining security vulnerability processing. To learn more on how the\nintegration works, see the [integration\ndocumentation](https://docs.hackerone.com/en/articles/8571227-gitlab-integration).\n\n\n## A look into HackerOne bug bounty programs\n\n\nHackerOne provides bug bounty programs or cybersecurity initiatives where\nrewards are offered for discovering and reporting vulnerabilities in\ncustomers’ software systems, websites, or applications. Bug bounty programs\nhelp enhance the security of an application by:\n\n\n* Identifying security flaws before malicious actors can exploit them  \n\n* Leveraging diverse expertise from a global community of security\nresearchers  \n\n* Providing a cost-effective way to improve cybersecurity  \n\n* Complementing internal security efforts and traditional penetration\ntesting\n\n\nGitLab utilizes HackerOne’s bug bounty program, allowing security\nresearchers to report vulnerabilities in GitLab applications or\ninfrastructure. This crowdsourced approach helps GitLab identify and address\npotential security issues more effectively.\n\n\n![HackerOne GitLab Bug Bounty\npage](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097510/Blog/Content%20Images/Blog/Content%20Images/hackerone_gitlab_bug_bounty_page_aHR0cHM6_1750097509645.png)\n\n\nBy leveraging HackerOne's platform and the global hacker community,\norganizations can significantly enhance their security posture, identify\nvulnerabilities faster, and stay ahead of potential threats.\n\n\n## Secure applications and improve efficiency with GitLab \n\n\nGitLab provides a complete DevSecOps platform, which enables functionality\nfor the complete software development lifecycle, including security and\ncompliance tools. GitLab supports the following security scanner types:\n\n- Static Application Security Testing (SAST)\n\n- Dynamic Application Security Testing (DAST)\n\n- Container Scanning\n\n- Dependency Scanning\n\n- Infrastructure as Code Scanning\n\n- Coverage-guided Fuzzing\n\n- Web API Fuzzing\n\n\nWith GitLab, you can add security scanning by simply applying a template to\nyour CI/CD pipeline definition file. For example, enabling SAST just takes a\nfew lines of code in the `.gitlab-ci.yml`:\n\n\n```yaml\n\nstage:\n  - test\n\ninclude:\n  - template: Jobs/SAST.gitlab-ci.yml\n```\n\n\nThis will run SAST on the test stage, and [auto-detect the languages\nused](https://docs.gitlab.com/ee/user/application_security/sast/#supported-languages-and-frameworks)\nin your application. Then, whenever you create a merge request, SAST will\ndetect the vulnerabilities in the diff between the feature branch and the\ntarget branch and provide relevant data on each vulnerability to assist with\nremediation.\n\n\n![NoSQL injection vulnerability seen in\nMR](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097510/Blog/Content%20Images/Blog/Content%20Images/no_sql_injection_vulnerability_mr_view_aHR0cHM6_1750097509647.png)\n\n\nThe results of the SAST scanner can block code from being merged if security\npolicies are applied. Native GitLab users can be set as approvers, allowing\nrequired reviews before merging insecure code. This assures that all\nvulnerabilities have oversight from the appropriate parties.\n\n\n![Merge request approval\npolicy](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097510/Blog/Content%20Images/Blog/Content%20Images/merge_request_approval_policy_aHR0cHM6_1750097509649.png)\n\n\nHackerOne has integrated GitLab into its operations and development\nprocesses in several significant ways, which have led to development process\nimprovements and enhanced scalability and collaboration. These improvements\ninclude faster deployments and cross-team planning.\n\n\n## Key benefits of HackerOne's GitLab integration\n\n\nThe key benefits of using HackerOne and GitLab together include:\n\n\n* **Enhanced security visibility:** Development teams gain immediate\nvisibility into security vulnerabilities without leaving their primary\nworkflow environment. This real-time awareness helps teams prioritize\nsecurity issues alongside feature development.  \n\n* **Streamlined remediation process:** By converting HackerOne reports\ndirectly into GitLab issues, the remediation process becomes part of the\nstandard development cycle. This eliminates context switching between\nplatforms and ensures security fixes are tracked alongside other development\nwork.  \n\n* **Accelerated time to fix:** The integration significantly reduces the\ntime between vulnerability discovery and resolution. With HackerOne\nsubmissions immediately available in GitLab, development teams can begin\nworking on fixes without delay, improving overall security posture.  \n\n* **Improved collaboration:** Security researchers, security teams, and\ndevelopers can communicate more effectively through this integration.\nComments and updates flow between both platforms, creating a collaborative\nenvironment focused on improving security.  \n\n* **Real-world impact:** Organizations implementing the HackerOne and GitLab\nintegration have reported:  \n  * Up to 70% reduction in time from vulnerability discovery to fix  \n  * Improved developer satisfaction by keeping them in their preferred workflow  \n  * Enhanced security visibility across the organization  \n  * More effective allocation of security resources\n\n> To get started today, visit [the integration setup\npage](https://docs.hackerone.com/en/articles/10394699-gitlab-setup) today.\n\n\n## Learn more\n\n\nTo learn more about GitLab and HackerOne, and how we can help enhance your\nsecurity posture, check out the following resources:\n\n* [HackerOne's GitLab Integration\nUsage](https://docs.hackerone.com/en/articles/8571227-gitlab-integration)  \n\n* [HackerOne GitLab Bug Bounty\nProgram](https://hackerone.com/gitlab?type=team)\n\n* [GitLab Security and Compliance\nSolutions](https://about.gitlab.com/solutions/security-compliance/)  \n\n* [HackerOne achieves 5x faster deployments with GitLab’s integrated\nsecurity](https://about.gitlab.com/customers/hackerone/)  \n\n* [GitLab Application Security\nDocumentation](https://docs.gitlab.com/ee/user/application_security/)\n",[716,807,9,281,493,976,1224],"bug bounty",{"slug":1226,"featured":6,"template":696},"enhance-application-security-with-gitlab-hackerone","content:en-us:blog:enhance-application-security-with-gitlab-hackerone.yml","Enhance Application Security With Gitlab Hackerone","en-us/blog/enhance-application-security-with-gitlab-hackerone.yml","en-us/blog/enhance-application-security-with-gitlab-hackerone",{"_path":1232,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1233,"content":1239,"config":1247,"_id":1249,"_type":13,"title":1250,"_source":15,"_file":1251,"_stem":1252,"_extension":18},"/en-us/blog/enhanced-migration-from-bitbucket-server-and-bitbucket-cloud-to-gitlab",{"title":1234,"description":1235,"ogTitle":1234,"ogDescription":1235,"noIndex":6,"ogImage":1236,"ogUrl":1237,"ogSiteName":683,"ogType":684,"canonicalUrls":1237,"schema":1238},"Enhanced migration from Bitbucket Server and Bitbucket Cloud to GitLab","Learn about performance improvements and more when migrating from Bitbucket Server and Cloud to GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668776/Blog/Hero%20Images/julia-craice-faCwTallTC0-unsplash.jpg","https://about.gitlab.com/blog/enhanced-migration-from-bitbucket-server-and-bitbucket-cloud-to-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Enhanced migration from Bitbucket Server and Bitbucket Cloud to GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Magdalena Frankiewicz\"}],\n        \"datePublished\": \"2023-11-30\",\n      }",{"title":1234,"description":1235,"authors":1240,"heroImage":1236,"date":1242,"body":1243,"category":1244,"tags":1245},[1241],"Magdalena Frankiewicz","2023-11-30","_Atlassian is ending support for all Server products in February 2024. Learn more about the [benefits of migrating from Atlassian to GitLab](https://about.gitlab.com/move-to-gitlab-from-atlassian/)._\n\nStarting [from February 15, 2024](https://about.gitlab.com/blog/atlassian-server-ending-move-to-a-single-devsecops-platform/), Atlassian will no longer offer technical support, security updates, or vulnerability fixes for their Server products, including Bitbucket Server.\n\nThrough improvements to our Bitbucket Server and Bitbucket Cloud importers, we've lowered the barrier to switch to GitLab, especially for large Bitbucket projects. We are happy to be able to offer a quick and effortless way to move your data to GitLab!\n\nLet's take a look at some of these improvements.\n\n## Improvements to imports of large projects\n\nGitLab has offered Bitbucket Server and Bitbucket Cloud importers for a long time. However, these importers operated sequentially in only one Sidekiq background job, which led to timeouts on imports of larger projects.\n\nTo solve the timeouts problem, we introduced parallel, asynchronous importers that split the work into smaller background jobs. This change was introduced in:\n\n- [GitLab 16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/411534) for the Bitbucket Server importer\n- [GitLab 16.6](https://gitlab.com/gitlab-org/gitlab/-/issues/412614) for the Bitbucket Cloud importer\n\nThis change:\n\n- ensures that the import process doesn’t time out on a single worker\n- spreads the number of calls we make to Bitbucket API, reducing the risk of running into rate limiting\n\nWe also improved error handling so that errors raised on single objects don't stop the whole import from completing.\n\n## More improvements\n\nRefactoring importers to be parallel was a crucial improvement, but not the only one we have made to our importers. We also worked to:\n\n- improve the integrity of imported data\n- extend the types of data that we import\n\nBecause Bitbucket Server and Bitbucket Cloud are separate products and require separate importers, the improvements we introduced differ for each importer. We describe them in the sub-sections below.\n\n### Bitbucket Server importer\n\nIn GitLab 16.5, we [fixed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131894) a problem when imported merged and closed merge requests had no commit data associated with them, leaving the diffs empty.\n\nIn Gitlab 16.3, we began [importing reviewers](https://gitlab.com/gitlab-org/gitlab/-/issues/416611) and in Gitlab 16.6, we began importing [pull request approvals](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/135256).\n\n### Bitbucket Cloud importer\n\nIn GitLab 16.6, we fixed a problem that users encountered when a pull request on Bitbucket Cloud was squashed and merged, and the branch deleted. When these pull requests were imported to GitLab, the resulting merge requests didn't have associated commits. The problem was addressed by associating merge commits to imported merge requests.\n\nNotes on issues and pull requests can contain references (links) to code, issues, comments, pull requests, and more. Previously, these were imported as is, which left comments with strangely formatted, unclickable links. We [fixed this](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131382) in GitLab 16.6 by converting refs to GitLab refs. Also, we [no longer import deleted notes](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133208), which caused data errors.\n\nAlso for the Bitbucket Cloud importer, we began [importing LFS objects](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133182) in GitLab 16.5 and [pull request reviewers](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131134) in GitLab 16.6.\n\n## Take advantage of importers today\n\nWith the improvements described, the experience of switching from Bitbucket Server or Bitbucket Cloud to the GitLab DevSecOps platform is better than ever! Check out the [Bitbucket Server importer documentation](https://docs.gitlab.com/ee/user/project/import/bitbucket_server.html) or the [Bitbucket Cloud importer documentation](https://docs.gitlab.com/ee/user/project/import/bitbucket.html) to get started today.\n\nFor GitLab self-managed instances, to benefit from parallel Bitbucket Cloud importer, administrators must enable the `bitbucket_parallel_importer` [feature flag](https://docs.gitlab.com/ee/administration/feature_flags.html). The Bitbucket Server importer is always parallel on GitLab self-managed and GitLab.com.","devsecops",[493,1246,9],"DevOps platform",{"slug":1248,"featured":6,"template":696},"enhanced-migration-from-bitbucket-server-and-bitbucket-cloud-to-gitlab","content:en-us:blog:enhanced-migration-from-bitbucket-server-and-bitbucket-cloud-to-gitlab.yml","Enhanced Migration From Bitbucket Server And Bitbucket Cloud To Gitlab","en-us/blog/enhanced-migration-from-bitbucket-server-and-bitbucket-cloud-to-gitlab.yml","en-us/blog/enhanced-migration-from-bitbucket-server-and-bitbucket-cloud-to-gitlab",{"_path":1254,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1255,"content":1261,"config":1267,"_id":1269,"_type":13,"title":1270,"_source":15,"_file":1271,"_stem":1272,"_extension":18},"/en-us/blog/fast-and-efficient-sbom-with-gitlab-and-rezilion",{"title":1256,"description":1257,"ogTitle":1256,"ogDescription":1257,"noIndex":6,"ogImage":1258,"ogUrl":1259,"ogSiteName":683,"ogType":684,"canonicalUrls":1259,"schema":1260},"Meet the demand for SBOMs with GitLab and Rezilion","Learn the role of SBOMs in helping to secure your software supply chain and how to generate them with the GitLab + Rezilion integration.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749672849/Blog/Hero%20Images/jessica-lewis-fJXv46LT7Xk-unsplash.jpg","https://about.gitlab.com/blog/fast-and-efficient-sbom-with-gitlab-and-rezilion","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Meet the demand for SBOMs and supply chain security with GitLab and Rezilion\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2022-10-17\",\n      }",{"title":1262,"description":1257,"authors":1263,"heroImage":1258,"date":1264,"body":1265,"category":716,"tags":1266},"Meet the demand for SBOMs and supply chain security with GitLab and Rezilion",[1220],"2022-10-17","\nModern software development often takes advantage of code reuse. Instead of reinventing the wheel, developers can use a library that focuses on a particular\nfunction for use in an application. However, there is one caveat: These\ndependencies may be susceptible to security vulnerabilities, which may render\nyour whole application – and possibly your software supply chain – as vulnerable.\n\nThat is why DevOps teams must be able to generate a software bill of materials, or [SBOM](https://docs.gitlab.com/ee/user/application_security/dependency_list/). GitLab has partnered with [Rezilion](/partners/technology-partners/#rezilion) to make this task easier.\n\n## The need for SBOMs\n\nIn 2020, the [Solar Winds software supply chain attack happened](https://www.businessinsider.com/solarwinds-hack-explained-government-agencies-cyber-security-2020-12). Hackers used an easy-to-guess password to inject malicious\ncode into a software update and many users of the affected Solar Winds product\nOrion, including government agencies, had their data compromised.\n\nThis breach, along with other high-profile attacks, led Pres. Biden's administration to [require software vendors to deliver a software bill of materials (SBOM)](https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/) with any software offer they make to federal agencies.\n\n## Secure your software and manage vulnerabilities\n\nTo get started with software supply chain security, you need to not only implement security scanning, but\nalso have a process in place to manage and effectively triage these vulnerabilities.\n\nBelow, you can see the typical software development lifecycle. It shows that security scans are run on a feature branch. A developer can view the presented vulnerabilities and continue to commit to the feature branch which re-runs the scans.\n\nOnce the vulnerabilities have been remediated the feature branch can be merged. If vulnerabilities are still present, [approval](https://docs.gitlab.com/ee/user/application_security/policies/scan-result-policies.html) by the security team can be required, and you can continue to keep track of the vulnerability with a [confidential issue](https://docs.gitlab.com/ee/user/project/issues/confidential_issues.html).\n\n![](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/sdlc.png)\n\nLet's go over how to do the following:\n\n* Implement security scanners in GitLab with built-in templates\n* Manage vulnerabilities with the GitLab vulnerability report\n* Manage dependencies and generate an SBoM\n* Efficiently triage exploitable vulnerabilities with Rezilion\n\n## Implement security scanners\n\nThe first step in securing your software supply chain is to implement [security scanners](https://docs.gitlab.com/ee/user/application_security/configuration/#security-testing) into your CI/CD pipeline.\nThese scanners should be set up in a way, where they run on each code commit. When a vulnerability is detected, approval by a security team member should be required.\n\nGitLab offers many different security scanners to get you started:\n\n* [Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)\n* [Dynamic Application Security Testing (DAST)](https://docs.gitlab.com/ee/user/application_security/dast/)\n* [Infrastructure as Code (IaC) Scanning](https://docs.gitlab.com/ee/user/application_security/iac_scanning/)\n* [Container Scanning](https://docs.gitlab.com/ee/user/application_security/container_scanning/)\n* [Dependency Scanning](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/)\n* [Coverage-Guided Fuzzing](https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing/)\n* [Web-API Fuzzing](https://docs.gitlab.com/ee/user/application_security/api_fuzzing/)\n* [Secret Detection](https://docs.gitlab.com/ee/user/application_security/iac_scanning/)\n\nWith the scanners running in a pipeline, static application source code is scanned, as well as dependencies and the\nrunning application itself.\n\nThese scanners can be implemented by simply adding templates to your [GitLab CI YAML](https://docs.gitlab.com/ee/user/application_security/sast/index.html#configure-sast-manually). You can also use the [Configuration UI](https://docs.gitlab.com/ee/user/application_security/sast/index.html#configure-sast-in-the-ui-with-customizations)\nto set up and configure these security scanners. You can check out the set up instructions for each scanner in the [GitLab appsec configuration documentation](https://docs.gitlab.com/ee/user/application_security/configuration/#security-testing).\n\n## Manage vulnerabilities\n\nNext up, see how to use GitLab to manage vulnerabilities. GitLab provides a single source of truth that allows developers and\nappsec engineers to collaborate and address issues together. After the security scanners have been implemented, there are a\nfew ways to manage vulnerabilities.\n\nDevelopers will use the MR view to see all the vulnerabilities present in the **diff** between the **feature branch** and the **branch you are merging with**.\n\nYou can see below, that each vulnerability is presented in an easy-to-read view: \n\n![Life cycle illustration](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/mr-view.png)\n\nWhen you click on a vulnerability, you can see details such as:\n\n* Status\n* Description\n* Evidence\n* Severity\n* Identifiers\n* Linked Issues\n* Solution\n* Security Training\n\nThe vulnerabilities are also actionable which means they can be dismissed or a confidential issue can be created to triage later.\n\n![Screenshot of vulnerabilities](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/mr-view-2.png)\n\nThen there is the [vulnerability report](https://docs.gitlab.com/ee/user/application_security/vulnerability_report/) which displays all the vulnerabilities detected within the **main** branch and allows for the\nsecurity team to triage and address vulnerabilities from a common interface, enabling collaboration.\n\n![Detailed view of vulnerability](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/vr-1.png)\n\nOnce you click on a vulnerability, you are provided with [advanced details](https://docs.gitlab.com/ee/user/application_security/vulnerabilities/) on the vulnerability as well as how to remediate it.\n\n![Vulnerability report](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/vr-2.png)\n![Remediation suggestions](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/vr-3.png)\n\nAn appsec engineer can change the status, add additional information, and create confidential issues from this view.\n\n## Manage dependencies\n\nNow that you have seen how to run security scans on your application, as well as manage vulnerabilities, let's explore managing our \napplication's dependencies and understanding what is running on your system.\n\nThere are a few ways of managing dependencies and generating an SBoM. I'll go over\nthe GitLab Dependency List (SBoM) as well as the dynamic Rezilion SBoM.\n\n### GitLab Dependency List (SBoM)\n\nGitLab provides a [Dependency List](https://docs.gitlab.com/ee/user/application_security/dependency_list/) also known as an SBoM.\nThe dependency list contains your project’s dependencies and critical details about those dependencies, including their known vulnerabilities.  GitLab displays dependencies with the following information:\n\n| Field\t| Description |\n| ----- | ----------- |\n| Component\t| The dependency’s name and version. |\n| Packager |\tThe packager used to install the dependency. |\n| Location |\tFor system dependencies, this lists the image that was scanned. For application dependencies, this shows a link to the packager-specific lock file in your project that declared the dependency. It also shows the dependency path to a top-level dependency, if any, and if supported. |\n| License\t| Links to the dependencies' software licenses. |\n\nYou can download your project’s full list of dependencies and their details in [CycloneDX](https://cyclonedx.org/) JSON format. CycloneDX is a lightweight SBoM standard designed for use in application security contexts and supply chain component analysis. See it in action below:\n\n\u003Ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/5a-_l1bqWhQ\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen>\u003C/iframe>\n\n### Rezilion SBoM\n\nRezilion provides a dynamic SBoM directly within the GitLab UI. It displays all the software components your application uses, and determines their loaded/unloaded status for a quick risk assessment.\n\n![Screenshot of SBoM](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/rezilion-sbom.png)\n\n## Easily triage exploitable vulnerabilities\n\nNow that you have seen how to secure your application as well as its dependencies, you \ncan make sure addressing security issues does not slow down development. What matters most in your\nenvironment is to help save developers time and deliver secure products in a swift manner.\n\nHere is where GitLab + Rezilion comes into play: The integration reduces developers' patching efforts by enabling them to only display vulnerabilities that are exploitable. Rezilion will mark unexploitable vulnerabilities as false positives, which can then be sorted out. This can be done within the GitLab vulnerability report:\n\n![Display of exploitable vulnerabilities](https://about.gitlab.com/images/blogimages/fast-and-efficient-supply-chain-security-with-rezilion-and-gitlab/rezilion-exploitable.png)\n\nCheck out the demo showing how GitLab and Rezilion work together:\n\n\u003Ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/FgNp7FQFniE\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen>\u003C/iframe>\n\nWith these tools in hand, not only will you be able to secure your application's code before it makes its way to production, but you'll be able to do it in a fast and efficient manner.\n\nTo learn more about the GitLab + Rezilion integration check out this [whitepaper](https://www.rezilion.com/wp-content/uploads/2022/03/Rezilion-GitLab-Solution-Overview.pdf). You can also sign up for a free trial of [GitLab Ultimate](/free-trial) and [Rezilion](https://rezilion.com/get-started).\n\nPhoto by \u003Ca href=\"https://unsplash.com/es/@jessicalewiscreative?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText\">Jessica Lewis\u003C/a> on \u003Ca href=\"https://unsplash.com/s/photos/checklist?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText\">Unsplash\u003C/a>\n",[716,281,9],{"slug":1268,"featured":6,"template":696},"fast-and-efficient-sbom-with-gitlab-and-rezilion","content:en-us:blog:fast-and-efficient-sbom-with-gitlab-and-rezilion.yml","Fast And Efficient Sbom With Gitlab And Rezilion","en-us/blog/fast-and-efficient-sbom-with-gitlab-and-rezilion.yml","en-us/blog/fast-and-efficient-sbom-with-gitlab-and-rezilion",{"_path":1274,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1275,"content":1281,"config":1288,"_id":1290,"_type":13,"title":1291,"_source":15,"_file":1292,"_stem":1293,"_extension":18},"/en-us/blog/five-essential-business-benefits-a-devops-platform-gives-smbs",{"title":1276,"description":1277,"ogTitle":1276,"ogDescription":1277,"noIndex":6,"ogImage":1278,"ogUrl":1279,"ogSiteName":683,"ogType":684,"canonicalUrls":1279,"schema":1280},"Five essential business benefits a DevOps platform gives SMBs","Multiply your SMB’s tech muscle, reduce expenses, and cut wasted time.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668332/Blog/Hero%20Images/architecture-building-business-258163.jpg","https://about.gitlab.com/blog/five-essential-business-benefits-a-devops-platform-gives-smbs","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Five essential business benefits a DevOps platform gives SMBs\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sharon Gaudin\"}],\n        \"datePublished\": \"2022-08-30\",\n      }",{"title":1276,"description":1277,"authors":1282,"heroImage":1278,"date":1284,"body":1285,"category":1244,"tags":1286},[1283],"Sharon Gaudin","2022-08-30","\nSmall and medium-sized businesses (SMBs) face a litany of potentially crippling obstacles, but there’s a single step executives can take that will create multiple business benefits. \n\n[Migrating to an end-to-end DevOps platform for SMBs](https://page.gitlab.com/migrate-to-devops-guide.html) will not only greatly improve an SMB’s odds of survival, but it will increase their chance of actually thriving in an environment that sees half of all small businesses failing within their first five years. That’s right. All businesses face competition and obstacles, but SMBs and small and medium-sized enterprises (SMEs), in particular, are looking at an uphill battle so steep that 20% of U.S. small businesses fail within just the first year, [according to the U.S. Bureau of Labor Statistics](https://www.bls.gov/bdm/entrepreneurship/entrepreneurship.htm). So why not grab onto any advantage available, especially one this beneficial?\n\nHere’s how [a full DevOps platform can help any SMB](/blog/gitlab-provides-small-business-with-a-professional-mature-devops-platform/):\n\n## Multiply tech muscle\n\nLarge enterprises might have an IT department, or even a separate DevOps group, made up of dozens or hundreds of people. That’s not the case with SMBs and SMEs. A small business might just have one IT person. That leaves one – or two or five – people shouldering a whole lot of work. They’re left not only to handle issues with cybersecurity, email, and buggy laptops, but they also have to design, develop, and deploy new software and iterations. With a DevOps platform, a lot of repetitive tasks are automated, and security testing is built in from the get-go, freeing up a lot of time. With a DevOps platform, it’s possible to do more with fewer hands. \n\n## Engage the entire team\n\n[Fostering collaboration](/blog/5-ways-collaboration-boosts-productivity-and-your-career/) is a big part of a DevOps platform and it’s of particular benefit to SMBs. Yes, there are fewer employees in a smaller organization. That, though, doesn’t have to be a disadvantage. A DevOps platform fosters a collaborative environment, [breaking down departmental silos](/blog/developing-a-successful-devops-strategy/) and enabling everyone – from the head of the business to people in sales, marketing, and customer service – to work together on software planning and design. That means a wider swath of employees can pitch in on projects, naturally bringing more input and help to the table. And that makes software more inclusive and well-rounded. It also makes employees more engaged. \n\n## Stop wasting time and effort on a toolchain\n\nSMBs, like their larger enterprise brethren, turn to DevOps to more efficiently and quickly develop and deploy software. But when they don’t go with a single, end-to-end DevOps platform, they end up creating a complicated tangle of tools, or a toolchain. And these toolchains force them to not only learn, but continually switch back and forth between multiple interfaces, passwords, and ways of working. Even worse, those [taxing toolchains](/topics/devops/use-devops-platform-to-avoid-devops-tax/) only grow in size and unwieldiness as the business grows. With fewer IT people onboard, the full burden of these toolchains falls solely on a limited number of people – or even worse, it might fall on just one person. Get rid of that chaotic environment, and the waste of time and effort it brings, by migrating to a single application. \n\n\n## Eliminate the expense of a toolchain\n\nSince most SMBs have limited budgets, many often turn to DevOps tools that have what initially appear to be smaller price tags. However, by casting around for what might seem like a bargain, it creates an even greater mishmash of tools, which the company continually has to pay for. A [2020 Forrester Consulting Total Economic Impact Study](https://learn.gitlab.com/c/forrester-tei?x=X4W83-) noted that moving to a single DevOps application improves development and delivery efficiency by more than 87%, cuts down on licensing costs, and increases savings. The [expenses that come along](/webcast/simplify-to-accelerate/) with multiple licenses and continual maintenance are diminished with a single, end-to-end DevOps platform, driving the bottom line and delivering business value. \n\n## Improved security benefits for your business\n\nSMBs have the perfect chance to build security into their code and processes from the very beginning. That’s a much better process than [making security an afterthought](/blog/toolchain-security-with-gitlab/), or completely pushing security aside when projects are bumping up against tight deadlines. That won’t happen with a single DevOps platform, which integrates security into the entire software delivery lifecycle – from planning through design, build, and monitoring. Every single step of the development process. A DevOps platform even automates security testing, ensuring it’s not forgotten and relieving IT professionals from some repetitive, hands-on tasks. When [security is shifted left](/blog/efficient-devsecops-nine-tips-shift-left/) this way, if a vulnerability or compliance issue is introduced into the code, it’s identified almost immediately. And improved security doesn’t just benefit your software. It also benefits your customers, your brand reputation, and your overall business.\n\nMost every business, [regardless of size](/blog/can-an-smb-or-start-up-be-too-small-for-a-devops-platform/), is creating software to serve customers, connect with partners and suppliers, and find new revenue streams. But muddling together a string of tools that end up costing time, effort, and money just to maintain and use them isn’t the answer. If SMBs toss that complicated toolchain aside and replace it with one platform, they’ll expand their IT capabilities, reduce costs, and be better able to take on competitors with more experience and deeper pockets.\n",[851,9,1287],"customers",{"slug":1289,"featured":6,"template":696},"five-essential-business-benefits-a-devops-platform-gives-smbs","content:en-us:blog:five-essential-business-benefits-a-devops-platform-gives-smbs.yml","Five Essential Business Benefits A Devops Platform Gives Smbs","en-us/blog/five-essential-business-benefits-a-devops-platform-gives-smbs.yml","en-us/blog/five-essential-business-benefits-a-devops-platform-gives-smbs",{"_path":1295,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1296,"content":1302,"config":1308,"_id":1310,"_type":13,"title":1311,"_source":15,"_file":1312,"_stem":1313,"_extension":18},"/en-us/blog/four-approaches-to-gitlab-integrations",{"title":1297,"description":1298,"ogTitle":1297,"ogDescription":1298,"noIndex":6,"ogImage":1299,"ogUrl":1300,"ogSiteName":683,"ogType":684,"canonicalUrls":1300,"schema":1301},"4 approaches to GitLab integrations","Learn about use cases that help extract even more value from a DevSecOps platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667946/Blog/Hero%20Images/4-facets-of-gitlab-integration.png","https://about.gitlab.com/blog/four-approaches-to-gitlab-integrations","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"4 approaches to GitLab integrations\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Kurt Dusek\"}],\n        \"datePublished\": \"2023-01-26\",\n      }",{"title":1297,"description":1298,"authors":1303,"heroImage":1299,"date":1305,"body":1306,"category":1244,"tags":1307},[1304],"Kurt Dusek","2023-01-26","\n\nThe benefit of a DevSecOps platform is to create a foundation upon which an organization can build its entire development process. Rather than having to log onto several different systems to manage, observe, and advance through the software development lifecycle, DevSecOps teams have one application to serve as their system of record. To augment the platform and create even more business value, organizations can create integrations with third-party software and systems, while still maintaining a unified experience for stakeholders, developers, and operators.\n\nLet's look at what integrations are possible and the use cases that drive them.\n\n## What can be integrated with GitLab\n\nAs a senior solutions architect for Alliances here at GitLab, I often get asked, \"How can I integrate GitLab with X?\" My response: That depends on what's being integrated. X could be a cloud provider, point tool, legacy application or web service that might be used in the development cycle. \n\n## How to integrate with GitLab\n\nThere are four approaches to GitLab integrations:\n\n1. Use GitLab to deploy client applications to X / Host GitLab runners on X\n2. Host GitLab Server on X\n3. Integrate with the development cycle\n4. Deep GitLab application integration\n\nLet's dig deeper into each one.\n\n### 1. Use GitLab to deploy client applications to `X` or Host GitLab runners on `X`\nA very common use case and typically the easiest to achieve. For instance, platform providers, who want to make it easy for their users to run apps built with GitLab on their infrastructure or application server, are often asked for this option. The path is to have GitLab Server be able to authenticate to the hosting platform, and deploy the (ideally containerized) application to the platform.\n\nA close cousin of this is the need to deploy [GitLab runners](https://docs.gitlab.com/runner/) to the infrastructure and register them with a GitLab instance, be it GitLab.com or a self-managed instance. Runners are easy to setup and register, and can be [configured and scaled in many different ways](https://docs.gitlab.com/runner/fleet_scaling/). \n\n### 2. Host GitLab Server on `X`\nPlatform providers are also asked to host GitLab Server on their infrastructure. What makes this easy is GitLab runs almost anywhere; if you've got Linux, you can run GitLab Server (even on a Raspberry Pi). The work has already been done for the major cloud providers, including [GCP](https://docs.gitlab.com/ee/install/google_cloud_platform/), [AWS](https://docs.gitlab.com/ee/install/aws/), [Azure](https://docs.gitlab.com/ee/install/azure/), and [Oracle Cloud](https://docs.oracle.com/en/solutions/deploy-gitlab-ci-cd-oci/index.html). If you want to run on your own infrastructure, the [Omnibus](https://docs.gitlab.com/omnibus/) installer does most of the heavy lifting for you; it's the easiest way to self-host GitLab.  \n\n### 3. Integrate with the development cycle\nHere's where it starts to get a bit more involved. The good news is that GitLab has extensive [APIs](https://docs.gitlab.com/ee/api/) and [webhooks](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html) that allow for listening for events and pushing and pulling data.\n\nIf the goal is to integrate with the [CI/CD pipeline](https://docs.gitlab.com/ee/ci/index.html), this can be done by creating a container image that encapsulates the application or scripts necessary and defining a job within the pipeline that uses this image to run the integration. It's likely the integrated app produces some output that **someone** needs to review. Displaying this output directly within the Merge Request elevates third-party data rather than something that has to be searched for in another system.  Depending on the nature of the tool being integrated, it's possible to show results and a [security report](https://docs.gitlab.com/ee/development/integrations/secure.html#report), [metrics report](https://docs.gitlab.com/ee/ci/testing/metrics_reports.html), or [artifact](https://docs.gitlab.com/ee/ci/pipelines/job_artifacts.html#expose-job-artifacts-in-the-merge-request-ui) that can contain almost any type of data.\n\n### 4. Deep GitLab application integration\nThis is the most complex since it requires an understanding of the [architecture of the GitLab application](https://docs.gitlab.com/ee/development/architecture.html#simplified-component-overview), and how an outside service will interact with and support this architecture. An example of this would be a managed PostgresSQL or Redis service. There's a potential risk of downtime if this type of integration goes wrong, so it's important to test thoroughly in a production-like environment before considering it production-ready. Fortunately GitLab publishes several tools to do this. [GitLab Performance Tool (GPT)](/handbook/support/workflows/gpt_quick_start.html) provides an excellent way to measure and report on the performance of a GitLab instance under various usage scenarios. Its counterpart [GitLab Browser Performance Tool](https://gitlab.com/gitlab-org/quality/performance-sitespeed) tests the browser performance of various GitLab pages.  \n\nRead more on [Kurt Dusek's blog](https://blog.scientifik.org/).\n",[9,281,851],{"slug":1309,"featured":6,"template":696},"four-approaches-to-gitlab-integrations","content:en-us:blog:four-approaches-to-gitlab-integrations.yml","Four Approaches To Gitlab Integrations","en-us/blog/four-approaches-to-gitlab-integrations.yml","en-us/blog/four-approaches-to-gitlab-integrations",{"_path":1315,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1316,"content":1322,"config":1329,"_id":1331,"_type":13,"title":1332,"_source":15,"_file":1333,"_stem":1334,"_extension":18},"/en-us/blog/from-idea-to-production-on-thousands-of-clouds",{"title":1317,"description":1318,"ogTitle":1317,"ogDescription":1318,"noIndex":6,"ogImage":1319,"ogUrl":1320,"ogSiteName":683,"ogType":684,"canonicalUrls":1320,"schema":1321},"From idea to production on thousands of clouds","Deliver cloud native applications in more places consistently at scale with GitLab and Gravity.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679266/Blog/Hero%20Images/blue-lights.jpg","https://about.gitlab.com/blog/from-idea-to-production-on-thousands-of-clouds","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"From idea to production on thousands of clouds\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Ev Kontsevoy\"}],\n        \"datePublished\": \"2019-11-20\",\n      }",{"title":1317,"description":1318,"authors":1323,"heroImage":1319,"date":1325,"body":1326,"category":298,"tags":1327},[1324],"Ev Kontsevoy","2019-11-20","\nToday, deploying an application with GitLab is easier than ever: just create a Kubernetes cluster on your cloud of choice, connect it to GitLab with the Kubernetes integration, and Auto DevOps creates a full deployment pipeline for you.\n\nBut what if you need your app to run in two clusters in two separate regions? Ten clusters across multiple cloud providers? A hundred clusters and also on a fleet of self-driving trucks?\n\nAt [Gravitational](https://gravitational.com), we believe the future should not belong to a single cloud provider and developers should be able to run their applications anywhere with the same simplicity as having a single Kubernetes cluster.\n\nI am a huge fan of GitLab. I’ve had the great pleasure of getting to know much of the founding team [over the years](https://about.gitlab.com/blog/gitlab-joins-forces-with-gravitational/) and was happy to provide my [own contribution](https://gitlab.com/gitlab-org/gitlab-foss/issues/22864) to the community a while back. Today, I’m happy to share some thoughts on how to build with GitLab and deploy applications into dozens or even hundreds of cloud environments. \n\n## The rise of multicloud\n\nHow do you run applications in different data centers? Do you need to rewrite them from scratch? AWS may still be the dominant cloud provider, but cloud competitors are eating into their lead. It’s not just the big public cloud companies either. [Private cloud data centers](https://www.forbes.com/sites/jasonbloomberg/2019/02/02/have-private-clouds-finally-found-their-place-in-the-enterprise/#2f859685604f) are growing just as rapidly.\n\nMany companies that need to meet tough security and compliance requirements will require applications to run in their bare metal data centers. Running an application on an on-premises or even air-gapped data center adds additional complexity due to the hundreds or even thousands of dependencies in modern applications.\n\nGravitational has built Gravity, an open source [Kubernetes packaging solution ](https://gravitational.com/gravity/)that allows developers to build “cluster images” (similar to VM images) that can contain an entire Kubernetes cluster pre-loaded with multiple applications. You would use GitLab to go from idea to production, and Gravity to expand your production to anywhere in the world. \n\nStatements like, “I have snapshotted our entire production environment and emailed it to you, so you can run it in your private data center,” will not seem completely crazy.\n\nGravity uses standard, upstream CNCF-supported tooling for creating \"images\" of Kubernetes clusters containing the applications and their dependencies. The resulting files are called cluster images which are just .tar files.\n\nA cluster image can be used to recreate full replicas of the original environments for any deployment environment where compliance and consistency matter, i.e. in locked-down AWS/GCP/Azure environments or even in air-gapped server rooms. Each image includes all dependencies to spin up a full cluster, as well as the Gravity daemon that handles the most common operational tasks associated with Kubernetes applications, and it monitors and alerts human operators of problems.\n\n## Deploy with GitLab, scale with Gravity\n\n![Gravity dashboard](https://about.gitlab.com/images/blogimages/gravity-dashboard.png)\n\nDevelopers can leverage a GitLab repository as a single source of truth for rolling out a Kubernetes app and leverage [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) for continuous delivery.\n\nAny project of meaningful scale begins by defining an [epic](https://docs.gitlab.com/ee/user/group/epics/) with goals, milestones, and tasks. An [issue](https://docs.gitlab.com/ee/user/project/issues/#issues) is the main object for collaborating on ideas and planning work. GitLab’s [package and container registry](https://about.gitlab.com/stages-devops-lifecycle/package/) helps you manage and package dependencies. \n\n[The GitLab Kubernetes integration](https://docs.gitlab.com/ee/user/project/clusters/) allows customers to create Kubernetes clusters, utilize review apps, run pipelines, use web terminals, deploy apps, view pod logs, detect and monitor Kubernetes, and much more. For deploying a Kubernetes cluster in a single destination, GitLab provides everything you need from start to finish. \n\nHowever, if your customers need to run your application in their private data centers, they can use Gravity, which essentially copy/pastes the entire Kubernetes cluster environment you’ve built in GitLab. \n\n[Download](https://gravitational.com/gravity/download/) and set up the Gravity open source edition following our [quickstart guide](https://gravitational.com/gravity/docs/quickstart/). From Gravity, you can build a cluster image of your Kubernetes application. Gravity’s [documentation](https://gravitational.com/gravity/docs/overview/) will walk you through the steps required to build an image manifest that describes the image build, the installation process, and the system requirements for the cluster. \n\nYou can build empty Kubernetes cluster images to quickly create a large number of identical, production-ready Kubernetes clusters within an organization, or you can build a cluster image that also includes Kubernetes applications to distribute your application to third parties. \n\n## Next steps\n\nIf you want to learn more about working with Kubernetes, start with [Kubernetes 101](https://www.youtube.com/watch?v=rq4GZ_GybN8). You’ll learn how GitLab and Kubernetes interact at various touchpoints. And, if you’re looking for a way to port your applications to new environments, check out [Gravity](https://gravitational.com/gravity). \n\n## About the guest author\n\nEv is a co-founder and the CEO of Gravitational. Before Gravitational, he launched the on-demand OpenCompute servers at Rackspace. Prior to Rackspace, he co-founded Mailgun, the first email service built for developers. Ev has been a fighter against unnecessary complexity in software for 20 years. He abhors cars but loves trains and open source software that doesn't require an army of consultants to operate.\n\n## About Gravitational\n\n[Gravitational](https://gravitational.com) helps companies deliver cloud applications across cloud providers, on-premises environments, and even air-gapped server rooms. Products include Teleport for multi-cloud privileged access management that doesn't get in the way of developer productivity, and Gravity, a Kubernetes packaging solution that takes the drama out of on-prem deployments. Gravitational was founded in 2015 and recently [announced their Series A](https://gravitational.com/blog/gravitational-series-a-funding/). \n\nCover image by [Sharon McCutcheon](https://unsplash.com/@sharonmccutcheon) on [Unsplash](https://unsplash.com/photos/TMwHpCrU8D4)\n",[850,851,9,1040,108,1328],"startups",{"slug":1330,"featured":6,"template":696},"from-idea-to-production-on-thousands-of-clouds","content:en-us:blog:from-idea-to-production-on-thousands-of-clouds.yml","From Idea To Production On Thousands Of Clouds","en-us/blog/from-idea-to-production-on-thousands-of-clouds.yml","en-us/blog/from-idea-to-production-on-thousands-of-clouds",{"_path":1336,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1337,"content":1343,"config":1349,"_id":1351,"_type":13,"title":1352,"_source":15,"_file":1353,"_stem":1354,"_extension":18},"/en-us/blog/getting-started-with-gitlab-and-digitalocean",{"title":1338,"description":1339,"ogTitle":1338,"ogDescription":1339,"noIndex":6,"ogImage":1340,"ogUrl":1341,"ogSiteName":683,"ogType":684,"canonicalUrls":1341,"schema":1342},"Getting started with GitLab and DigitalOcean","This tutorial is adapted from the How To Use the GitLab One-Click Install Image to Manage Git Repositories tutorial on DigitalOcean.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749672941/Blog/Hero%20Images/sharks-paper.jpg","https://about.gitlab.com/blog/getting-started-with-gitlab-and-digitalocean","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Getting started with GitLab and DigitalOcean\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Achilleas Pipinellis\"}],\n        \"datePublished\": \"2016-04-27\",\n      }",{"title":1338,"description":1339,"authors":1344,"heroImage":1340,"date":1346,"body":1347,"category":739,"tags":1348},[1345],"Achilleas Pipinellis","2016-04-27","_This tutorial is adapted from the [How To Use the GitLab One-Click Install\n\nImage to Manage Git Repositories][do-source] tutorial on DigitalOcean._\n\n\n### Introduction\n\n\nCollaborating on projects, keeping track of source changes, and maintaining\na\n\nclean code repository are some great reasons to use a [version\ncontrol](/topics/version-control/) system.\n\nVersion control is now considered an essential tool in software development.\n\n\nGit is the most popular distributed version control system. GitLab is a Git\n\nrepository management server that can be used to host repositories and set\nup\n\ncontrol structures for git within a clean web interface. It is built on Ruby\non\n\nRails.\n\n\n[DigitalOcean] has created a GitLab application image that can be used to\n\ninstantly deploy GitLab Community Edition on a DigitalOcean Ubuntu 14.04\nx86-64\n\ndroplet using the [Omnibus installer]. You can have your own repository\nsystem\n\nup and running in minutes.\n\n\n\u003C!-- more -->\n\n\n## Requirements\n\n\nThe [GitLab documentation recommends a minimum of 2GB of RAM and 2 CPU\ncores][req]\n\nfor optimum performance. If your projects are small (fewer than 100 users\ntotal),\n\n1GB of RAM and 1 CPU core may be sufficient, but make sure you have at least\n1GB\n\nswap. You can follow the [How To Add Swap on Ubuntu 14.04][swap] tutorial.\n\n\nLow memory may result in `500` server errors (\"cannot allocate memory\"), so\nmake\n\nsure you add enough RAM according to your needs.\n\n\n## Step One – Create a GitLab Droplet\n\n\nBefore you begin using GitLab, you need to spin up a DigitalOcean droplet\nusing\n\nthe provided image.\n\n\nFrom the Control Panel, click on the \"Create Droplet\" button that is visible\n\nfrom any page:\n\n\n![Create\nDroplet](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/create-droplet-shadow.png)\n\n\nUnder the \"Choose an image\" section, select the \"One-click Apps\" tab and\nclick\n\nthe \"GitLab\" image (the version might differ).\n\n\n![Droplet\napp](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/select_gitlab_app-shadow.png)\n\n\nThe next step is to choose the droplet size and the region you would like to\nuse.\n\n\n![Hardware](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/hardware-shadow.png)\n\n\nAdd any SSH Keys, select any settings you'd like to use, and click \"Create\"\nat\n\nthe bottom.\n\n\n![Finalize\ncreation](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/finalize-shadow.png)\n\n\nYour GitLab droplet will be created and available in a few minutes!\n\n\n## Step Two – Configure Domain Names and Emails\n\n\nWe still need to configure just a few things first to utilize our\nenvironment.\n\n\nBegin by setting up the domain name you would like to use for your GitLab\n\ninstance. Learn [how to set up domain names on DigitalOcean][do-domain] if\nyou\n\nwant to use DigitalOcean's nameservers.\n\n\n>**Note:**\n\nIf you don't have a domain name at your disposal, you can just use your\n\ndroplet's IP address, but GitLab will _not_ be able to send emails without\n\nusing an SMTP server.\n\n\nOnce your domain name is configured correctly, you need to adjust some\nvalues\n\non the actual VPS instance. Log into your droplet as root through SSH, and\nopen\n\nthe GitLab configuration file with your text editor:\n\n\n```\n\nvim /etc/gitlab/gitlab.rb\n\n```\n\n\nUncomment and adjust the `external_url` parameter to match your domain name:\n\n\n```\n\nexternal_url \"http://your_domain.com/\"\n\n```\n\n\nIf you have [generated an SSL certificate][ssl] for your domain, you can\n\nconfigure GitLab to use it in this file as well. The following settings set\nthe\n\nlocations of the SSL certificates and instruct the NGINX web server to\nredirect\n\nthe HTTP traffic to HTTPS. Note that for HTTPS to work, you **must** set the\nURL\n\nscheme in `external_url` as `https`:\n\n\n```\n\nexternal_url \"https://your_domain.com/\"\n\n\nnginx['ssl_certificate'] = \"/etc/gitlab/ssl/your_domain.com.crt\"\n\nnginx['ssl_certificate_key'] = \"/etc/gitlab/ssl/your_domain.com.key\"\n\nnginx['redirect_http_to_https'] = true\n\n```\n\n\nGitLab uses its own bundled NGINX web server. You can find more information\nlike\n\nusing your own external web server, changing the ports NGINX listens to,\netc.,\n\nin the [official documentation][nginx-docs].\n\n\nWhile we're in this file, we can adjust the email settings that GitLab will\nuse\n\nin the \"From:\" field in automated emails, and the email display name,\nrespectively:\n\n\n```\n\ngitlab_rails['gitlab_email_from'] = \"gitlab@your_domain.com\"\n\ngitlab_rails['gitlab_email_display_name'] = 'Example'\n\n```\n\n\nThe GitLab One-Click application is configured to use a local postfix server\n\nfor sending emails. If you wish to use it with GitLab you might want to set\nit\n\nup correctly. Follow the \"[How To Install and Configure Postfix as a\nSend-Only\n\nSMTP Server on Ubuntu 14.04][do-postfix]\" tutorial for more information. For\na\n\nproduction site, you will likely want to use an external service such as\n\nMandrill or SendGrid. If so, you can [configure the SMTP settings][gl-smtp]\nhere\n\nas well.\n\n\nAfter saving and closing the file, we just need to reconfigure the service:\n\n\n```\n\ngitlab-ctl reconfigure\n\n```\n\n\nThis should be done whenever you make configuration changes in order for\nthem to\n\ntake effect.\n\n\n## Step Three – Log into GitLab\n\n\nWhen you connect to your GitLab instance via SSH or the DigitalOcean web\nconsole,\n\nyou will see the message of the day (MOTD) which contains your randomly\ngenerated\n\nGitLab password. It will look like this:\n\n\n```\n\n------------------------------------------------------------------------------\n\nThank you for using DigitalOcean's GitLab Application.\n\nYour GitLab instance can be accessed at http://xxx.xxx.xxx.xxx/\n\nThe default credentials for GitLab are:\n\nUsername: root\n\nPassword: e0wXRM4fLmb6\n\n\nYou can find more information on using this image at: http://do.co/gitlabapp\n\n------------------------------------------------------------------------------\n\n```\n\n\nNext, open a web browser and navigate to your domain name (or the IP address\nof\n\nyour Droplet if you did not set up a domain name). You will be able to log\nin\n\nusing the credentials you found above.\n\n\n![Login](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/login-shadow.png)\n\n\nYou now have a full GitLab server configured and at your disposal to manage\nyour\n\nrepositories.\n\n\n![Landing](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/landing-shadow.png)\n\n\n## Step Four – Modify Account Information\n\n\nIt would probably be more helpful if the account you're using, more\naccurately\n\nreflected your information. This will allow you to receive email updates and\n\nwill display your information to other users. The root account is the first\none\n\ncreated by default, and it contains some predefined values for \"Name\",\n\"Username\"\n\nand \"Email\". You can change all that from the \"Admin Area\".\n\n\nLet's navigate to the \"Admin Area\" by clicking the wrench icon in the\ntop-right\n\ncorner.\n\n\n![Admin](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/admin_button-shadow.png)\n\n\nIn the left sidebar click **Users**. This should only contain one user, the\n\nAdministrator account you are logged into.\n\n\n![Users\narea](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/admin_users-shadow.png)\n\n\nClick on the \"Edit\" button and change the account information at the top.\n\n\nThe \"Name\" field will be your name as displayed to other users. The\n\"Username\"\n\ncan be used to log in and it defines the owner of your projects. The \"Email\"\n\nis where alerts will be sent.\n\n\nIt is important to at least change the email field.\n\n\n![Account\nedit](https://about.gitlab.com/images/blogimages/getting-started-with-gitlab-and-digitalocean/account-shadow.png)\n\n\nClick \"Save changes\" at the bottom for the changes to take effect.\n\n\n## Updating to Newer Releases\n\n\nThe GitLab One-Click application is configured to use the GitLab Apt\nrepository.\n\n[Updating to the most recent version][update-doc] is as simple as running:\n\n\n```\n\nsudo apt-get update\n\nsudo apt-get upgrade\n\n```\n\n\nBefore upgrading to a new release, GitLab automatically backups the\ndatabase.\n\nIf you wish to make a full back up of your existing installation, run:\n\n\n```\n\nsudo gitlab-rake gitlab:backup:create\n\n```\n\n\nThe resulting backup will be located in: `/var/opt/gitlab/backups`. You can\nread\n\nmore in the [Omnibus backup documentation][backup].\n\n\n## Conclusion\n\n\nYou should now have a server configured to handle your team's Git projects.\nYou\n\ncan easily manage user access, configure both public and private\nrepositories,\n\nand get an overview of your projects' issues and commits.\n\n\nGitLab has a great help system accessible from within the user interface\n\n(visit `https://your_domain.com/help`). In a future article, we will discuss\n\nhow to manage repositories and users and effectively take advantage of the\n\ninterface.\n\n\nFor further information on configuring your GitLab Omnibus installation,\ncheck\n\nout the [official documentation][omnidocs].\n\n\n---\n\n\nIf you already have GitLab installed and want to use the [integrated\nCI][glci]\n\nfor your projects, check our other tutorial on\n\n[setting up GitLab Runner on DigitalOcean][runner-do].\n\n\n---\n\n\n[![Powered by\nDigitalOcean](https://about.gitlab.com/images/blogimages/powered-by-do-badge-gray.png)](https://www.digitalocean.com/features/one-click-apps/gitlab/)\n\n\n---\n\n\n_Photo credits: \u003Chttps://flic.kr/p/9RAQ2J> ([CC BY-NC 2.0][cc])_\n\n\n[digitalocean]: https://www.digitalocean.com\n\n[omnibus installer]: /2016/03/21/using-omnibus-gitlab-to-ship-gitlab/\n\n[req]:\nhttp://doc.gitlab.com/ce/install/requirements.html#hardware-requirements\n\n[do-domain]:\nhttps://www.digitalocean.com/community/articles/how-to-set-up-a-host-name-with-digitalocean\n\n[ssl]:\nhttps://www.digitalocean.com/community/tutorials/how-to-install-an-ssl-certificate-from-a-commercial-certificate-authority\n\n[nginx-docs]: http://doc.gitlab.com/omnibus/settings/nginx.html\n\n[do-postfix]:\nhttps://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-as-a-send-only-smtp-server-on-ubuntu-14-04\n\n[gl-smtp]: http://doc.gitlab.com/omnibus/settings/smtp.html\n\n[backup]: http://doc.gitlab.com/omnibus/settings/backups.html\n\n[omnidocs]: http://doc.gitlab.com/omnibus\n\n[do-source]:\nhttps://www.digitalocean.com/community/tutorials/how-to-use-the-gitlab-one-click-install-image-to-manage-git-repositories\n\n[swap]:\nhttps://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04\n\n[runner-do]: /blog/how-to-set-up-gitlab-runner-on-digitalocean/\n\n[glci]: /solutions/continuous-integration/\n[cc]: https://creativecommons.org/licenses/by-nc/2.0/\n\n[update-doc]:\nhttp://doc.gitlab.com/omnibus/update/README.html#updating-using-the-official-repositories\n",[9],{"slug":1350,"featured":6,"template":696},"getting-started-with-gitlab-and-digitalocean","content:en-us:blog:getting-started-with-gitlab-and-digitalocean.yml","Getting Started With Gitlab And Digitalocean","en-us/blog/getting-started-with-gitlab-and-digitalocean.yml","en-us/blog/getting-started-with-gitlab-and-digitalocean",{"_path":1356,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1357,"content":1363,"config":1369,"_id":1371,"_type":13,"title":1372,"_source":15,"_file":1373,"_stem":1374,"_extension":18},"/en-us/blog/gitlab-and-google-cloud",{"title":1358,"description":1359,"ogTitle":1358,"ogDescription":1359,"noIndex":6,"ogImage":1360,"ogUrl":1361,"ogSiteName":683,"ogType":684,"canonicalUrls":1361,"schema":1362},"How GitLab and Google Cloud drive innovation and efficiency for retailers","Learn how pairing DevSecOps with multicloud environments eases the development burden on retailers.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667457/Blog/Hero%20Images/open_source_program_blog_image.jpg","https://about.gitlab.com/blog/gitlab-and-google-cloud","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How GitLab and Google Cloud drive innovation and efficiency for retailers\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Regnard Raquedan\"}],\n        \"datePublished\": \"2023-03-08\",\n      }",{"title":1358,"description":1359,"authors":1364,"heroImage":1360,"date":1366,"body":1367,"category":1244,"tags":1368},[1365],"Regnard Raquedan","2023-03-08","\nInnovation and growth can sometimes be at odds in the world of retail, especially when trying to develop, deploy, and manage modern applications across multicloud environments. GitLab and Google Cloud together help retailers create and secure software that scales along with their business.\n\nGitLab’s comprehensive [DevSecOps Platform](/the-source/platform/devops-teams-want-to-shake-off-diy-toolchains-a-platform-is-the-answer/) connects with Google Cloud’s [Distributed Cloud Edge](https://cloud.google.com/distributed-cloud/edge/latest/docs/overview) edge networking environment and [Anthos](https://cloud.google.com/anthos/docs/concepts/overview) cloud-centric container platform to provide retailers with enterprise-class features such as collaboration and planning, continuous integration ([CI](https://docs.gitlab.com/ee/ci/)), configuration management, and built-in security and compliance.\n\nGitLab enables development teams to streamline management of their distributed, hybrid environments right out of the gate. Retailers can utilize the following capabilities:\n\n* Agile planning and collaboration to ensure Anthos cloud container cluster configurations and policies are up to date and compliant with company standards.\n* Continuous integration to help develop quality code and configurations while simultaneously reducing code errors.\n* Configuration management to roll back to previously working Anthos states or configurations.\n* Native integration with Google Cloud to deploy software faster and more securely.\n\n## Why GitLab for retail?\n\nMulticloud environments are beneficial to retailers because they enable them to easily deploy and manage applications across a vast network of stores, warehouses, and the like. In addition, developing and hosting applications in the cloud provides more choice, faster delivery (i.e. time to market), real-time data access, and the ability to automatically scale resources (up or down). As more retailers look to cloud platforms to achieve these goals, GitLab is uniquely positioned to help them manage these environments in a way that keeps them agile, secure, and able to meet customer demands. \n\nGitLab’s DevSecOps Platform is geared toward helping retailers gain operational efficiencies throughout the software development lifecycle and across [multicloud environments](https://about.gitlab.com/topics/multicloud/) like Google Cloud. \n\nDevelopers at retailers can leverage the full range of features in GitLab’s DevSecOps Platform to build, test, deploy, and secure high-performance, low-latency business-critical applications, such as point of sale. \n\n[Google Distributed Cloud Edge](https://cloud.google.com/distributed-cloud/edge/latest/docs/overview) retail customers can use GitLab to manage their hybrid cloud policies, manage configurations, and administer [Anthos](https://cloud.google.com/anthos/docs) clusters. GitLab’s industry-leading DevSecOps Platform helps developers streamline in-store technology management processes and makes it easier for DevSecOps teams to collaborate. GitLab’s DevSecOps Platform also has built-in security and compliance to meet the unique auditing and reporting needs of retailers. \n\n## Use case: Automated deployment at scale\n\nRetail companies with multiple locations need technology that enables them to manage sprawling resources and maintain smooth operations, even when major changes are introduced. With GitLab’s DevSecOps Platform, retailers can automatically sync configurations and data across their Google Cloud, as well as other cloud and on-premises environments. This is critical for large retailers looking to scale hybrid Anthos clusters vertically across their network with Google Distributed Cloud Edge machines.\n\nGitLab also lets developers easily collaborate and make changes using Agile tools, Merge Requests, and requirements-based workflows. This creates a streamlined, audit-ready process that helps team members make decisions quickly.\n\nConfigurations are stored as YAML files in GitLab repositories, where teams can use a different repository per configuration state. Anthos Configuration Management then retrieves the appropriate configurations when network access is available, allowing for specific regional changes to be made.\n\nOnce changes are reconciled across regions, the new configurations are automatically applied and propagated to the correct Google Distributed Cloud Edge nodes. This secure, scalable process can be used at thousands of locations, decreasing the company's time to value and increasing ROI.\n\nHaving the right technology is a key driver of growth and innovation for retailers. Investing in technology and utilizing platforms like GitLab and Google Cloud can be a game changer for retailers looking to thrive in today's competitive market.\n",[850,785,716,9],{"slug":1370,"featured":6,"template":696},"gitlab-and-google-cloud","content:en-us:blog:gitlab-and-google-cloud.yml","Gitlab And Google Cloud","en-us/blog/gitlab-and-google-cloud.yml","en-us/blog/gitlab-and-google-cloud",{"_path":1376,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1377,"content":1383,"config":1389,"_id":1391,"_type":13,"title":1392,"_source":15,"_file":1393,"_stem":1394,"_extension":18},"/en-us/blog/gitlab-and-jira-integration-the-final-steps",{"title":1378,"description":1379,"ogTitle":1378,"ogDescription":1379,"noIndex":6,"ogImage":1380,"ogUrl":1381,"ogSiteName":683,"ogType":684,"canonicalUrls":1381,"schema":1382},"GitLab and Jira integration: the final steps","The last of our three-part series on GitLab and Jira integrations offers a step-by-step look at how the tools work together.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679490/Blog/Hero%20Images/jira-importer-blog-post.png","https://about.gitlab.com/blog/gitlab-and-jira-integration-the-final-steps","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab and Jira integration: the final steps\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tye Davis\"}],\n        \"datePublished\": \"2021-05-24\",\n      }",{"title":1378,"description":1379,"authors":1384,"heroImage":1380,"date":1386,"body":1387,"category":739,"tags":1388},[1385],"Tye Davis","2021-05-24","\n_This is the third in our three-part series on GitLab and Jira integrations. [Part one](/blog/integrating-gitlab-com-with-atlassian-jira-cloud/) explained how to integrate GitLab.com with Jira Cloud. [Part two](/blog/gitlab-jira-integration-selfmanaged/) walked through a detailed explanation of integrating GitLab self-managed with Jira._\n\nAfter the integration is set up on GitLab and Jira, you can:\n\n* Refer to any Jira issue by its ID in GitLab branch names, commit messages, and merge request titles.\n\n* Using commit messages in GitLab, you have the ability to move Jira issues along that Jira projects defined transitions. Here you can see that this Jira issue has Backlog, Selected for Development, In Progress and Done. \n\n![Issue View in Jira](https://about.gitlab.com/images/blogimages/atlassianjira/issueview.png){: .shadow.medium.center}\nIssue View in Jira\n{: .note.text-center}\n\n* As referenced in the Base GitLab-Jira integration, when you comment in a merge request and commit referencing an issue, e.g., PROJECT-7, will add a comment in Jira issue in the format. In addition, by commenting in a jira transition (putting a “#” first), this will initiate the movement of a Jira Issue to the desired transition. Below is using the built-in GitLab Web IDE (this can be done in your Web IDE of choice as well).\n\n![Comment in a Commit/MR](https://about.gitlab.com/images/blogimages/atlassianjira/commitcomment.png){: .shadow.medium.center}\nComment in a Commit/MR\n{: .note.text-center}\n\n* Currently, the Jira-GitLab Dev Panel integration via DVCS refreshes on a 60-min schedule. To expedite, you’ll need to manually refresh the specific project with your most recent changes.\n\n![Dev Panel refreshes every 60 minutes](https://about.gitlab.com/images/blogimages/atlassianjira/devpanelrefresh.png){: .shadow.medium.center}\nDev Panel refreshes every 60 minutes\n{: .note.text-center}\n\n* See the linked branches, commits, and merge requests in Jira issues (merge requests are called “pull requests” in Jira issues).\nJira issue IDs must be formatted in uppercase for the integration to work.\n\n![See GitLab linked in the Dev Panel](https://about.gitlab.com/images/blogimages/atlassianjira/gitlabdevpanel.png){: .shadow.medium.center}\nSee GitLab linked in the Dev Panel\n{: .note.text-center}\n\n* Click the links to see your GitLab repository data.\n\n![Click into the commits](https://about.gitlab.com/images/blogimages/atlassianjira/clickintocommit.png){: .shadow.medium.center}\nClick into the commits\n{: .note.text-center}\n\n![See GitLab linked in the Dev Panel](https://about.gitlab.com/images/blogimages/atlassianjira/clickintopr.png){: .shadow.medium.center}\nClick into the merge (pull) requests\n{: .note.text-center}\n\nFor more information on using Jira Smart Commits to track time against an issue, specify an issue transition, or add a custom comment, see the Atlassian page Using [Smart Commits](https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html)\n\n## View Jira Issues within GitLab\n\nYou can browse and search issues from a selected Jira project directly in GitLab. This requires configuration in GitLab by an administrator.\n\n* In the GitLab integration setup for Jira, click \"enable Jira issues.\"\n\n![Enable Jira issues in GitLab](https://about.gitlab.com/images/blogimages/atlassianjira/enablejiraissues.png){: .shadow.medium.center}\nEnable Jira issues in GitLab\n{: .note.text-center}\n\n* Locate your project key in Jira.\n\n![Locate your project key in Jira](https://about.gitlab.com/images/blogimages/atlassianjira/locateprojectkey.png){: .shadow.medium.center}\nLocate your project key in Jira\n{: .note.text-center}\n\n* Add your proejct key into the GitLab integration setup for Jira.\n\n![Add your proejct key to GitLab](https://about.gitlab.com/images/blogimages/atlassianjira/addprojectkey.png){: .shadow.medium.center}\nAdd your proejct key to GitLab\n{: .note.text-center}\n\n* Select \"Jira Issues\", then \"Issue List\" from the left panel in GitLab\n\n![Select Jira Issues on left panel](https://about.gitlab.com/images/blogimages/atlassianjira/selectjiraissues.png){: .shadow.medium.center}\nSelect Jira Issues\n{: .note.text-center}\n\nFrom the Jira Issues menu, click Issues List. The issue list defaults to sort by Created date, with the newest issues listed at the top. You can change this to Last updated.\nIssues are grouped into tabs based on their [Jira status](https://confluence.atlassian.com/adminjiraserver070/defining-status-field-values-749382903.html).\n\n* The Open tab displays all issues with a Jira status in any category other than Done.\n* The Closed tab displays all issues with a Jira status categorized as Done.\n* The All tab displays all issues of any status.\n\nClick an issue title to open its original Jira issue page for full details.\n\n![View Jira issues in GitLab](https://about.gitlab.com/images/blogimages/atlassianjira/viewjiraissues.png){: .shadow.medium.center}\nView Jira issues in GitLab\n{: .note.text-center}\n\n### Search and filter the issues list\n\nTo refine the list of issues, use the search bar to search for any text contained in an issue summary (title) or description.\nYou can also filter by labels, status, reporter, and assignee using URL parameters. Enhancements to be able to use these through the user interface are [planned](https://gitlab.com/groups/gitlab-org/-/epics/3622).\n\n* To filter issues by labels, specify one or more labels as part of the labels[] parameter in the URL. When using multiple labels, only issues that contain all specified labels are listed. /-/integrations/jira/issues?labels[]=backend&labels[]=feature&labels[]=QA\n* To filter issues by status, specify the status parameter in the URL. /-/integrations/jira/issues?status=In Progress\n* To filter issues by reporter, specify a reporter’s Jira display name for the author_username parameter in the URL. /-/integrations/jira/issues?author_username=John Smith\n* To filter issues by assignee, specify their Jira display name for the assignee_username parameter in the URL. /-/integrations/jira/issues?assignee_username=John Smith\n\n## Troubleshooting\nIf these features do not work as expected, it is likely due to a problem with the way the integration settings were configured.\n\n### GitLab is unable to comment on a Jira issue\n\nMake sure that the Jira user you set up for the integration has the correct access permission to post comments on a Jira issue and also to transition the issue, if you’d like GitLab to also be able to do so. Jira issue references and update comments will not work if the GitLab issue tracker is disabled.\n\n### GitLab is unable to close a Jira issue\n\nMake sure the Transition ID you set within the Jira settings matches the one your project needs to close an issue.\nMake sure that the Jira issue is not already marked as resolved; that is, the Jira issue resolution field is not set. (It should not be struck through in Jira lists.)\n\n## Conclusion\n \nGitLab helps teams ship software faster with technology integration options, such as the integration with Jira, that automate tasks, provide visibility into development progress and the greater end-to-end software lifecycle. We recognize that many companies use Jira for Agile project management and our seamless integration brings Jira together with GitLab. \n\n## Watch and learn\n\nMore of a video person? For a walkthrough of the integration with GitLab for Jira, watch and learn how to configure GitLab Jira Integration using Marketplace App.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/fWvwkx5_00E\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n\n",[717,9,851],{"slug":1390,"featured":6,"template":696},"gitlab-and-jira-integration-the-final-steps","content:en-us:blog:gitlab-and-jira-integration-the-final-steps.yml","Gitlab And Jira Integration The Final Steps","en-us/blog/gitlab-and-jira-integration-the-final-steps.yml","en-us/blog/gitlab-and-jira-integration-the-final-steps",{"_path":1396,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1397,"content":1402,"config":1409,"_id":1411,"_type":13,"title":1412,"_source":15,"_file":1413,"_stem":1414,"_extension":18},"/en-us/blog/gitlab-arm-aws-graviton2-solution",{"title":1398,"description":1399,"ogTitle":1398,"ogDescription":1399,"noIndex":6,"ogImage":863,"ogUrl":1400,"ogSiteName":683,"ogType":684,"canonicalUrls":1400,"schema":1401},"Announcing 32/64-bit Arm Runner Support for AWS Graviton2","GitLab enables CI/CD solution on Arm-based AWS Graviton2 instances.","https://about.gitlab.com/blog/gitlab-arm-aws-graviton2-solution","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Announcing 32/64-bit Arm Runner Support for AWS Graviton2\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Kushal Koolwal\"}],\n        \"datePublished\": \"2020-05-15\",\n      }",{"title":1398,"description":1399,"authors":1403,"heroImage":863,"date":1405,"body":1406,"category":763,"tags":1407},[1404],"Kushal Koolwal","2020-05-15","\n\n_Kushal Koolwal is senior manager, Software Ecosystem Development at Arm Inc._\n\nAt Arm TechCon 2019, GitLab and Arm [announced](/blog/devops-on-the-edge-a-conversation-about-gitlab-and-arm/) a joint partnership with the goal of providing first class citizen support for Arm architecture starting with [GitLab’s CI/CD tool](/topics/ci-cd/).\n\n\"Arm is on a mission to make cloud-native developers’ experience frictionless by building out the software stack and enabling a complete set of developer tools,\" says [Pete Goldberg](/company/team/#pete_goldberg), director of Partnerships, GitLab. \"Amazon Web Services (AWS) is the first major cloud provider to build and deploy Arm-powered compute instances. GitLab is proud to be Arm’s CI/CD solution, enabling DevOps to seamlessly certify new and existing applications in production environments hosted on AWS Graviton2.\"\n\n### GitLab and Arm announcement and partnership enhancements\n\nToday, the partnership achieved another major milestone in its partnership efforts with the delivery of official support for 32-bit and 64-bit Arm-based GitLab runners in binary, rpm/deb packaging, and Docker image format.\n\n#### This milestone highlights the following enhancements:\n\n\n*   Arm [Runner binaries](https://gitlab-runner-downloads.s3.amazonaws.com/latest/index.html) were made available in the 12.6 release as part of the Graviton2 launch at [AWS re:Invent 2019](/blog/updates-from-aws-reinvent/), allowing developers to start immediately in their custom environments.\n*   [RPM/DEB packages](https://packages.gitlab.com/runner/gitlab-runner) for easier install/upgrade in 12.9 release.\n*   Native Arm [Docker image](https://hub.docker.com/r/gitlab/gitlab-runner/tags) in 13.0 release for container-based environments.\n\n#### As a testament to the strength of the partnership, GitLab has:\n\n*   [Released a demo showing how to deploy and AWS Graviton2 M6g Instance](https://youtu.be/0dntra12w6w)\n*   [Joined](https://developer.arm.com/solutions/infrastructure/developer-resources/ci-cd/gitlab) the [Arm Neoverse developer program ](https://developer.arm.com/solutions/infrastructure/developer-resources/ci-cd/gitlab)\n*   Adding support for Arm architectures for [Auto DevOps](https://gitlab.com/gitlab-org/gitlab/-/issues/214552) and [Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/1625)\n\nLearn more about EC2 M6g Instances, powered by AWS Graviton2, [here](https://aws.amazon.com/blogs/aws/new-m6g-ec2-instances-powered-by-arm-based-aws-graviton2/).\n",[9,108,1408],"demo",{"slug":1410,"featured":6,"template":696},"gitlab-arm-aws-graviton2-solution","content:en-us:blog:gitlab-arm-aws-graviton2-solution.yml","Gitlab Arm Aws Graviton2 Solution","en-us/blog/gitlab-arm-aws-graviton2-solution.yml","en-us/blog/gitlab-arm-aws-graviton2-solution",{"_path":1416,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1417,"content":1422,"config":1428,"_id":1430,"_type":13,"title":1431,"_source":15,"_file":1432,"_stem":1433,"_extension":18},"/en-us/blog/gitlab-ci-cd-with-firebase",{"title":1418,"description":1419,"ogTitle":1418,"ogDescription":1419,"noIndex":6,"ogImage":863,"ogUrl":1420,"ogSiteName":683,"ogType":684,"canonicalUrls":1420,"schema":1421},"How to leverage GitLab CI/CD for Google Firebase","Firebase is a powerful backend-as-a-service tool and when combined with GitLab it can be easy to enable continuous deployment of database, serverless and apps.","https://about.gitlab.com/blog/gitlab-ci-cd-with-firebase","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to leverage GitLab CI/CD for Google Firebase\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brendan O'Leary\"}],\n        \"datePublished\": \"2020-03-16\",\n      }",{"title":1418,"description":1419,"authors":1423,"heroImage":863,"date":1425,"body":1426,"category":739,"tags":1427},[1424],"Brendan O'Leary","2020-03-16","\n\nBuilding mobile apps can be painful - especially when it comes to finding a way to provide all the tooling needed to make the application feasible without becoming an expert in many different disciplines. [Firebase from Google](https://firebase.google.com/) aims to take away that burden by providing an app deployment platform and a BaaS or Backend-as-a-Service. While the offerings can vary greatly, most BaaS providers include a database, object storage, push notifications and some sort of hosting package. Firebase goes beyond this and provides user authentication built-in as well as [serverless](/topics/serverless/) functions, telemetry, and Google tools for growth.  \n\nThose tools are very appealing to mobile and even web-app developers and Firebase has been successful in that market with customers including The New York Times, Lyft and Duolingo just to name a few. But even with all of the fantastic BaaS tools Firebase brings to bear on a project, it is critical to have source code management and [CI/CD tools](/topics/ci-cd/) to match. As Firebase configuration for important settings such as database security, serverless functions, and hosting can all be stored “as-code” inside your application’s repository, GitLab paired with Firebase can make for a powerful duo.\n\n## Our app\n\nOur application will be a relatively simple link shortener for use with the domain [labwork.dev](https://labwork.dev). In order to build a link shortener, we’ll need the ability to log users in, a database for storing the links and a way to redirect folks coming with the short links to the longer website. Firebase comes with these items packaged together - which should make it relatively painless to stand up (famous last words right?).\n\nI plan on covering the application in more detail in the future, or if you want to jump to the end you can find the [completed project here](https://gitlab.com/brendan-demo/labwork/homepage/). For now, I wanted to at least introduce the architecture plan. I’ll use [Vue.js](https://vuejs.org) for the frontend. Vue.js is a web application that lets users log in using Firebase Authentication. Once logged in, users will have access to a form that allows them to create new short URLs. That form will call a Firebase Function that checks to see if the shortcode requests already exist (or create a random hash if not specified). If the shortcode is unique, the function adds the shortcode and longer URL to the `urls` collection in Firestore and returns okay.  \n\nOnce the shortcode is in the database, I’ll use another cloud function to retrieve the long URL associated with it. Firestore has a great feature that allows you to redirect traffic based on a pattern to a specified function, and I’ll use this so that anything that comes to `/go/{shortcode}` gets magically redirected to the correct long URL.\n\n![Basic Architecture Diagram](https://about.gitlab.com/images/blogimages/firebase_01.png){: .shadow.large.center}\n\n## Add Firebase to the project\n\nOnce we have this architecture finalized, and have built the skeleton of the project and are ready to start deploying and testing, it’s time to add Firebase to our project. Firebase provides a [very helpful CLI tool](https://github.com/firebase/firebase-tools) for getting started here and we’ll use that to begin.\n\nThe first command `firebase init` starts the project initialization process.\n\n![Output of firebase init command](https://about.gitlab.com/images/blogimages/firebase_02.png){: .shadow.large.center}\n\nFrom there, you can select which services you want to use with this project. You’ll also be able to decide to create a new Firebase project, or use one you previously created in the [Firebase console](https://console.firebase.google.com/). You also can select where to store the configuration files. I’ll add a folder called `firebase-config` to store all of these files. Now you are able to source control all changes to your Firebase architecture - from indexes to security rules - all in the same repository as your project.\n\n![Firebase config files](https://about.gitlab.com/images/blogimages/firebase_03.png){: .shadow.large.center}\n\nYou can see all of the changes required to add Firebase to the project [in this merge request](https://gitlab.com/brendan-demo/labwork/homepage/-/merge_requests/1).\n\n## Deploy project to Firebase\n\nNow that Firebase is installed in our project folder and configured, we’re ready to deploy for the first time. In order to deploy the Vue.js portion of the project, we first need to build it to production HTML, CSS and Javascript. So before deployment, run the `yarn build` command.  This will output the build to the `dist` folder by default, and I’ve configured Firebase to recognize that directory as the hosting direction in the `firebase.json`.\n\n![Firebase.json example](https://about.gitlab.com/images/blogimages/firebase_04.png){: .shadow.large.center}\n\nOnce the project is built, running a simple `firebase deploy` will deploy ALL of the features of the project to Firebase: the security rules and indexes for Firestore, the Firebase Functions and the Vue.js project to Firebase Hosting.\n\nIf desired, we can also chose to deploy just a particular part of the project with the `--only` flag. For example, to only deploy a new version of the functions, we can say \n\n`firebase deploy --only functions`\n\nThis is a feature that we’ll combine with GitLab CI/CD in the next step to make our deployments as efficient as possible.\n\n## Automate deployments with GitLab CI/CD\n\nNow that we have the project deploying, we can automate that deploy process so that we don’t have to be at our computer authenticated to Firebase in order to deploy new changes. The steps to automate the deploy are relatively painless and include: (1) acquire a Firebase API key to use during deployment, (2) setup the `.gitlab-ci.yml` file to install the firebase CLI before running any other steps and (3) issue the deployment commands for each part of the infrastructure depending on the change in a particular commit to the main branch.\n\nFirst, we need an API key so that GitLab CI/CD can authenticate to Firebase and perform the deploy. To get the API key, we can run `firebase login:ci` from the same place we were deploying the application previously. This will provide a key that looks something like `` which we’ll add to GitLab.\n\nWhen you enter `firebase login:ci`, open the URL provided in your browser. That will open a Google authentication page; then log in with your Google account and click `Allow`.  Then return to the terminal and you’ll see the authentication code.\n\n![Output of firebase login:ci command](https://about.gitlab.com/images/blogimages/firebase_05.png){: .shadow.large.center}\n\nOnce you’ve successfully authenticated and obtained the token, go to your project on GitLab and go to Settings -> CI/CD -> Variables. Here’s where we’ll add the token as an environmental variable to be used in our deployment jobs. The key is `FIREBASE_TOKEN` and then the value is the token that was printed to your terminal. I’ve made mine both a [protected](https://docs.gitlab.com/ee/ci/variables/#protected-environment-variables) and [masked](https://docs.gitlab.com/ee/ci/variables/#masked-variables) variable. That means the variable will only be exposed to protected branches and if it’s accidentally echoed to the job output, GitLab will hide it from leaking into there.\n\n![Varaiable configuration screen in GitLab](https://about.gitlab.com/images/blogimages/firebase_06.png){: .shadow.large.center}\n\nNow we can start on the configuration for our `.gitlab-ci.yml`.  At the top of the file I’m going to set the default image to be the current node alpine image from Docker hub:\n\n```yaml\nimage: node:12.13.0-alpine\n```\n\nNext, I’ll create a `before_script` that will install the firebase CLI before running any jobs in the file. In the future, I could bundle that CLI into my own custom Docker image to avoid doing this every time, but for now I’ll go with the boring solution.\n\n```yaml\nbefore_script:\n  - npm i -g firebase-tools\n```\n\nFor the build steps, I want to create a separate job for each part of the infrastructure: Firestore, Functions and the Vue app into Firebase Hosting. To do this, I’m going to utilize the ﻿﻿[`only:`](https://docs.gitlab.com/ee/ci/yaml/#only--except) feature to only deploy that part of the infrastructure impacted by changes and that have been merged to master. For example, we’ll only deploy the Firebase Functions when something changes in the `/functions` on the `master` branch\n\n```yaml\ndeploy-functions:\n  stage: deploy\n  script:\n    - cd functions\n    - npm install\n    - cd ..\n    - firebase deploy --only functions --token $FIREBASE_TOKEN\n  only:\n    refs:\n      - master\n    changes:\n      - functions/**/*\n```\nWe’ll repeat this same pattern for both Firestore and the Hosting project, adding the `yarn build` step before deploying hosting each time. Once that’s completed, every time a merge request is accepted, GitLab CI/CD will automatically deploy the changes into our live production application. You can view the [completed `.gitlab-ci.yml` here](https://gitlab.com/brendan-demo/labwork/homepage/-/blob/master/.gitlab-ci.yml), or check out the link shortener for yourself (and try and [Rick Roll](https://labwork.dev/go/30201a) your friends at [labwork.dev](https://labwork.dev)).\n",[108,850,9],{"slug":1429,"featured":6,"template":696},"gitlab-ci-cd-with-firebase","content:en-us:blog:gitlab-ci-cd-with-firebase.yml","Gitlab Ci Cd With Firebase","en-us/blog/gitlab-ci-cd-with-firebase.yml","en-us/blog/gitlab-ci-cd-with-firebase",{"_path":1435,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1436,"content":1442,"config":1448,"_id":1450,"_type":13,"title":1451,"_source":15,"_file":1452,"_stem":1453,"_extension":18},"/en-us/blog/gitlab-ci-on-google-kubernetes-engine",{"title":1437,"description":1438,"ogTitle":1437,"ogDescription":1438,"noIndex":6,"ogImage":1439,"ogUrl":1440,"ogSiteName":683,"ogType":684,"canonicalUrls":1440,"schema":1441},"GitLab CI/CD on Google Kubernetes Engine in 15 minutes or less","Install GitLab's Runner on GKE in a few simple steps and get started with GitLab CI/CD pipelines.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667003/Blog/Hero%20Images/gke_in_15_cover_2.jpg","https://about.gitlab.com/blog/gitlab-ci-on-google-kubernetes-engine","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab CI/CD on Google Kubernetes Engine in 15 minutes or less\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Elliot Rushton\"}],\n        \"datePublished\": \"2020-03-27\",\n      }",{"title":1437,"description":1438,"authors":1443,"heroImage":1439,"date":1444,"body":1445,"category":739,"tags":1446},[803],"2020-03-27","If you use [GitLab Self-Managed](/pricing/#self-managed), then getting started with GitLab CI using [GitLab's integration with Google Kubernetes Engine (GKE)](/partners/technology-partners/google-cloud-platform/) can be accomplished in a few simple steps. We have several blog posts and documentation that provide detailed [setup instructions for working with Kubernetes clusters](#other-resources). In this post, we highlight the essential steps so that you can get going with GitLab CI/CD in less than 15 minutes.\n\nBy using the GitLab and GKE integration, with one click, you install GitLab Runners on GKE and immediately start running your CI pipelines. Runners are the lightweight agents that execute the CI jobs in your [GitLab CI/CD](/topics/ci-cd/) pipeline.\n\n## Prerequisites:\n\nThe following pre-requisities will need to have been configured in order for you to use the built in GitLab GKE integration:\n- GitLab instance installed and configured with user credentials\n- [Google OAuth2 OmniAuth Provider](https://docs.gitlab.com/ee/integration/google.html) installed and configured on your GitLab instance\n- A Google Cloud project with the following [APIs enabled](https://docs.gitlab.com/ee/integration/google.html#enabling-google-oauth):\n  - Google Kubernetes Engine API\n  - Cloud Resource Manager API\n  - Cloud Billing API\n\n## Get started\n\n![Setup pipeline](https://about.gitlab.com/images/blogimages/ci-gke-in-15/gke_in_15_pipeline.png){: .shadow.medium.center}\n\n### Step 1\n\nWe’re going to add a shared runner at the instance level. First, as an administrator, click the “Admin Area” icon\n\n![Runner setup step 1](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_001.png){: .shadow.medium.center}\n\nThen on the left menu, select “Kubernetes”\n\n![Runner setup step 2](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_002.png){: .shadow.medium.center}\n\n### Step 2\n\nClick the green “Add Kubernetes cluster” button.\n\n![Runner setup step 3](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_003.png){: .shadow.medium.center}\n\n### Step 3\n\nThe screen to “Add a Kubernetes cluster integration” should come up. Click on the “Google GKE” icon on the right.\n\n![Runner setup step 4](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_004.png){: .shadow.medium.center}\n\n### Step 4\n\nGive your cluster a name, and select a “Google Cloud Platform project” from your linked GCP account. If no projects are populated in the menu then either your Google OAUTH2 integration isn’t configured correctly or your project is missing the needed permissions. Check that these are set up and that the [APIs mentioned in the prerequisites above](#prerequisites) are enabled.\n\nChoose a zone in which to run your cluster. For the purposes of running CI, the number of nodes in your cluster is going to be how many simultaneous jobs you can run at given time. As we are using the built-in GitLab Google Kubernetes integration, you can set a maximum of four nodes.\nHere we set that to three.\n\nClick “Create Kubernetes Cluster”\n\n![Runner setup step 5](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_005.png){: .shadow.medium.center}\n\nIt takes a few minutes for the cluster to be created. While it’s happening you should see a screen like this. You can leave this screen and come back (by going to “Admin Area> Kubernetes > [your cluster name]”)\n\n![Runner setup step 6](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_006.png){: .shadow.medium.center}\n\n### Step 5\n\nOnce the cluster has been created, we need to install two applications. First, install “Helm Tiller” by clicking on the “Install” button next to it.\n\n![Runner setup step 7](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_007.png){: .shadow.medium.center}\n\nThis takes a moment, but should be much quicker than creating the cluster initially was.\n\n![Runner setup step 8](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_008.png){: .shadow.medium.center}\n\n### Step 6\n\nNow that Helm Tiller is installed, more applications can be installed. For this tutorial we only need to install the “GitLab Runner” application. Click the install button next to GitLab Runner.\n\n![Runner setup step 9](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_009.png){: .shadow.medium.center}\n\nAgain, this should go pretty quickly.\n\n![Runner setup step 10](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_010.png){: .shadow.medium.center}\n\nOnce done, the button will change to an “Uninstall” button. You’re now set up with shared runners on your GitLab instance and can run your first CI pipeline!\n\n![Runner setup step 11](https://about.gitlab.com/images/blogimages/ci-gke-in-15/ci_gke_in_15_011.png){: .shadow.medium.center}\n\n### Next steps\n\nNow that you are up and running with GitLab CI/CD on GKE, you can build and run your first GitLab CI/CD pipeline. Here are links to a few resources to get you started.\n\n- [Getting Started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/)\n- [How to build a CI/CD pipeline in 20 minutes or less](/blog/building-a-cicd-pipeline-in-20-mins/)\n- [Getting started with Auto DevOps](https://docs.gitlab.com/ee/topics/autodevops/cloud_deployments/auto_devops_with_gke.html)\n\nIf you are planning to manage your own fleet of GitLab Runners, then you may also be thinking about how best to set up autoscaling of GitLab Runners. As we have just set up your first Runner on GKE, then you can review the [GitLab Runner Kubernetes Executor docs](https://docs.gitlab.com/runner/executors/kubernetes.html) for additional details as to how the GitLab Runner uses Kubernetes to run builds on a Kubernetes cluster.\n\n### Other resources\n\n- [Scalable app depoyment webcast](https://about.gitlab.com/webcast/scalable-app-deploy/)\n- [Install GitLab on a cloud native environment](https://docs.gitlab.com/charts/)\n- [Adding and removing Kubernetes clusters](https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html)\n- [Deploy production-ready GitLab on Google Kubernetes Engine](https://cloud.google.com/solutions/deploying-production-ready-gitlab-on-gke)\n\nCover image by [Agê Barros](https://unsplash.com/photos/rBPOfVqROzY) on [Unsplash](https://www.unsplash.com)\n{: .note}\n",[9,1040,850,108,1447,741],"GKE",{"slug":1449,"featured":6,"template":696},"gitlab-ci-on-google-kubernetes-engine","content:en-us:blog:gitlab-ci-on-google-kubernetes-engine.yml","Gitlab Ci On Google Kubernetes Engine","en-us/blog/gitlab-ci-on-google-kubernetes-engine.yml","en-us/blog/gitlab-ci-on-google-kubernetes-engine",{"_path":1455,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1456,"content":1462,"config":1470,"_id":1472,"_type":13,"title":1473,"_source":15,"_file":1474,"_stem":1475,"_extension":18},"/en-us/blog/gitlab-cnh-for-50k-users",{"title":1457,"description":1458,"ogTitle":1457,"ogDescription":1458,"noIndex":6,"ogImage":1459,"ogUrl":1460,"ogSiteName":683,"ogType":684,"canonicalUrls":1460,"schema":1461},"Ready-To-Run GitLab for 50,000 users with AWS Quick Start","If you have two hours, you can deploy a GitLab instance on EKS for any number of users. All it takes is about 14 clicks! Here's what you need to know.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680619/Blog/Hero%20Images/construction-blueprint.jpg","https://about.gitlab.com/blog/gitlab-cnh-for-50k-users","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to provision Ready-To-Run GitLab for 50,000 users with the AWS Quick Start\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Darwin Sanoy\"}],\n        \"datePublished\": \"2021-10-06\",\n      }",{"title":1463,"description":1458,"authors":1464,"heroImage":1459,"date":1466,"body":1467,"category":739,"tags":1468},"How to provision Ready-To-Run GitLab for 50,000 users with the AWS Quick Start",[1465],"Darwin Sanoy","2021-10-06","\n\nIf you have spent time reviewing GitLab Reference Architectures, you may have noticed the flexibility of the GitLab codebase; it's possible to support a broad range of implementations from a single box for under one hundred users to horizontal hyper-scaled setups for 50,000 or more.\n\nScaling to massive sizes requires the services within GitLab to be broken out into dedicated compute and storage layers so they can each expand cost effectively based on high loading and an organization's specific usage patterns.\n\nThose who provision large scale systems on the cloud generally turn to [Infrastructure as Code (IaC)](/direction/delivery/infrastructure_as_code/) to ensure consistency and to allow easy setup of pre-production environments for the target system. Until recently, GitLab implementers have had to craft this code from scratch.\n\nNow, thanks to our investments in IaC tooling, GitLab customers now have an entire implementation eco-system to work from. These efforts include the [GitLab Environment Toolkit (GET)](/blog/why-we-are-building-the-gitlab-environment-toolkit-to-help-deploy-gitlab-at-scale/) and the AWS Quick Start for cloud native hybrid on EKS.\n\nThis post will focus on the AWS Quick Start - but it's worth noting both initiatives are open source - so you can consume, customize and contribute!\n\n## What is an AWS Quick Start?\n\nAWS Quick Starts are much more than the \"getting started\" feeling implied by their name. As a part of the Quick Start program, AWS ensures that each one reflects the best practices of the software vendor (GitLab in this case) as well as AWS' own well-architected standards. They reflects a high level of technical partnership and technical assurance by both companies. The Quick Start program also includes a hard requirement for high availability of every component of the deployed application. Even bastion hosts are run in an autoscaling group so they will respawn if they unexpectedly terminate. Quick Starts are also intended to create a \"Ready-to-Run\" implementation whenever possible. Quick Starts are open source and have a dependency model which allows GitLab to reuse the existing EKS Quick Start as a foundation.\n\n## What Is the GitLab AWS implementation pattern for cloud native hybrid on EKS?\n\nGitLab has Reference Architectures that determine how to install GitLab for various user counts. Each Reference Architecture has a section on cloud native hybrid to show how to configure it and the advised number of vCPUs and memory for the target user count. Each one is similar to blueprints for a building. \n\nThe AWS implementation pattern for cloud native hybrid on EKS builds on this information by:\n\n- Showing how to maximize the usage of AWS PaaS with assurance of GitLab Reference Architecture compliance.\n- Showing a tally of total cluster resources as specified by the Rreference Architecture.\n- Presenting a bill of materials listing:\n\n  - EKS node instance type (sizing) and count as tested.\n  - RDS PostgreSQL and Redis Elasticache instance types (sizing) and count as tested.\n  - Gitaly Cluster instance types (sizing) and count as tested.\n  \n- [GPT testing](https://gitlab.com/gitlab-org/quality/performance) results for a system configured according to the bill of materials. This can be used to compare back to the reference architectures and to your own configuration that is based on the bill of materials.\n\nSo while the Reference Architectures are like building blueprints, the AWS implementation pattern for cloud native hybrid on EKS intends to be like a bBill of mterials (shopping list) you can plug directly into the parameters of the AWS Quick Start or the GitLab Environment Toolkit to build GitLab on EKS with a pre-tested configuration.\n\n## \"Deploy Now\" links\n\nWithin each AWS implementation pattern for cloud native hybrid on EKS you will find some \"Deploy Now\" links.  These make the AWS Quick Start even easier to use by presetting all the instance types and instance counts based on the bill of materials for the user size.  This reduces the number of fields you need to fill out on the Quick Start form. The Deploy Now links are how we were able to reduce the number of clicks to deploy for 50,000 users to just 14.\n\nThe Quick Start takes about two hours to deploy regardless of the size of instance you choose.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/s3ZaBXYG8nc\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n## How you can deploy GitLab for any number of users in a couple of hours\n\nThe YouTube playlist [Learning to provision the AWS Quick Start for GitLab on EKS](https://youtube.com/playlist?list=PL05JrBw4t0Koi8VBnoVhmj_MstnbJjGw5) walks you through:\n\n1. [GitLab Reference Architectures, performance testing, cloud native hybrid and what is Gitaly](https://www.youtube.com/watch?v=1TYLv2xLkZY&list=PL05JrBw4t0Koi8VBnoVhmj_MstnbJjGw5&index=1&t=399s) (11mins)\n2. [An overview of GitLab AWS implementation patterns](https://www.youtube.com/watch?v=_x3I1aq7fog&list=PL05JrBw4t0Koi8VBnoVhmj_MstnbJjGw5&index=2) (13mins)\n3. [An overview of AWS Quick Start for cloud native hybrid on EKS](https://www.youtube.com/watch?v=XHg6m6fJjRY&list=PL05JrBw4t0Koi8VBnoVhmj_MstnbJjGw5&index=3&t=8s) (9mins)\n4. [Provisioning Ready-To-Run GitLab for 50,000 users in 14 clicks and a long lunch)](https://www.youtube.com/watch?v=s3ZaBXYG8nc&list=PL05JrBw4t0Koi8VBnoVhmj_MstnbJjGw5&index=4&t=798s) (21mins) - same as above video.\n5. [Easy performance testing an AWS Quick Start-provisioned GitLab cloud native hybrid instance](https://www.youtube.com/watch?v=QpkF1vXXCjk&list=PL05JrBw4t0Koi8VBnoVhmj_MstnbJjGw5&index=5&t=510s) (32mins)\n\nIf you would like help getting started with Gitlab instance provisioning on AWS, please contact your GitLab account team or reach out to [GitLab Sales](https://about.gitlab.com/sales/)!\n",[850,9,1469],"AWS",{"slug":1471,"featured":6,"template":696},"gitlab-cnh-for-50k-users","content:en-us:blog:gitlab-cnh-for-50k-users.yml","Gitlab Cnh For 50k Users","en-us/blog/gitlab-cnh-for-50k-users.yml","en-us/blog/gitlab-cnh-for-50k-users",{"_path":1477,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1478,"content":1484,"config":1490,"_id":1492,"_type":13,"title":1493,"_source":15,"_file":1494,"_stem":1495,"_extension":18},"/en-us/blog/gitlab-com-artifacts-cdn-change",{"title":1479,"description":1480,"ogTitle":1479,"ogDescription":1480,"noIndex":6,"ogImage":1481,"ogUrl":1482,"ogSiteName":683,"ogType":684,"canonicalUrls":1482,"schema":1483},"GitLab.com CI artifacts to use Google Cloud CDN","GitLab CI users might benefit from faster downloads from edge caches closest to the user's location.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663009/Blog/Hero%20Images/ESA_case_study_image.jpg","https://about.gitlab.com/blog/gitlab-com-artifacts-cdn-change","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab.com CI artifacts to use Google Cloud CDN\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Stan Hu\"}],\n        \"datePublished\": \"2022-10-25\",\n      }",{"title":1479,"description":1480,"authors":1485,"heroImage":1481,"date":1487,"body":1488,"category":763,"tags":1489},[1486],"Stan Hu","2022-10-25","Over the next month and going forward, requests for GitLab CI artifacts\ndownloads may be redirected\n\nto [Google Cloud CDN](https://cloud.google.com/cdn) instead of\n\n[Google Cloud Storage](https://cloud.google.com/storage). We anticipate that\nGitLab CI users may benefit from faster\n\ndownloads from edge caches closest to your location.\n\n\n**Disclaimer:** This blog contains information related to upcoming products,\nfeatures, and functionality. It is important to note that the information in\nthis blog post is for informational purposes only. Please do not rely on\nthis information for purchasing or planning purposes. As with all projects,\nthe items mentioned in this blog and linked pages are subject to change or\ndelay. The development, release, and timing of any products, features, or\nfunctionality remain at the sole discretion of GitLab.\n\n\n## How will this work?\n\n\nCurrently when a CI runner or other client [downloads a CI\nartifact](https://docs.gitlab.com/ee/api/job_artifacts.html),\n\nGitLab.com responds with a 302 redirect to a time-limited, pre-signed URL\nwith a domain of `storage.googleapis.com`.\n\n\nAfter this change, the domain will change to\n`cdn.artifacts.gitlab-static.net`.\n\n\nThe exception is for requests originating from within the Google Cloud\n\nPlatform. These will continue to be redirected to Cloud Storage.\n\n\n## When will this change occur?\n\n\nWe expect to start the transition around the end of October 2022. This will\nbe a\n\ngradual transition using a percentage-based rollout, so we anticipate that\nyou will see\n\nan increasing number of your requests redirected to Google Cloud\n\nCDN instead of Google Cloud Storage until all of the requests are served by\nthe\n\nformer.\n\n\nYou can follow along with the progress of this initiative and raise any\n\nquestions in [this\nissue](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/7894). We\n\nwill post more detailed timelines in that issue as we refine the rollout\n\nplan.\n\n\n## How does this change impact you?\n\n\nSince GitLab CI runners and certain clients automatically handle URL\n\nredirections already, we expect that downloads for CI artifacts should\n\ncontinue to work without any action.\n\n\nWe encourage upgrading to the latest version of the GitLab Runner in\n\norder to take advantage of the CDN. This feature was [introduced in\n\nGitLab Runner\nv13.1.0](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/2115).\n\nIf a runner cannot download from the CDN host, it will retry without the\n\nCDN and download the artifact directly through GitLab.com.\n\n\nHowever, if you have a firewall that only allows\n\n`storage.googleapis.com`, you will need to add\n\n`cdn.artifacts.gitlab-static.net` (34.110.204.38) to the allow list.\n\n\n### What do these warning messages mean?\n\n\nWith this change, users may see warning messages in the CI job logs:\n\n\n#### read: connection reset by peer\n\n\n```plaintext\n\nERROR: Downloading artifacts from coordinator... error couldn't execute GET\nagainst https://gitlab.com/api/v4/jobs/\u003Cjob\nid>/artifacts?direct_download=true: Get\n\"https://cdn.artifacts.gitlab-static.net/...\n\nread tcp 172.17.0.2:59332->34.110.204.38:443: read: connection reset by\npeer  id=1234 token=\u003Csome token>\n\nWARNING: Retrying...                                error=invalid argument\n\nDownloading artifacts from coordinator... ok        id=1234\nresponseStatus=200 OK token=\u003Csome token>\n\n```\n\n\nThis error suggests the runner was not able to access the CDN. Check\n\nyour network firewalls and allow access to the IP 34.110.204.38.\n\n\nNote that there are two `Downloading artifacts from coordinator`\n\nmessages. The second attempt succeeded because the runner retried\n\nwithout the CDN.\n\n\n#### x509: certificate signed by unknown authority\n\n\n```plaintext\n\nERROR: Downloading artifacts from coordinator... error couldn't execute GET\nagainst https://gitlab.com/api/v4/jobs/\u003Cjob\nid>/artifacts?direct_download=true: Get\n\"https://storage.googleapis.com/gitlab-gprd-artifacts/...: x509: certificate\nsigned by unknown authority  id=1234 token=\u003Csome token>\n\n```\n\n\nIf you see this error with a Windows runner, upgrade to v15.5.0 since it\n\nis compiled with [Go 1.18](https://tip.golang.org/doc/go1.18), which\n\nsupports [using the system certificate\npool](https://github.com/golang/go/issues/16736).\n\n\nOtherwise, this error suggests the runner is configured with [custom SSL\ncertificates](https://docs.gitlab.com/runner/configuration/tls-self-signed.html).\n\nYou may need to update your certificates or include the certificates\ndirectly in the bundle.\n\n\n#### Authentication required\n\n\nSome clients may report a 401 error with `Authentication required` after\n\nrequesting to download a job artifact:\n\n\n```xml\n\n\u003C?xml version='1.0'\nencoding='UTF-8'?>\u003CError>\u003CCode>AuthenticationRequired\u003C/Code>\u003CMessage>Authentication\nrequired.\u003C/Message>\u003C/Error>\n\n```\n\n\nThis error message suggests the HTTP client is following the 302\n\nredirect and sending the `Authorization` header with the redirected\n\nURL. This is a known issue with Java HTTP clients.\n\n\nUpdate your client to drop the `Authorization` header the\n\nredirect. Google Cloud Storage ignores this header if it were set, but\n\nCloud CDN rejects requests that have the `Authorization` header set.\n",[851,1161,1287,9,785],{"slug":1491,"featured":6,"template":696},"gitlab-com-artifacts-cdn-change","content:en-us:blog:gitlab-com-artifacts-cdn-change.yml","Gitlab Com Artifacts Cdn Change","en-us/blog/gitlab-com-artifacts-cdn-change.yml","en-us/blog/gitlab-com-artifacts-cdn-change",{"_path":1497,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1498,"content":1504,"config":1510,"_id":1512,"_type":13,"title":1513,"_source":15,"_file":1514,"_stem":1515,"_extension":18},"/en-us/blog/gitlab-com-container-registry-cdn-change",{"title":1499,"description":1500,"ogTitle":1499,"ogDescription":1500,"noIndex":6,"ogImage":1501,"ogUrl":1502,"ogSiteName":683,"ogType":684,"canonicalUrls":1502,"schema":1503},"GitLab.com Container Registry to use Google Cloud CDN","The GitLab.com Container Registry will now interface with the Google Cloud Content Delivery Network","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670766/Blog/Hero%20Images/container-reg-cdn-blog.jpg","https://about.gitlab.com/blog/gitlab-com-container-registry-cdn-change","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab.com Container Registry to use Google Cloud CDN\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Darren Eastman\"}],\n        \"datePublished\": \"2022-01-13\",\n      }",{"title":1499,"description":1500,"authors":1505,"heroImage":1501,"date":1507,"body":1508,"category":298,"tags":1509},[1506],"Darren Eastman","2022-01-13","\n\nIn January 2022, we are working on implementing a change to the Container Registry on GitLab.com. The GitLab Container Registry will now interface with the Google Cloud Content Delivery Network [CDN](https://cloud.google.com/cdn) to optimize costs and improve performance. When implemented, the system will redirect download requests for blobs stored in the GitLab Container Registry to Google Cloud CDN instead of Google Cloud Storage, as is the case today. We expect GitLab CI users to benefit from faster image downloads for those image layers retrieved from edge caches closest to your location.\n\n**Disclaimer** This blog contains information related to upcoming products, features, and functionality. It is important to note that the information in this blog post is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. As with all projects, the items mentioned in this blog and linked pages are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab.\n\n## How will this work?\n\nAuthorized requests for [downloading a blob](https://docs.docker.com/registry/spec/api/#pulling-a-layer) and [checking if a blob exists](https://docs.docker.com/registry/spec/api/#existing-layers) in the [GitLab.com Container Registry](https://docs.gitlab.com/ee/user/packages/container_registry) will be redirected to the Google Cloud CDN at `cdn.registry.gitlab-static.net`. So far, these requests were redirected to Google Cloud Storage at `storage.googleapis.com`.\n\nThe exception is for requests originating from within the Google Cloud Platform. These will continue to be redirected to Cloud Storage.\n\n## When will this change occur?\n\nWe expect to start the transition in late January 2022. This will be a gradual transition using a percentage-based rollout, so you can expect an increasing number of your requests to be redirected to Google Cloud CDN instead of Google Cloud Storage until all of them are served by the former.\n\nYou can follow along with the progress of this initiative and raise any questions in this [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/350048). We will post more detailed timelines in that issue as we refine the rollout plan.\n\n## How does this change impact you?\n\nSince most client tools, such as the Docker CLI, handle redirections automatically, this change will be imperceptible for most users on GitLab.com.\n\nHowever, if you are allow listing `storage.googleapis.com`, you will need to add `cdn.registry.gitlab-static.net` to the allow list as well. Please keep both endpoints on your allow list for the time being, as the transition will be gradual. There will be another blog post once the transition is complete.\n\n\nCover image by [Pat Kay](https://unsplash.com/photos/3d7DTnuNj6E) on [Unsplash](https://unsplash.com)\n{: .note}\n",[851,1161,1287,9],{"slug":1511,"featured":6,"template":696},"gitlab-com-container-registry-cdn-change","content:en-us:blog:gitlab-com-container-registry-cdn-change.yml","Gitlab Com Container Registry Cdn Change","en-us/blog/gitlab-com-container-registry-cdn-change.yml","en-us/blog/gitlab-com-container-registry-cdn-change",{"_path":1517,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1518,"content":1523,"config":1529,"_id":1531,"_type":13,"title":1532,"_source":15,"_file":1533,"_stem":1534,"_extension":18},"/en-us/blog/gitlab-com-container-registry-update",{"title":1519,"description":1520,"ogTitle":1519,"ogDescription":1520,"noIndex":6,"ogImage":754,"ogUrl":1521,"ogSiteName":683,"ogType":684,"canonicalUrls":1521,"schema":1522},"Announcing an exciting update to the GitLab.com Container Registry","A new version of our Container Registry is coming with improvements we're excited about. Here's what you need to know.","https://about.gitlab.com/blog/gitlab-com-container-registry-update","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Announcing an exciting update to the GitLab.com Container Registry\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Rizzi\"}],\n        \"datePublished\": \"2021-10-25\",\n      }",{"title":1519,"description":1520,"authors":1524,"heroImage":754,"date":1526,"body":1527,"category":763,"tags":1528},[1525],"Tim Rizzi","2021-10-25","\n\nIn the coming weeks, we are planning to roll out a new version of the Container Registry on GitLab.com. Prior to deploying this major update, we wanted to clearly communicate the planned changes, what to expect, and why we are excited about this update. \n\nIf you have any questions or concerns, please don’t hesitate to comment in the [epic](https://gitlab.com/groups/gitlab-org/-/epics/5523). \n\n## Context \n\nIn [milestone 8.8](/releases/2016/05/22/gitlab-8-8-released/), GitLab launched the MVC of the Container Registry. This feature integrated the Docker Distribution registry into GitLab so that any GitLab user could have a space to publish and share container images. \n\nBut there was an inherent limitation with Docker Distribution as all metadata associated with a given image/tag was stored in the storage backend. This made using that metadata to build API features like storage usage visibility and sorting and filtering unfeasible. With the most recent update to the Container Registry, we’ve added a new metadata database that will store all of the metadata in Postgres instead of the storage backend. This will allow us to unblock many of the features that you’ve been asking for.\n\n## Why we are excited \n\n- [Storage visibility for the container registry](https://gitlab.com/groups/gitlab-org/-/epics/7225)\n- Performance improvements for list operations when using the GitLab API and UI\n- [Redesign of the UI](https://gitlab.com/groups/gitlab-org/-/epics/3211), including\n  - [Build and commit metadata for tags built via CI](https://gitlab.com/gitlab-org/gitlab/-/issues/197996)\n  - [Search by tag name](https://gitlab.com/gitlab-org/gitlab/-/issues/255614)\n  \n## The plan \n\nWe're planning a phased migration, starting with newly-created repositories. We'll roll this out incrementally to maintain safety for those customers and provide our team with an opportunity to identify and address any concerns. \n\n## Timing \n\nWe're starting the percentage-based rollout on October 26th, 2021, with GitLab internal projects' customers with less usage, which we expect to take 4 to 6 weeks. For more information about the planned, percentage-based rollout, please refer to this [epic](https://gitlab.com/groups/gitlab-org/-/epics/6426). \n\nOnce we complete that work, we’ll switch to customers who heavily use the Container Registry for new repositories. \n\n## FAQ \n\n- You mentioned new image repositories, but what about existing image repositories? \n  - The migration of newly-created repositories is phase 1 of this project. Once complete, we have some planned development work and then will begin to schedule the migration of existing repositories. Please stay tuned or follow along in this [epic](https://gitlab.com/groups/gitlab-org/-/epics/5523) for more information. \n- Do I need to do anything?\n  - No, the process is fully automated. \n- Is there anything I can do to help? \n  - Yes! Although no action is necessary, we recommend activating the Container Registry [cleanup policies](https://docs.gitlab.com/ee/user/packages/container_registry/#cleanup-policy) for any relevant projects. This will make [phase 2](https://gitlab.com/groups/gitlab-org/-/epics/6427) of the migration much faster. \n- Is the update required? \n  - Yes. This change will allow us to deliver a more modern and scalable product and you don’t want to miss out on those features.\n- Will there be any downtime?\n  - For phase 1 of the migration, which will focus on new image repositories, there is no expected downtime. \n- How can we learn more about phase 2? \n  - Right now we are focused on phase 1, but please feel free to ask any questions you may have in this [epic](https://gitlab.com/groups/gitlab-org/-/epics/6427).\n",[851,1161,9],{"slug":1530,"featured":6,"template":696},"gitlab-com-container-registry-update","content:en-us:blog:gitlab-com-container-registry-update.yml","Gitlab Com Container Registry Update","en-us/blog/gitlab-com-container-registry-update.yml","en-us/blog/gitlab-com-container-registry-update",{"_path":1536,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1537,"content":1543,"config":1549,"_id":1551,"_type":13,"title":1552,"_source":15,"_file":1553,"_stem":1554,"_extension":18},"/en-us/blog/gitlab-composer-packages-migration-path",{"title":1538,"description":1539,"ogTitle":1538,"ogDescription":1539,"noIndex":6,"ogImage":1540,"ogUrl":1541,"ogSiteName":683,"ogType":684,"canonicalUrls":1541,"schema":1542},"Migrate composer packages to GitLab","GitLab Packages now ships with a composer registry","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681586/Blog/Hero%20Images/gitlab-composer-package-migration.jpg","https://about.gitlab.com/blog/gitlab-composer-packages-migration-path","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Migrate composer packages to GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jochen Roth\"}],\n        \"datePublished\": \"2020-09-22\",\n      }",{"title":1538,"description":1539,"authors":1544,"heroImage":1540,"date":1546,"body":1547,"category":714,"tags":1548},[1545],"Jochen Roth","2020-09-22","{::options parse_block_html=\"true\" /}\n\n\n\n\n## Manage Composer Packages in Gitlab\n\n\nWith Gitlab 13.3, a repository for composer packages was introduced. This\nallows you to store and manage your private and public composer packages in\nyour Gitlab instance.\n\n\n### Create Packages\n\n\nCreating packages is only a matter of adding the composer template to your\n`.gitlab-ci.yml`. Gitlab will automatically create a package when a git tag\nwas created or a commit was pushed to a branch.\n\n\n[\u003Cimg src=\"/images/blogimages/select-template.png\" width=\"500\"\nheight=\"auto\">](/images/blogimages/select-template.png)\n\n\n### Migrate your Packages to Gitlab\n\n\nYou might wonder how to create packages for your existing tags of each\nrepository.\n\n\nYou have 2 options:\n\n\n1. Use curl to create packages manually e.g. ```curl --data tag=1.0.0\n'https://__token__:\u003Cpersonal-access-token>@gitlab.com/api/v4/projects/\u003Cproject_id>/packages/composer'```\n\n2. Use [this\npackage](https://gitlab.com/ochorocho/gitlab-create-package-versions), which\nwill create all packages and their versions for you using the Gitlab API.\n\n\n## Conclusion\n\n\nSo far it is working pretty well. Publish and install packages works\nflawlessly. Managing permissions for a package is a breeze.\n\n\nCurrently there is only a group endpoint. I could imagine others may require\nan instance endpoint to be able to access all packages of a Gitlab instance\nusing a single endpoint/repository.\n\nFor now you have to add multiple endpoints/repositories to your\ncomposer.json for each group.\n\n\nIn my company, one group contains all shared projects and we were able\ncircumvent adding multiple endpoints/repositories.\n\n\nThere is always room for improvement. For example, the GUI should show more\n[details about the size of packages and how it was published (manually or\nvia CI)](https://gitlab.com/gitlab-org/gitlab/-/issues/254385) and [semantic\nversioning is not fully\nsupported](https://gitlab.com/gitlab-org/gitlab/-/issues/240887).\n\nIf you are interested in GitLab or Composer, both issues are great ways to\ncontribute, so that we can continue to improve this product together.\n\n\n## Resources\n\n\n* [GitLab Packages\nDocs](https://docs.gitlab.com/ee/user/packages/composer_repository/)\n\n* [Composer Docs](https://getcomposer.org/doc/)\n\n* [Migrate to Gitlab\nPackages](https://gitlab.com/ochorocho/gitlab-create-package-versions)\n",[693,872,9],{"slug":1550,"featured":6,"template":696},"gitlab-composer-packages-migration-path","content:en-us:blog:gitlab-composer-packages-migration-path.yml","Gitlab Composer Packages Migration Path","en-us/blog/gitlab-composer-packages-migration-path.yml","en-us/blog/gitlab-composer-packages-migration-path",{"_path":1556,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1557,"content":1563,"config":1570,"_id":1572,"_type":13,"title":1573,"_source":15,"_file":1574,"_stem":1575,"_extension":18},"/en-us/blog/gitlab-duo-amazon-q-transform-ideas-into-code-in-minutes",{"title":1558,"description":1559,"ogTitle":1558,"ogDescription":1559,"noIndex":6,"ogImage":1560,"ogUrl":1561,"ogSiteName":683,"ogType":684,"canonicalUrls":1561,"schema":1562},"GitLab Duo + Amazon Q: Transform ideas into code in minutes","The new GitLab Duo with Amazon Q integration analyzes your issue descriptions and automatically generates complete working code solutions, accelerating development workflows.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097127/Blog/Hero%20Images/Blog/Hero%20Images/Screenshot%202024-11-27%20at%204.55.28%E2%80%AFPM_4VVz6DgGBOvbGY8BUmd068_1750097126673.png","https://about.gitlab.com/blog/gitlab-duo-amazon-q-transform-ideas-into-code-in-minutes","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab Duo + Amazon Q: Transform ideas into code in minutes\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Cesar Saavedra\"}],\n        \"datePublished\": \"2025-04-28\",\n      }",{"title":1558,"description":1559,"authors":1564,"heroImage":1560,"date":1566,"body":1567,"category":1568,"tags":1569},[1565],"Cesar Saavedra","2025-04-28","Have you ever spent days or even weeks converting a complex issue into working code? We've all been there. You start with a solid idea and a clear set of requirements, but the path from that initial concept to deployable code can be frustratingly long. Your productivity gets bogged down in implementation details, and projects that should move quickly end up dragging on.\n\nThis is where the power of [agentic AI](https://about.gitlab.com/topics/agentic-ai/) capabilities comes in. [GitLab Duo with Amazon Q](https://about.gitlab.com/blog/gitlab-duo-with-amazon-q-agentic-ai-optimized-for-aws/), which combines the comprehensive AI-powered DevSecOps platform with the deepest set of cloud computing capabilities, is designed to dramatically accelerate your application development process, all within your familiar GitLab workflow. By streamlining your path from idea to deployment, this powerful integration can propose implementation solutions based on your issue descriptions alone – transforming what used to take days into something that happens in minutes.\n\n## How it works: From issue to working code\n\nLet's walk through how this agentic AI feature works in practice. Imagine you're a developer tasked with creating a mortgage calculator application. Here's how GitLab Duo with Amazon Q helps you get it done:\n\n1. **Create an issue with detailed requirements:** Start by creating a standard [GitLab issue](https://docs.gitlab.com/user/project/issues/). In the description, you'll provide a comprehensive list of requirements that your service needs to meet. This becomes the blueprint for your solution.\n\n2. **Invoke Amazon Q with a quick action:** Once your issue is created, simply add a comment with a quick action, “/q dev”, to invoke Amazon Q. This is where the magic begins. \n\n3. **Let AI generate your implementation:** GitLab Duo with Amazon Q analyzes the issue description you've provided and the context of your source code, then autonomously generates code that meets all your stated requirements. It doesn't stop there – it actually commits those changes in a merge request, ready for your review.\n\n![GitLab Duo  with Amazon Q activity pop-up screenshot](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097156/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097156018.png)\n\n4. **Review the generated application**: Navigate into the merge request to review the generated code. You can verify that all your requirements have been met and make any necessary adjustments.\n\n5. **Test the proposed application**: Finally, check that the application runs successfully. With minimal effort on your part, you now have working code that implements your original requirements.\n\n## Improve your development process\n\nGitLab Duo with Amazon Q completely transforms this process, including dramatically decreasing the time it takes to carry out complex developer tasks, through intelligent automation. By leveraging an agentic AI approach, you can accelerate your path from idea to deployment, freeing development teams to focus on more strategic work.\n\nWith GitLab Duo and Amazon Q, you'll develop software faster, more efficiently, and with less manual coding effort. This integration helps you:\n\n* **Save valuable development time** by automating implementation based on requirements  \n* **Maintain consistency** in code generation across your projects  \n* **Reduce the cognitive load** of translating requirements into working code  \n* **Accelerate your release cycles** by removing implementation bottlenecks  \n* **Focus your expertise** on reviewing and optimizing, rather than writing boilerplate code\n\nReady to see GitLab Duo with Amazon Q in action? Watch our demo video to discover how you can transform your development workflow today.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/jxxzNst3jpo?si=j_LQdZhUnwqoQEst\" title=\"GitLab Duo with Amazon Q demo video for dev workflow\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n> To learn more about GitLab Duo with Amazon Q visit us at an upcoming [AWS Summit in a city near you](https://about.gitlab.com/events/aws-summits/) or [reach out to your GitLab representative](https://about.gitlab.com/partners/technology-partners/aws/#form).\n\n## GitLab Duo with Amazon Q resources\n\n- [GitLab Duo with Amazon Q: Agentic AI optimized for AWS generally available](https://about.gitlab.com/blog/gitlab-duo-with-amazon-q-agentic-ai-optimized-for-aws/)\n- [GitLab and AWS partner page](https://about.gitlab.com/partners/technology-partners/aws/)\n- [GitLab Duo with Amazon Q documentation](https://docs.gitlab.com/user/duo_amazon_q/)","ai-ml",[934,1469,807,493,1019,9],{"slug":1571,"featured":90,"template":696},"gitlab-duo-amazon-q-transform-ideas-into-code-in-minutes","content:en-us:blog:gitlab-duo-amazon-q-transform-ideas-into-code-in-minutes.yml","Gitlab Duo Amazon Q Transform Ideas Into Code In Minutes","en-us/blog/gitlab-duo-amazon-q-transform-ideas-into-code-in-minutes.yml","en-us/blog/gitlab-duo-amazon-q-transform-ideas-into-code-in-minutes",{"_path":1577,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1578,"content":1584,"config":1590,"_id":1592,"_type":13,"title":1593,"_source":15,"_file":1594,"_stem":1595,"_extension":18},"/en-us/blog/gitlab-duo-with-amazon-q-devsecops-meets-agentic-ai",{"title":1579,"description":1580,"ogTitle":1579,"ogDescription":1580,"noIndex":6,"ogImage":1581,"ogUrl":1582,"ogSiteName":683,"ogType":684,"canonicalUrls":1582,"schema":1583},"GitLab Duo with Amazon Q: DevSecOps meets agentic AI","AI-powered DevSecOps enhanced with autonomous AI agents accelerates developer productivity, application modernization, and innovation.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659604/Blog/Hero%20Images/Screenshot_2024-11-27_at_4.55.28_PM.png","https://about.gitlab.com/blog/gitlab-duo-with-amazon-q-devsecops-meets-agentic-ai","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab Duo with Amazon Q: DevSecOps meets agentic AI\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Emilio Salvador\"}],\n        \"datePublished\": \"2024-12-03\",\n      }",{"title":1579,"description":1580,"authors":1585,"heroImage":1581,"date":1587,"body":1588,"category":1568,"tags":1589},[1586],"Emilio Salvador","2024-12-03","We're excited to announce GitLab Duo with Amazon Q, a joint offering that brings together GitLab's comprehensive AI-powered DevSecOps platform with Amazon Q's autonomous AI agents in a single, integrated solution.\n\nGitLab Duo with Amazon Q transforms software development by integrating powerful AI agents directly into your daily workflows. Instead of switching between multiple tools, developers can now accelerate key tasks — from feature development to code reviews — all from within GitLab's comprehensive DevSecOps platform. Amazon Q’s AI agents act as intelligent assistants, automating time-consuming tasks like generating code from requirements, creating unit tests, conducting code reviews, and modernizing Java applications. By handling these complex tasks, this joint offering helps teams focus on innovation, while maintaining security and quality standards.\n\nThis enterprise-class developer experience includes:\n* The GitLab unified platform with one single data store, which automates the building, testing, packaging, and deployment of secure code\n* GitLab Duo, enhanced with Amazon Q developer, which leverages GitLab project context to generate multi-file changes based on the task\n* Amazon Q AI agents integrated with GitLab Duo, updating issues and creating merge requests per task, with permission scoped to the project\n\n\u003Cdiv style=\"padding:56.25% 0 0 0;position:relative;\">\u003Ciframe src=\"https://player.vimeo.com/video/1033653810?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"GitLab Duo and Amazon Q\">\u003C/iframe>\u003C/div>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n## Partnership innovation: GitLab and AWS\n\nGitLab Duo with Amazon Q is the result of close collaboration between GitLab and AWS engineering teams, combining our strengths to transform software development. This partnership unites GitLab's expertise in unified DevSecOps with AWS's leadership in cloud computing, creating an innovative solution that understands how developers work.\n\nBy integrating Amazon Q's autonomous agents with GitLab's comprehensive AI-powered platform, we've built more than a technical integration. We've created an experience that makes AI-powered development feel natural and upholds the security, compliance, and reliability that enterprises require.\n\nIndustry analysts recognize the significance of this integration in advancing AI-powered software development:\n\n***\"With this joint offering, GitLab and AWS are combining their strengths to make agentic AI a reality in software development,\" said Katie Norton, Research Manager at IDC. \"GitLab Duo with Amazon Q addresses strong use cases and critical challenges that empower customers to harness the full potential of AI.\"***\n\n***\"Both developers and the organizations they work for are increasingly interested in simplified and unified experiences,\" says Rachel Stephens, senior analyst at RedMonk. \"Especially in the era of AI – when security and privacy are paramount concerns – organizations want to both harness the power of cutting edge technology while also controlling risk and minimizing disjointed software tool chains. The partnership between GitLab Duo and Amazon Q seeks to give developers the tools they need within the context of an end-to-end DevSecOps experience.\"***\n\n## 4 key customer benefits \n\nGitLab Duo with Amazon Q pairs AI-powered DevSecOps with the deepest set of cloud computing capabilities. Together, they help development teams:\n\n### 1. Streamline feature development from idea to code \n\nDevelopment teams often spend hours translating requirements into code, leading to slower delivery and inconsistent implementation. You can now invoke the GitLab Duo with Amazon Q agent by utilizing a new quick action `/q dev`, which will convert an issue description directly into merge-ready code in minutes. The agent analyzes requirements, plans the implementation, and generates a complete merge request — all while adhering to your team's development standards. Teams can iterate rapidly using feedback in comments, significantly reducing the time from idea to production.\n\n\u003Cdiv style=\"padding:56.25% 0 0 0;position:relative;\">\u003Ciframe src=\"https://player.vimeo.com/video/1034050110?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Feature Dev with Rev\">\u003C/iframe>\u003C/div>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n### 2. Modernize legacy code without the headache \n\nUpgrading Java applications traditionally requires weeks of careful planning, manual code changes, and extensive testing. By using quick action `/q transform`, you can change this by automating the entire Java modernization process. In minutes, not hours, the agent analyzes your Java 8 or 11 codebase, creates a comprehensive upgrade plan, and generates fully documented merge requests for Java 17 migration. Every change is tracked and traceable, giving teams confidence while improving application security and performance.\n\n\u003Cdiv style=\"padding:56.25% 0 0 0;position:relative;\">\u003Ciframe src=\"https://player.vimeo.com/video/1034050145?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"QCT\">\u003C/iframe>\u003C/div>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n### 3. Accelerate code reviews without sacrificing quality \n\nCode reviews often create bottlenecks: Teams wait days for feedback yet must maintain consistent standards. With the `/q review` quick action, you get instant, intelligent feedback on code quality and security directly in merge requests. By automatically identifying potential issues and suggesting improvements based on your standards, teams can maintain high-quality code while dramatically reducing review cycles.\n\n\u003Cdiv style=\"padding:56.25% 0 0 0;position:relative;\">\u003Ciframe src=\"https://player.vimeo.com/video/1034050136?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Code Reviews\">\u003C/iframe>\u003C/div>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n### 4. Automate testing to ship with confidence\n\nManual test creation is time-consuming and often leads to inconsistent coverage across teams. With the `/q test` quick action, you can automatically generate comprehensive unit tests that understand your application logic. The agent ensures thorough coverage of critical paths and edge cases, matching your existing testing patterns. This automation helps teams catch issues earlier and maintain consistent quality standards, saving valuable developer time.\n\n\u003Cdiv style=\"padding:54.37% 0 0 0;position:relative;\">\u003Ciframe src=\"https://player.vimeo.com/video/1034050181?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture; clipboard-write\" style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"Use GitLab Duo with Amazon Q to add tests\">\u003C/iframe>\u003C/div>\u003Cscript src=\"https://player.vimeo.com/api/player.js\">\u003C/script>\n\n## Enterprise-grade security and guardrails included\n\nBuilt for enterprise scale and security, this offering combines GitLab's integrated security, compliance, and privacy with Amazon Q's AI agent, accelerating developer workflows to help organizations ship secure software faster.\n\nThe integration features:\n\n* Built-in guardrails that maintain development velocity  \n* Granular controls for AI-powered features at user, project, and group levels  \n* End-to-end security integration with existing workflows\n\nDevSecOps teams can securely scale the development environment with the world's most broadly adopted cloud.\n\n## What's next\n\nGitLab Duo with Amazon Q builds on our existing integration with [AWS announced in May 2024](https://press.aboutamazon.com/2024/4/aws-announces-general-availability-of-amazon-q-the-most-capable-generative-ai-powered-assistant-for-accelerating-software-development-and-leveraging-companies-internal-data), representing a significant step forward in our joint mission to transform software development. This deeper integration of AI capabilities marks the beginning of our expanded collaboration with AWS. As we continue to evolve these capabilities, we'll focus on:\n\n* Extending AI features across the development lifecycle  \n* Enhancing developer productivity  \n* Meeting enterprise development demands at scale\n\n**GitLab Duo with Amazon Q is available today on a [public branch](https://gitlab.com/groups/gitlab-org/-/epics/16059) in the GitLab.org project. To get access to a preview and learn more about how it can transform your software development process, visit [our website](https://about.gitlab.com/partners/technology-partners/aws/#interest).**",[763,1469,934,493,9],{"slug":1591,"featured":90,"template":696},"gitlab-duo-with-amazon-q-devsecops-meets-agentic-ai","content:en-us:blog:gitlab-duo-with-amazon-q-devsecops-meets-agentic-ai.yml","Gitlab Duo With Amazon Q Devsecops Meets Agentic Ai","en-us/blog/gitlab-duo-with-amazon-q-devsecops-meets-agentic-ai.yml","en-us/blog/gitlab-duo-with-amazon-q-devsecops-meets-agentic-ai",{"_path":1597,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1598,"content":1604,"config":1610,"_id":1612,"_type":13,"title":1613,"_source":15,"_file":1614,"_stem":1615,"_extension":18},"/en-us/blog/gitlab-gke-autopilot",{"title":1599,"description":1600,"ogTitle":1599,"ogDescription":1600,"noIndex":6,"ogImage":1601,"ogUrl":1602,"ogSiteName":683,"ogType":684,"canonicalUrls":1602,"schema":1603},"How to use GitLab with GKE Autopilot","GitLab works out of the box with the new GKE Autopilot from Google Cloud, a managed variant of the popular Google Kubernetes Engine.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681920/Blog/Hero%20Images/kubernetes.png","https://about.gitlab.com/blog/gitlab-gke-autopilot","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to use GitLab with GKE Autopilot\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Abubakar Siddiq Ango\"}],\n        \"datePublished\": \"2021-02-24\",\n      }",{"title":1599,"description":1600,"authors":1605,"heroImage":1601,"date":1607,"body":1608,"category":763,"tags":1609},[1606],"Abubakar Siddiq Ango","2021-02-24","\n\nIn the cloud native landscape, there are dozens of providers that offer managed Kubernetes services. Despite the abstraction, and ease of use promised, a major problem remains: getting the node size right. You want it to match your workloads so that you don’t under-provision – making the workloads unstable – or over-provision and rake in unnecessary costs. \n\n[GKE Autopilot from Google Cloud](https://cloud.google.com/blog/products/containers-kubernetes/introducing-gke-autopilot) solves this problem by enabling your team to focus on building your solutions with a fully managed and opinionated variant of Google Kubernetes Engine (GKE), where nodes are automatically provisioned based on your workload requirements and with no need to be managed independently. \n\nGKE Autopilot uses the resource specification in the PodSpec of your deployment to provision nodes or use defaults, automatically resize the nodes, or provision new nodes as the pods’ needs change. GitLab and Google Cloud officially support several use cases, including running GitLab and GitLab Runners as workloads on GKE Autopilot clusters, as well as using GitLab CI/CD to deploy applications onto GKE Autopilot.\n\n## GitLab and GKE Autopilot\n\n### GitLab Server\n\nGitLab can be installed on GKE Autopilot easily out of the box using the official Helm Charts and can be configured to match your company’s use case, such as external object storage and database. GKE Autopilot works to ensure the right sizes and number of nodes are provisioned based on the requirements specified in the GitLab charts and your customizations. You can access other resources in Google Cloud, such as storage and databases using Google Cloud Workload Identity.\n\nAll GKE Autopilot clusters come with Google Cloud Workload Identity pre-configured. Workload Identity allows you to bind Kubernetes Service Accounts to Google Service Accounts, with whatever permission that Google Service Account has. This can include resources in other Google Cloud platform projects.\n\nIn the first part of the GitLab with GKE Autopilot demo, I demonstrate how to install GitLab on a GKE Autopilot cluster:\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/cNffh-qyXhQ\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n### GitLab Runner\n\nThe GitLab Runner can be deployed on GKE Autopilot in unprivileged mode, allowing it to only run GitLab CI jobs that do not require privileged pods or Docker in Docker due to the lack of support for privileged pods on GKE Autopilot. To build container images, [Kaniko](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html) or its likes can be used as an alternative to Docker. This applies to the bundled runner in the official GitLab Helm chart or when deployed independently using the official GitLab Runner chart. This also affects jobs using GitLab Auto DevOps, but works best when an independent Runner (set up on a GKE Standard cluster or virtual machine) is registered with the GitLab server running on GKE Autopilot.\n\n### Integrating GKE Autopilot clusters\n\nGKE Autopilot clusters integrate with GitLab just like a GKE Standard cluster. There are two options, the preferred of which is to use the [GitLab Agent for Kubernetes](/blog/gitlab-kubernetes-agent-on-gitlab-com/), especially if you are concerned about security or your cluster is behind a firewall. You can learn more about this in our [detailed documentation](https://docs.gitlab.com/ee/user/clusters/agent/).\nAlternatively, you can create a cluster-admin and provide the cluster certificate and token to [integrate with the cluster](https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html).  As of the time of writing, GKE Autopilot clusters cannot be created from GitLab like standard GKE clusters. The DinD limitation also affects the runner listed in the GitLab-managed apps that you can install as part of the integration. \n\nIn the second part of the demo video, I demonstrate how to integrate GitLab with a GKE Autopilot cluster and deploy an application using Auto DevOps.\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/rCwHL3hQEWU\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n## Considerations\n\nGKE Autopilot is opinionated and less configurable than GKE Standard. As a managed service, it allows you to focus on delivering the best solutions to your users and not worry about operations; these are limitations common for such managed Kubernetes services. \n\nAdministrative access to the nodes provisioned by GKE Autopilot is not supported, thus making any operation requiring access to the nodes limited. Host options, node selectors, node affinity/anti-affinity, taints, and tolerations are other functionalities that apply at the node level in GKE Standard but are not supported in Autopilot.\n\nWhen integrating an Autopilot cluster with GitLab, you cannot install the bundled cert-manager. I encountered an error while testing, stating that `mutatingwebhookconfigurations/` is managed and access is denied in GKE Autopilot. Alternatively, you can follow the directions provided in the official cert-manager documentation.\n\n## Wrapping up\n\nGKE Autopilot is designed to implement Google Cloud-developed best practices and has been fine-tuned to provide an ideal user experience. You can move from idea to production and scale worry-free when you integrate GitLab with GKE Autopilot, allowing you to deploy and monitor your application’s health, all within GitLab. If you also choose to deploy GitLab itself on GKE Autopilot, our official Helm chart will work out of the box.\n",[1040,1447,741,9],{"slug":1611,"featured":6,"template":696},"gitlab-gke-autopilot","content:en-us:blog:gitlab-gke-autopilot.yml","Gitlab Gke Autopilot","en-us/blog/gitlab-gke-autopilot.yml","en-us/blog/gitlab-gke-autopilot",{"_path":1617,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1618,"content":1624,"config":1630,"_id":1632,"_type":13,"title":1633,"_source":15,"_file":1634,"_stem":1635,"_extension":18},"/en-us/blog/gitlab-google-cloud-integrations-now-in-public-beta",{"title":1619,"description":1620,"ogTitle":1619,"ogDescription":1620,"noIndex":6,"ogImage":1621,"ogUrl":1622,"ogSiteName":683,"ogType":684,"canonicalUrls":1622,"schema":1623},"GitLab-Google Cloud integrations now in public beta","The multiple integrations streamline authentication, automate CI/CD, and reduce context switching across GitLab and Google Cloud.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663121/Blog/Hero%20Images/LogoLockupPlusLight.png","https://about.gitlab.com/blog/gitlab-google-cloud-integrations-now-in-public-beta","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab-Google Cloud integrations now in public beta\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jackie Porter\"}],\n        \"datePublished\": \"2024-04-09\",\n      }",{"title":1619,"description":1620,"authors":1625,"heroImage":1621,"date":1627,"body":1628,"category":763,"tags":1629},[1626],"Jackie Porter","2024-04-09","In 2023, we announced our plan [to integrate GitLab with Google Cloud](https://about.gitlab.com/blog/gitlab-google-partnership-s3c/). This week, at Google Cloud Next '24, we are announcing that our first integrations from that partnership are now in public beta. \n\nThese critical integrations streamline authentication, automate CI/CD, and decrease context switching across GitLab and Google Cloud, reducing the friction involved in using the two and improving the overall developer experience by helping them focus on deploying code, and not setting up infrastructure. GitLab users can learn [how to set up the GitLab-Google Cloud integrations](https://docs.gitlab.com/ee/tutorials/set_up_gitlab_google_integration/).\n\n## Streamline authentication\n\nWhen organizations want to use GitLab and Google Cloud together, they typically need to use a service account key to access Google Cloud resources from GitLab. This approach can present an unnecessary security risk and add additional maintenance burden.\n\nWith the new GitLab-Google Cloud integration, GitLab customers can use industry-standard methods identity and access management ([IAM](https://cloud.google.com/security/products/iam)) and Workload Identity Federation ([WLIF](https://cloud.google.com/iam/docs/workload-identity-federation)) for authentication. This replaces the need for cross-system service accounts, decreasing the risk associated with service account keys, and minimizing management overhead for rotating keys. To learn more about setting up IAM and WLIF, read our [documentation](https://docs.gitlab.com/ee/integration/google_cloud_iam.html).\n\nWe also added a method to streamline authentication from CI/CD pipelines using a developer-minded approach with a new identity keyword. Learn more in the [identity keyword documentation](https://docs.gitlab.com/ee/ci/yaml/#identity).\n\n## Automate CI/CD\n\nA primary objective of the GitLab-Google Cloud partnership is to help organizations deploy applications to Google Cloud faster. With this in mind, we have built two mechanisms to support that: runner configuration automation and a library of Google Cloud Services components.\n\nRunners are the backbone of all CI/CD jobs, but installing, managing, and updating them can be time-consuming and inefficient. GitLab offers [runners](https://docs.gitlab.com/ee/ci/runners/) built on infrastructure as code (IaC) best practices, which means we provision and manage runners for you, including deleting them once they’ve done their job. With our runner configuration automation for Google Cloud, our hosted runners are now available to users on Google Cloud, without needing to leave GitLab.\nCheck out our [setup documentation](https://docs.gitlab.com/ee/tutorials/set_up_gitlab_google_integration/#set-up-gitlab-runner-to-execute-your-cicd-jobs-on-google-cloud) to learn more.\n\nWe’ve also worked with Google Cloud to provide a [library of Google components in GitLab’s CI/CD Catalog](https://gitlab.com/google-gitlab-components). These components make it easy to configure your pipelines to deploy to Google Cloud Services, including Google Kubernetes Engine, Artifact Registry, and Cloud Deploy. Rather than search the web for the right YAML configurations, simply browse the CI/CD Catalog within GitLab and import the component configuration into your pipeline’s .yml file.\n\n![gitlab-google image 1](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749677557/Blog/Content%20Images/Screenshot_2024-04-09_at_11.43.27_AM.png)\n\n> Learn more about [how to use Google Cloud Components](https://docs.gitlab.com/ee/tutorials/set_up_gitlab_google_integration/#deploy-to-google-cloud-with-cicd-components).\n\n## Reduce context switching\n\nGitLab and Google Cloud together create a single data plane for all your software development needs, from source code management to deployment. This means full visibility into your product performance metrics, security and compliance policies, and insights to empower you to optimize your software delivery process – all without having to context switch between multiple systems. For users of Google Cloud and GitLab, this is a game changer.\n\nOur guiding principles throughout this integration plan were developer experience and efficiency. As an example, check out this demo showing how simple it is to integrate GitLab with Google Cloud Artifact Registry.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/CcPl3k3IHjM?si=XNfGnK9Qlx7XxD3v\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n## What’s next?\n\nWe are now in beta and welcome your feedback. To begin using the Google Cloud integrations, follow the steps in this [tutorial](https://docs.gitlab.com/ee/tutorials/set_up_gitlab_google_integration/).",[741,9,763],{"slug":1631,"featured":90,"template":696},"gitlab-google-cloud-integrations-now-in-public-beta","content:en-us:blog:gitlab-google-cloud-integrations-now-in-public-beta.yml","Gitlab Google Cloud Integrations Now In Public Beta","en-us/blog/gitlab-google-cloud-integrations-now-in-public-beta.yml","en-us/blog/gitlab-google-cloud-integrations-now-in-public-beta",{"_path":1637,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1638,"content":1644,"config":1649,"_id":1651,"_type":13,"title":1652,"_source":15,"_file":1653,"_stem":1654,"_extension":18},"/en-us/blog/gitlab-google-partnership-s3c",{"title":1639,"description":1640,"ogTitle":1639,"ogDescription":1640,"noIndex":6,"ogImage":1641,"ogUrl":1642,"ogSiteName":683,"ogType":684,"canonicalUrls":1642,"schema":1643},"Better together with GitLab and Google Cloud","GitLab’s DevSecOps workflow now integrates with Google Cloud secure Artifact Registry, security scanning, and deployment toolchains.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679290/Blog/Hero%20Images/gitlabgooglecloud.png","https://about.gitlab.com/blog/gitlab-google-partnership-s3c","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Better together with GitLab and Google Cloud\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jackie Porter\"}],\n        \"datePublished\": \"2023-08-29\",\n      }",{"title":1639,"description":1640,"authors":1645,"heroImage":1641,"date":1646,"body":1647,"category":763,"tags":1648},[1626],"2023-08-29","\nToday, we are pleased to announce that Google Cloud and GitLab are partnering to integrate GitLab's unique capabilities with Google Cloud. This partnership will combine GitLab's source code management, planning, CI/CD workflow, advanced security, and compliance capabilities with the unified data plane in Google’s Cloud console and Artifact Registry.\n\nWe continually hear developers are frustrated with the increased complexity and security risk of having multiple point solutions in their DevSecOps toolchain. Our new integration will bring multiple tools together to allow them to be fully managed and cloud-hosted.  The integration relieves operators of the duties typically associated with a self-hosted solution, such as applying patches and upgrades and then testing them to make sure things continue to work as expected. Developers will love that they are able to reduce the number of tools and cognitive load needed to develop and ship software faster, with security included from the start.\n\n> Sign up for the Google Software Supply Chain Security and GitLab DevSecOps [integration waitlist](https://page.gitlab.com/interest-gitlab-and-google-security-solution-contact-request.html).\n\n## Powering the DevSecOps lifecycle with scale and visibility \nGoogle’s Software Supply Chain Security pairs with GitLab’s DevSecOps platform to provide system-wide governance and policy enforcement throughout the software development lifecycle. \n\n![Diagram](https://about.gitlab.com/images/blogimages/2023-08-29-gitlab-google-partnership/s3cimage1.png){: .shadow}\n\nThe joint solution replaces a myriad of point solutions that are difficult to manage, maintain, and upgrade. The integration will enable customers to better leverage the benefits of GitLab’s unified DevSecOps workflow with native supply chain security capabilities from Google Cloud. \n\n## Seamless connections for security \nEven before a developer writes any code, they will be able to easily access their GitLab project from the Google Cloud Console. Teams will be able to plan, create issues, and define epics all within GitLab, ensuring security is integrated from the start. \n\nWhen code is ready to be pushed to production, the integration will enable easy registration and configuration of private Google Cloud-powered runners from within GitLab, then utilize CI/CD component templates for deploying to various Google Cloud resources like Google Kubernetes Engine (GKE) and Cloud Run.\n\nOne of the most exciting things for our customers' connected experience will be the ability to use Google’s Artifact Registry with GitLab’s pipelines and packaging to create a security data plane. In this view of the Google Artifact Registry, developers will be able to see a consolidation of security scanning results and the metadata from vulnerability reports in GitLab. A great example of how users will benefit is from having a SLSA-rated provenance telling users where and how software was built, a software bill of materials (SBOM) which provides transparency regarding the content of the software artifacts, and vulnerability impact information gated with Google’s Binary Authorization policies. Outputs from GitLab can be confirmed via attestation and signature such that packages can be prevented from running on a cluster if they do not satisfy the security or verification requirements. \n\n![Artifacts](https://about.gitlab.com/images/blogimages/2023-08-29-gitlab-google-partnership/s3cimage2.png){: .shadow}\n\n\"We are excited to expand our partnership with GitLab to provide our customers end-to-end software supply chain security that is easier and more accessible than ever before,” said Gabe Monroy, VP of Developer Experience at Google Cloud. “I am looking forward to more joint innovation with GitLab in the DevSecOps space with the goal of helping our customers deliver software more rapidly and with greater confidence.\"\n\n## Join our early access program \nWe are excited about how this collaboration will help Google Cloud and GitLab customers ship better, more secure, software faster. To join our early access program, sign up for the [waitlist](https://page.gitlab.com/interest-gitlab-and-google-security-solution-contact-request.html)! \n\n",[763,741,9],{"slug":1650,"featured":6,"template":696},"gitlab-google-partnership-s3c","content:en-us:blog:gitlab-google-partnership-s3c.yml","Gitlab Google Partnership S3c","en-us/blog/gitlab-google-partnership-s3c.yml","en-us/blog/gitlab-google-partnership-s3c",{"_path":1656,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1657,"content":1663,"config":1672,"_id":1674,"_type":13,"title":1675,"_source":15,"_file":1676,"_stem":1677,"_extension":18},"/en-us/blog/gitlab-hashicorp-terraform-vault-pt-1",{"title":1658,"description":1659,"ogTitle":1658,"ogDescription":1659,"noIndex":6,"ogImage":1660,"ogUrl":1661,"ogSiteName":683,"ogType":684,"canonicalUrls":1661,"schema":1662},"GitLab and HashiCorp streamline delivery workflows","Discover how to leverage CI/CD for your infrastructure scripts with Terraform and GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670238/Blog/Hero%20Images/gitlab-terraform-pipelines.jpg","https://about.gitlab.com/blog/gitlab-hashicorp-terraform-vault-pt-1","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab and HashiCorp: Providing application and infrastructure delivery workflows\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Kelly Hair\"},{\"@type\":\"Person\",\"name\":\"Anthony Davanzo\"}],\n        \"datePublished\": \"2019-09-17\",\n      }",{"title":1664,"description":1659,"authors":1665,"heroImage":1660,"date":1668,"body":1669,"category":848,"tags":1670},"GitLab and HashiCorp: Providing application and infrastructure delivery workflows",[1666,1667],"Kelly Hair","Anthony Davanzo","2019-09-17","\nA growing number of teams are becoming more and more invested in continually improving the business through iterative development. Adopting the culture of DevOps isn’t necessarily confined to software development itself, but is equally applicable to ITOps, System Admins, and other infrastructure teams as well. Just as a proper CI/CD workflow is the foundation of today’s application delivery, a similar automated workflow is essential for managing the delivery of infrastructure as well.\n\nAs developers try to become more agile in building, packing, and testing their applications, having the right CI/CD tool that is flexible to other automation use cases is critical. GitLab has gone into great detail about their [flexible CI/CD capabilities here](https://docs.gitlab.com/ee/ci/introduction/index.html#how-gitlab-cicd-works). What’s sometimes overlooked is implementing the proper CI/CD process for the underlying infrastructure that these applications rely on. In addition to application delivery, organizations need to consider what their infrastructure delivery process looks like. GitLab and HashiCorp have partnered to create a multi-blog series on how to combine the application delivery workflow with the infrastructure delivery workflow. In this part we will discuss a high-level overview of the solutions that we will dive deeper into in Part 2.\n\n## Leveraging HashiCorp Terraform for CI/CD Pipelines\n\n[HashiCorp Terraform](https://www.terraform.io/) is an open source tool for provisioning infrastructure as code. Users define infrastructure in HashiCorp Configuration Language (HCL) configuration files, Terraform reads those configurations, offers a speculative plan of what it will create, and then users confirm and apply those changes. Terraform keeps track of what infrastructure is provisioned in a state file.\n\nThe recently announced Terraform Cloud application provides users with additional automation and collaboration capabilities on top of Terraform, such as remotely managing and version that state file, executing Terraform runs (plan/apply) remotely, and allowing teams to comment and collaborate on Terraform. By remotely managing state files, Terraform Cloud empowers teams to work more quickly and safely in parallel without concerns of losing the file or overwriting each other's changes. These features are especially helpful for users implementing CI/CD pipelines because they allow users to interact with Terraform via webhooks/API instead of having Terraform run on a local machine.\n\nMost users will store their configuration files in a VCS (Version Control System) like GitLab and connect that VCS to Terraform Cloud. That connection allows users to borrow best practices from software engineering to version and iterate on infrastructure as code, using VCS and Terraform Cloud as a provisioning pipeline for infrastructure. Terraform will automatically run a plan upon changes to configuration files in a VCS. This plan can be reviewed by the team for safety and accuracy in the Terraform UI, then it can be applied to provision the specified infrastructure. Terraform Cloud can also be configured to automatically apply those changes.\n\nTerraform Cloud also includes a Governance upgrade, which provides access to the [Sentinel](https://www.hashicorp.com/sentinel) policy as code framework.  This framework allows users to define fine-grain rules and policies for their infrastructure that are automatically enforced before that infrastructure is provisioned. This allows users to work with the speed and efficiency they want in their continuous integration/delivery pipelines, while still ensuring that best practices are being implemented.\n\n### Future iterations\n\nIt is also worth discussing current work in progress with GitLab and Vault. Vault from Hashicorp secures, stores, and tightly controls access to tokens, passwords, certificates, API keys, and other secrets that services depend on. In efforts to improve [Variables and secrets management in GitLab CI/CD](https://gitlab.com/groups/gitlab-org/-/epics/816) we’re working with HashiCorp to provide a [first-class integration with Vault](https://gitlab.com/gitlab-org/gitlab-ce/issues/61053) sometime in the future.\n\n## Next steps\n\nAs a follow up, we will soon be posting a blog on the technical details of _how_ to build a Terraform pipeline in GitLab CI/CD.\n\nIn meantime, check out how [WagLabs reduced their release process from 40 minutes to just six](/blog/wag-labs-blog-post/), using Terraform and GitLab CI/CD!\n\n### About the authors\n\n_[Anthony Davanzo](https://www.linkedin.com/in/anthonydavanzo/) is the product marketing manager for Terraform Cloud at HashiCorp. In this role he focuses on bringing Terraform Cloud to market, hoping to drive adoption and spread awareness of the tool. His prior role as the technical product marketing manager for Terraform helps with deep domain knowledge and before HashiCorp, he was a product marketing manager at Cloudflare._\n\n_[Kelly Hair](/company/team/#khair1) is a solutions architect at GitLab._\n\nPhoto by [Saad Salim](https://unsplash.com/@saadx?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n{: .note}\n",[108,850,851,9,1671],"frontend",{"slug":1673,"featured":6,"template":696},"gitlab-hashicorp-terraform-vault-pt-1","content:en-us:blog:gitlab-hashicorp-terraform-vault-pt-1.yml","Gitlab Hashicorp Terraform Vault Pt 1","en-us/blog/gitlab-hashicorp-terraform-vault-pt-1.yml","en-us/blog/gitlab-hashicorp-terraform-vault-pt-1",{"_path":1679,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1680,"content":1686,"config":1691,"_id":1693,"_type":13,"title":1694,"_source":15,"_file":1695,"_stem":1696,"_extension":18},"/en-us/blog/gitlab-is-now-available-as-an-aws-codestar-connections-provider",{"title":1681,"description":1682,"ogTitle":1681,"ogDescription":1682,"noIndex":6,"ogImage":1683,"ogUrl":1684,"ogSiteName":683,"ogType":684,"canonicalUrls":1684,"schema":1685},"GitLab is now available as an AWS CodeStar Connections provider","AWS released native CodePipeline integration for GitLab projects and repos, helping to ensure a best-in-class experience when using GitLab and AWS together.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098884/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_397632156_3Ldy1urjMStQCl4qnOBvE0_1750098884409.jpg","https://about.gitlab.com/blog/gitlab-is-now-available-as-an-aws-codestar-connections-provider","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab is now available as an AWS CodeStar Connections provider\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Darwin Sanoy\"}],\n        \"datePublished\": \"2024-01-11\",\n      }",{"title":1681,"description":1682,"authors":1687,"heroImage":1683,"date":1688,"body":1689,"category":1244,"tags":1690},[1465],"2024-01-11","The GitLab DevSecOps Platform now integrates natively with many AWS services through AWS CodeStar Connections and AWS CodePipeline. This long-awaited integration was recently completed by the AWS CodeSuite service team for GitLab.com SaaS, GitLab Self-Managed, and GitLab Dedicated. AWS CodeStar Connections is a utility layer, which means other AWS services can enable native GitLab integration with less work.\n\nOnce created, CodeStar Connections objects can be used directly to integrate with many AWS services such as:\n- AWS CodePipeline,\n- Amazon CodeWhisperer Customization Capability,\n- AWS Service Catalog\n- AWS Glue\n\nWhen a CodeStar Connection is used to configure a GitLab CodePipeline configuration it can further support:\n- AWS CodeBuild\n- Amazon SageMaker MLOps Projects\n- AWS CodeDeploy\n\nGitLab and AWS have been working at ever deeper levels of technical and business integration to ensure that our co-customers have a best-in-class experience when using GitLab and AWS together.\n\n![AWS CodeStar integration](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098901/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750098900704.png)\n\nCheck out the complete list of AWS Services that are now directly accessible in the [GitLab AWS Integration Index documentation](https://docs.gitlab.com/ee/solutions/cloud/aws/gitlab_aws_integration.html).\n\n![CodeStar - New Technology and Solutions for using GitLab and AWS Together ](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098901/Blog/Content%20Images/Blog/Content%20Images/AWS_re_Invent_2023__New_Technology_and_Solutions_for_using_GitLab_and_AWS_Together__4__aHR0cHM6_1750098900705.png)\n\n## Resources\n\n- GitLab [AWS Integration Index documentation](https://docs.gitlab.com/ee/solutions/cloud/aws/gitlab_aws_integration.html) is a one-stop location for these new integrations as well as existing integrations\n- AWS documentation for [setting up CodeStar Connections with GitLab.com SaaS](https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-gitlab-managed.html)\n- AWS documentation for [setting up CodeStar Connections with self-managed GitLab](https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-gitlab-managed.html)\n - AWS documentation for [configuring AWS CodePipeline integration](https://docs.gitlab.com/ee/user/project/integrations/aws_codepipeline.html)\n- [AWS announcement for GitLab CodePipeline Integration for GitLab SaaS](https://aws.amazon.com/about-aws/whats-new/2023/08/aws-codepipeline-supports-gitlab/) and [AWS announcement for GitLab Self-Managed](https://aws.amazon.com/about-aws/whats-new/2023/12/codepipeline-gitlab-self-managed/)\n\n![codestar-amazonpartnerlogo](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098901/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750098900705.png)\n",[1469,108,281,9],{"slug":1692,"featured":6,"template":696},"gitlab-is-now-available-as-an-aws-codestar-connections-provider","content:en-us:blog:gitlab-is-now-available-as-an-aws-codestar-connections-provider.yml","Gitlab Is Now Available As An Aws Codestar Connections Provider","en-us/blog/gitlab-is-now-available-as-an-aws-codestar-connections-provider.yml","en-us/blog/gitlab-is-now-available-as-an-aws-codestar-connections-provider",{"_path":1698,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1699,"content":1705,"config":1711,"_id":1713,"_type":13,"title":1714,"_source":15,"_file":1715,"_stem":1716,"_extension":18},"/en-us/blog/gitlab-merge-requests-in-tower",{"title":1700,"description":1701,"ogTitle":1700,"ogDescription":1701,"noIndex":6,"ogImage":1702,"ogUrl":1703,"ogSiteName":683,"ogType":684,"canonicalUrls":1703,"schema":1704},"Merge requests are coming to your desktop with Tower","GitLab users can now work with merge requests right from their desktops. A new version of Tower brings native support for all self-managed versions of GitLab and GitLab.com.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680144/Blog/Hero%20Images/gitlab-merge-requests-in-tower.png","https://about.gitlab.com/blog/gitlab-merge-requests-in-tower","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Merge requests are coming to your desktop with Tower\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tobias Günther\"}],\n        \"datePublished\": \"2018-04-18\",\n      }",{"title":1700,"description":1701,"authors":1706,"heroImage":1702,"date":1708,"body":1709,"category":298,"tags":1710},[1707],"Tobias Günther","2018-04-18","\n\nThe concept of \"[merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/)\" has changed the way we work – by redefining the way we _collaborate_. Although it's a relatively new tool, it's already hard to think back to how we worked without them.\n\nVery recently, they have even burst out of the browser and are now, finally, accessible right on your desktop: the upcoming new major version of [Tower, a Git desktop client for Mac and Windows](https://www.git-tower.com/public-beta-2018), brings native support for GitLab merge requests!\n\nThis means that working with merge requests has become even more comfortable and easy: the most common tasks can now be performed directly from your desktop! You can create, merge, comment, inspect, and close merge requests in Tower. And, since you can of course work on your MRs in Tower _and_ in the browser side by side, we've included a quick link so you can access the browser version with just a click.\n\nAt the moment, you can use the _new_ Tower for free during our Public Beta. Simply [sign up on our beta page](https://www.git-tower.com/public-beta-2018) and give it a try. You'll see that we've worked very hard to make GitLab merge requests feel at home in Tower.\n\n### Check out how the integration works in the demo below:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/AXAyloYrgx4\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nAnd please let us know if you have [feedback for us](https://www.git-tower.com/support/contact): we're eager to help GitLab users become even more productive through Tower!\n\n## About the guest author\n\nTobias Günther is the founder and CEO of [Tower, the popular Git client for Mac and Windows](https://www.git-tower.com/).\n",[9],{"slug":1712,"featured":6,"template":696},"gitlab-merge-requests-in-tower","content:en-us:blog:gitlab-merge-requests-in-tower.yml","Gitlab Merge Requests In Tower","en-us/blog/gitlab-merge-requests-in-tower.yml","en-us/blog/gitlab-merge-requests-in-tower",{"_path":1718,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1719,"content":1725,"config":1732,"_id":1734,"_type":13,"title":1735,"_source":15,"_file":1736,"_stem":1737,"_extension":18},"/en-us/blog/gitlab-on-vmware-cloud-marketplace",{"title":1720,"description":1721,"ogTitle":1720,"ogDescription":1721,"noIndex":6,"ogImage":1722,"ogUrl":1723,"ogSiteName":683,"ogType":684,"canonicalUrls":1723,"schema":1724},"GitLab for Cloud Native Transformation on VMware Marketplace","Guest authors from VMware share how to accelerate your software delivery process in just a few clicks with Bitnami and GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680841/Blog/Hero%20Images/bitnami-gitlab.png","https://about.gitlab.com/blog/gitlab-on-vmware-cloud-marketplace","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab Enterprise Edition now available for VMware Cloud Marketplace users\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Raquel Campuzano\"}],\n        \"datePublished\": \"2019-10-11\",\n      }",{"title":1726,"description":1721,"authors":1727,"heroImage":1722,"date":1729,"body":1730,"category":298,"tags":1731},"GitLab Enterprise Edition now available for VMware Cloud Marketplace users",[1728],"Raquel Campuzano","2019-10-11","\n\nHave you ever tried to choose from an extensive list of developer tools and wondered what you should do next? You’re not alone. There are hundreds of solutions to choose from, which can make it challenging to select the right solution and deploy.\n\nNow, GitLab and Bitnami have partnered to offer VMware users [GitLab](https://marketplace.cloud.vmware.com/services/details/129dc4e9-191d-405f-ab4d-803d56f366a9) in the VMware Cloud Marketplace. This version package is free, fully functional, and easy to [upgrade to an enterprise plan](https://docs.bitnami.com/vmware-marketplace/apps/gitlab-ee/get-started/license/).\n\n### Reduce costs and avoid security risks\nAs the industry leader in application packaging, Bitnami helped GitLab create an easy, click-to-deploy, open source solution. The GitLab Enterprise Edition (CORE) Virtual Appliance certified by Bitnami is an up-to-date and secure image that includes the latest versions of the application, its components, and the most recent security fixes. You can run GitLab with confidence; Bitnami’s automated pipeline and tools for building and testing applications ensure this application can run on any platform without issues. If you experience any problems deploying the solution, you can contact the [Bitnami Support team](https://community.bitnami.com/c/gitlab) with your questions.\n\n### Run on VMware infrastructure in a few clicks\nTo make GitLab available in the [VMware Cloud Marketplace](https://marketplace.cloud.vmware.com/services/details/129dc4e9-191d-405f-ab4d-803d56f366a9), GitLab placed its trust in Bitnami’s expertise in packaging. GitLab users now have the ability to run the latest version on their VMware infrastructure in a few clicks.\n\n### Some of the key benefits of GitLab's marketplace listing:\n* GitLab includes a built-in container registry and Kubernetes integration, enabling you to quickly create a [continuous integration (CI)](/solutions/continuous-integration/) pipeline with Kubernetes. Learn more about [creating a CI/CD pipeline with GitLab and Kubernetes](https://docs.bitnami.com/tutorials/create-ci-cd-pipeline-gitlab-kubernetes/).\n* By deploying GitLab on a VMware cloud server, you can add a budget- and resource-checking stage to your pipeline. This allows you to implement best practices into your continuous deployment (CD) process and control the consumption and costs of your application deployments.\n* Premium features such as code quality and performance testing, static and dynamic application security testing, package dependency analysis, and automated tests for vulnerabilities enable you to identify and remediate issues and security breaches from development to monitoring stages. Learn more about [building misconfiguration and vulnerability checks into your CI/CD pipeline to achieve continuous security](https://thenewstack.io/how-continuous-security-can-solve-the-cloud-protection-conundrum/).\n\n### How do you get started? We’ll show you how\nIn order to upgrade your GitLab Core version to enjoy the Enterprise Edition features, take the following steps:\n\n1) First log into the [VMware Cloud Marketplace](https://marketplace.cloud.vmware.com/services/details/129dc4e9-191d-405f-ab4d-803d56f366a9) and browse for the “GitLab Enterprise (CORE) Virtual Appliance” solution.\n\n2) Then click to view the details. Note: The GitLab Enterprise (CORE) Virtual Appliance is available in the [VMware Cloud Marketplace](https://marketplace.cloud.vmware.com/services/details/129dc4e9-191d-405f-ab4d-803d56f366a9) in two deployment options: VMware Cloud on AWS (VMC) or vCloud Director (VCD).\n\n![GitLab is available in the VMware Cloud Marketplace in two deployment options: VMware Cloud on AWS (VMC) or vCloud Director (VCD)](https://about.gitlab.com/images/blogimages/gitlabonvmware1.png){: .shadow.medium.center}\n\n3) To deploy the application both on VMC or VCD, you need to first subscribe to the image, as shown below:\n\n![To deploy the application both on VMC or VCD, you need to first subscribe, as shown below](https://about.gitlab.com/images/blogimages/subscribetovmwmarketplace.png){: .shadow.medium.center}\n\n4) Then, select the platform where you wish to deploy it, as shown below:\n\n![After subscribing, select the VMC or VCD platform where you wish to deploy](https://about.gitlab.com/images/blogimages/deploytovmwplatform.png){: .shadow.medium.center}\n\n5) Depending on the platform you select, you will be redirected to the vSphere Client or vCloud Director platform. Follow these instructions to launch a [GitLab Enterprise (CORE) Virtual Appliance using the vSphere Client](https://docs.bitnami.com/vmware-marketplace/apps/gitlab-ee/get-started/get-started-vmware-cloud/) or as a [vApp from VMware vCloud Director](https://docs.bitnami.com/vmware-marketplace/get-started-vcloud-director/).\n\n6) When you deploy the [GitLab Enterprise (CORE) Virtual Appliance certified by Bitnami](https://marketplace.cloud.vmware.com/services/details/129dc4e9-191d-405f-ab4d-803d56f366a9), you get the free and fully functional [Core version of GitLab](/pricing/#self-managed), which is easily upgradable to Starter, Premium, or Ultimate. To upgrade, sign into the application, navigate to the “Admin Area,” and then select the “License” menu option. As you can see in the image below, you now have the option to either upload your `.gitlab-license` file or start a [free trial](/free-trial/).\n\nNote: If you start a free trial, you will be able to try all the paid features for the duration of the trial. After that time, your server will revert to Core features.\n{: .alert .alert-info}\n\n![To upgrade, sign into the application, navigate to the “Admin Area,” and then select the “License” menu option](https://about.gitlab.com/images/blogimages/vmwmarketplacefreetrial.png){: .shadow.medium.center}\n\n\n7) Once you activate your license, paid features will be enabled as shown below and you can start deploying with confidence.\n\n![Once you activate your license, paid features will be enabled](https://about.gitlab.com/images/blogimages/vmwpremiumfeatures.png){: .shadow.medium.center}\n\n## Conclusion\n\nWhat used to be a complex task is now just a few clicks, without compromising your budget and your security. Enjoy all the advantages of the GitLab in the VMware Cloud Marketplace and accelerate your software delivery process by leveraging the simplicity of the Bitnami experience.\n\n[Get started now](https://marketplace.cloud.vmware.com/services/details/129dc4e9-191d-405f-ab4d-803d56f366a9). If you have any questions, feel free to reach out to the Bitnami Support team!\n\n### About the guest author\n\nRaquel Campuzano is a Content Marketing Specialist at Bitnami, now part of VMware. She is in charge of managing the creation of technical content that allows developers to deploy awesome software everywhere. Raquel was part of the Bitnami team as technical writer. Her know-how creating tutorials, product documentation, and videos gave her the ability to identify in which stage of developer’s journey the user experience can be improved.\n\nPrevious to Bitnami, she led the communication and marketing strategy for Redborder (cybersecurity) and Oklan (network and hosting services). She is also a member of Ping a Programadoras, a non-profit organisation focused on promoting women’s inclusion in programming and software development.\n",[108,850,851,9],{"slug":1733,"featured":6,"template":696},"gitlab-on-vmware-cloud-marketplace","content:en-us:blog:gitlab-on-vmware-cloud-marketplace.yml","Gitlab On Vmware Cloud Marketplace","en-us/blog/gitlab-on-vmware-cloud-marketplace.yml","en-us/blog/gitlab-on-vmware-cloud-marketplace",{"_path":1739,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1740,"content":1746,"config":1753,"_id":1755,"_type":13,"title":1756,"_source":15,"_file":1757,"_stem":1758,"_extension":18},"/en-us/blog/gitlab-rezilion-integration-reduces-vulnerability-backlog-identifies-exploitable-risks-to-fix",{"title":1741,"description":1742,"ogTitle":1741,"ogDescription":1742,"noIndex":6,"ogImage":1743,"ogUrl":1744,"ogSiteName":683,"ogType":684,"canonicalUrls":1744,"schema":1745},"Reducing vulnerability backlog with Rezilion and GitLab","The native integration helps developers detect and remediate vulnerabilities that are exploitable early on in the development process.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668437/Blog/Hero%20Images/faster-cycle-times.jpg","https://about.gitlab.com/blog/gitlab-rezilion-integration-reduces-vulnerability-backlog-identifies-exploitable-risks-to-fix","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How GitLab's integration with Rezilion reduces vulnerability backlog and identifies exploitable risks\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Baksheesh Singh Ghuman\"}],\n        \"datePublished\": \"2022-03-23\",\n      }",{"title":1747,"description":1742,"authors":1748,"heroImage":1743,"date":1750,"body":1751,"category":716,"tags":1752},"How GitLab's integration with Rezilion reduces vulnerability backlog and identifies exploitable risks",[1749],"Baksheesh Singh Ghuman","2022-03-23","\n\nRezilion and GitLab are partnering on an integration that will help resolve the longstanding tension between developers and security teams in organizations around the world. DevOps wants to write code and push new products to innovate and stay competitive. Security teams want to ensure applications are secure and unexploitable so that their organizations stay safe. These two desires often collide as DevOps wants to keep moving and security is seen as a bottleneck to their progress.\n\nTo help developers detect and remediate vulnerabilities early on in the development process and release products quickly and securely, Rezilion’s DevSecOps technology is now natively integrated with GitLab CI.\n\nSome of the key use benefits of this integration are the ability to:\n\n- [Reduce vulnerability backlog by up to 70%](https://www.rezilion.com/wp-content/uploads/2019/11/Rezilion-CARTA-Runtime-Vuln-Memory-Analysis-Report.pdf) and reduce patching efforts by identifying unexploitable vulnerabilities so that developers can fix what matters most and not waste time. \n\n- Prioritize what matters most in your environment to help save developers time and deliver better products faster.\n\n- Remediate significantly faster by integrating Rezilion's capabilities directly into the GitLab development workflow. This allows you to address real threats in a timely manner.\n\n- Gain actionable insights within the GitLab CI pipeline. Non-exploitable vulnerabilities are marked as “false positives” and can be dismissed, while issues can be easily assigned to fix the exploitable ones.\n\n- Identify software components with a dynamic Software Bill of Materials (SBOM), including open source components and their loaded/unloaded status for quick risk view.\n\n- Shift security left by validating vulnerabilities early in the process (right after the build, in the CI pipeline itself as part of tests that are running there). \n\nResults are available within the GitLab Security Dashboard and Vulnerability Management for use within the CI pipeline, at the project level, and across groups of projects.\n\n## Too many vulnerabilities, not enough focus\n\nA growing vulnerability backlog coupled with a lack of clarity on which vulnerabilities to fix – and when – can lead to a range of challenges, including:\n\n- Wasting developers' time\n- Delaying time to market\n- Increasing the likelihood of exploitation due to long remediation timelines\n\nA large vulnerability backlog takes up too much time. Remediating everything is not always realistic, practical, or secure. That’s why Rezilion’s native integration with GitLab CI allows teams to focus on fixing what matters most.\n\n## Enhanced runtime validation to fix what is exploitable \n\nBy integrating Rezilion’s capabilities into GitLab CI, developers now have a more complete and convenient security solution to restore focus on innovation. \n\nUsing Rezilion’s enhanced runtime validation, customers save time by scanning for vulnerabilities, filtering out scan results that do not pose a risk, building efficient remediation plans, and continuing to focus on seamlessly innovating software.\n\nCustomers can also easily visualize what software components are present in their environment – which are loaded to memory and therefore exploitable – by accessing their dynamic SBOM directly from the GitLab UI platform.\n\n\n![Rezilion Enhanced Vulnerability Validation funnel](https://about.gitlab.com/images/blogimages/rezilionfigure1.png){: .shadow}\n\nFigure 1: Enhanced Vulnerability Validation helps you focus on and fix what matters most\n{: .note.text-center}\n\n\n\n![Vulnerability report](https://about.gitlab.com/images/blogimages/rezilionfigure2.png){: .shadow}\n\nFigure 2: The vulnerability report shows a list of vulnerabilities in your pipeline and marks the false positives. Additionally, each row shows when it was detected, its status, severity, and details.\n{: .note.text-center}\n\nWe believe this integration will be very impactful for CISOs, product security team members, and developers who need to focus on innovating and product delivery, without delays due to a vulnerability backlog and cumbersome remediation timelines.\n\nCheckout this video to see Rezilion's GitLab integration in action:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/FXPwn7h8sBc\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nGet started today with a free trial of both \u003Ca href=\"/free-trial/\" data-ga-name=\"free trial\" data-ga-location=\"blog inline\">GitLab Ultimate\u003C/a> and [Rezilion](https://www.rezilion.com/sign-up-for-30day-free-trial/) to experience more efficient software vulnerability management.\n\n\n\n",[716,976,9,763],{"slug":1754,"featured":6,"template":696},"gitlab-rezilion-integration-reduces-vulnerability-backlog-identifies-exploitable-risks-to-fix","content:en-us:blog:gitlab-rezilion-integration-reduces-vulnerability-backlog-identifies-exploitable-risks-to-fix.yml","Gitlab Rezilion Integration Reduces Vulnerability Backlog Identifies Exploitable Risks To Fix","en-us/blog/gitlab-rezilion-integration-reduces-vulnerability-backlog-identifies-exploitable-risks-to-fix.yml","en-us/blog/gitlab-rezilion-integration-reduces-vulnerability-backlog-identifies-exploitable-risks-to-fix",{"_path":1760,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1761,"content":1767,"config":1774,"_id":1776,"_type":13,"title":1777,"_source":15,"_file":1778,"_stem":1779,"_extension":18},"/en-us/blog/gitlab-serverless-with-cloudrun-for-anthos",{"title":1762,"description":1763,"ogTitle":1762,"ogDescription":1763,"noIndex":6,"ogImage":1764,"ogUrl":1765,"ogSiteName":683,"ogType":684,"canonicalUrls":1765,"schema":1766},"Announcing GitLab Serverless deploying to Cloud Run for Anthos","Discover how we're making it easier to deploy serverless workloads on-premise with Anthos.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666851/Blog/Hero%20Images/gitlab-serverless-blog.png","https://about.gitlab.com/blog/gitlab-serverless-with-cloudrun-for-anthos","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Announcing GitLab Serverless deploying to Cloud Run for Anthos\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mayank Tahilramani\"}],\n        \"datePublished\": \"2019-11-19\",\n      }",{"title":1762,"description":1763,"authors":1768,"heroImage":1764,"date":1770,"body":1771,"category":691,"tags":1772},[1769],"Mayank Tahilramani","2019-11-19","\nThis week at Google Cloud Next ’19 UK, Google Cloud grew its Anthos product portfolio with the addition of Cloud Run for Anthos running on-prem. I’m excited to share that GitLab has been collaborating with Google Cloud product teams to support this launch and enable customers with CI/CD and [GitLab Serverless](/topics/serverless/) capabilities for quicker and easier adoption of serverless solutions. In the spirit of our partnership, our support for [Cloud Run for Anthos](https://cloud.google.com/run) is a continuation of our collaboration [announced earlier this year at Google Cloud Next ’19 in San Francisco](/blog/running-a-consistent-serverless-platform/), where we showed how you can deploy a serverless function to Cloud Run using the same developer workflow you’re already familiar with in GitLab. Now, we’re looking to bring that same UX and workflow consistency to Cloud Run deployments on Anthos running on-premise. Overall, together, GitLab and Google Cloud are aiming to lower the barrier of adoption for customers looking to architect scalable, cloud native solutions. \n\nHowever, when discussing cloud native, oftentimes ‘public cloud infrastructure’ comes to mind. But when I think of cloud native, I think of the various, modern ways of architecting scalable solutions, backed by managed services to make operations more convenient. Until very recently, infrastructure-centric managed services like Google Kubernetes Engine (GKE), Cloud Run, StackDriver, etc. have been traditionally associated with workloads running within cloud data centers. Given the recent announcements of [Google Cloud Anthos](https://cloud.google.com/blog/products/serverless/knative-based-cloud-run-services-are-ga), Google is clearly broadening the boundaries of cloud native across hybrid and heterogeneous environments, including customer data centers. As the infrastructure landscape diversifies, as application development intertwines with abstraction layers of managed services, and as workload flexibility becomes inherent with microservice containerization, the one thing you can rely on staying consistent is GitLab’s developer workflow to supplement all the above. In the context of all things [serverless](/topics/serverless/), let's take a closer look at what’s available today, what we’re still working on, and what that means for our users.\n\n## What’s available today\n\nGitLab serves as a single application for all of [DevOps](/topics/devops/), which includes building, deploying, and managing serverless applications. GitLab serverless enables developers to focus on writing application code without having to worry about Kubernetes or Knative YAML configuration. GitLab provides templates allowing developers to easily build and deploy Knative services that can be deployed to Cloud Run. Here is a [quick video walkthrough on the anatomy of a serverless project hosted in GitLab and deployed to Knative](https://youtu.be/IIM8JWhAbNk?t=210). With Google, you have a few options on how to leverage Cloud Run as a deployment target for GitLab CI/CD. As of this week, you can run Cloud Run in three different flavors: \n\n1. **Cloud Run**: This is a fully managed cloud service powered by Knative for serverless apps. GitLab supports deploying to Cloud Run and the full CI/CD workflow to leverage GitLab Runners to build and test functions. GitLab takes in the [`serverless.yml`](https://docs.gitlab.com/ee/update/removals.html) file within the root of your source code repository to define and deploy to Cloud Run.  \n\n2. **Cloud Run for Anthos running on Google Cloud**: This is a managed deployment of Knative on Anthos GKE clusters running on Google Cloud Platform. This enables you to install a managed Cloud Run deployment on top of your own Kubernetes cluster. Similar to above, GitLab also supports deploying to Cloud Run via the full CI/CD workflow, but as of right now, the highest version of Knative supported by GitLab is 0.7. Latest version support for Knative is coming in [GitLab 12.6](/releases/) on Dec. 22, 2019.  \n\n3. **Cloud Run for Anthos running on-premise**: Similar to above, this flavor of Cloud Run enables users to run a managed Cloud Run deployment on top of Anthos GKE On-Prem in your own data center. Currently, Knative v.0.9 is deployed in GKE-OP clusters. GitLab is soon to release support for Knative v0.9 and users can track the progress of this work in [this open issue](https://gitlab.com/gitlab-org/gitlabktl/issues/55) today. If you like what we’re working on, stop by and give us a thumbs up for feedback. So far, internal testing has been very positive and we look forward to formally supporting Cloud Run for Anthos running on-premise in the coming months/releases. The user experience will be almost identical to the prior two use cases listed above as you would expect.\n\n## Where to get started\n\nIf you’re interested in getting started with some sample code, check out our [documentation](https://docs.gitlab.com/ee/update/removals.html) and [sample app project](https://gitlab.com/knative-examples/functions) for reference. Additionally, [here is a walkthrough of deploying a demo app to Cloud Run from GitLab](https://youtu.be/lb_bRRAgEyc?t=1103). If you’re looking to get started with Serverless on Google Cloud Platform, [sign up for GitLab.com here](https://gitlab.com/users/sign_up) and then [sign up for $200 additional free GCP credits](https://cloud.google.com/partners/partnercredit/?PCN=a0n60000006Vpz4AAC).\n",[108,850,851,9,1773],"careers",{"slug":1775,"featured":6,"template":696},"gitlab-serverless-with-cloudrun-for-anthos","content:en-us:blog:gitlab-serverless-with-cloudrun-for-anthos.yml","Gitlab Serverless With Cloudrun For Anthos","en-us/blog/gitlab-serverless-with-cloudrun-for-anthos.yml","en-us/blog/gitlab-serverless-with-cloudrun-for-anthos",{"_path":1781,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1782,"content":1788,"config":1794,"_id":1796,"_type":13,"title":1797,"_source":15,"_file":1798,"_stem":1799,"_extension":18},"/en-us/blog/gitlab-trello-power-up-launch",{"title":1783,"description":1784,"ogTitle":1783,"ogDescription":1784,"noIndex":6,"ogImage":1785,"ogUrl":1786,"ogSiteName":683,"ogType":684,"canonicalUrls":1786,"schema":1787},"You asked, you got it: GitLab Power-Up comes to Trello","With 9.4 we shipped a GitLab Power-Up for Trello – attach a merge request to a Trello card and enjoy an even more seamless workflow.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671369/Blog/Hero%20Images/trello-power-up-blog-cover.png","https://about.gitlab.com/blog/gitlab-trello-power-up-launch","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"You asked, you got it: GitLab Power-Up comes to Trello\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2017-07-22\",\n      }",{"title":1783,"description":1784,"authors":1789,"heroImage":1785,"date":1791,"body":1792,"category":298,"tags":1793},[1790],"Rebecca Dodd","2017-07-22","\nTrello's most requested third-party Power-Up is now live! As of [GitLab 9.4](/releases/2017/07/22/gitlab-9-4-released/), Trello users can now connect to GitLab from within a Trello board and attach a merge request to a Trello card.\n\n\u003C!-- more -->\n\nThis integration has got a lot of people excited. Here's our VP of Product [Job van der Voort](/company/team/#Jobvo) demonstrating his enthusiasm for the Power-Up:\n\n![VP of Product Job van der Voort](https://about.gitlab.com/images/blogimages/trello-power-up-job.jpg)\n\nYou can follow more discussion around the integration [on the issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/32042).\n\n## Here's the Power-Up in action\n\n![GitLab Trello Power-Up gif](https://about.gitlab.com/images/blogimages/trello-power-up-gif.gif)\n\n1. When viewing one of your boards in Trello, simply go to Power-Ups and select the GitLab Power-Up. After setup, you can search GitLab merge requests from within a Trello card and attach one to the card.\n\n2. Click through to the attached merge request directly from the card.\n\nSimple!\n\n## How it helps\n\nWe're always looking for ways to streamline developer workflows and reduce the need for context-switching. The less time spent stringing together tooling, the better. GitLab's Trello Power-Up integrates two popular platforms to tighten up the development process and make the experience of using GitLab and Trello even better.\n\n![GitLab Trello Power-Up screengrab](https://about.gitlab.com/images/blogimages/trello-power-up-screengrab.png){: .shadow\n\n## What's next\n\nAs always, as a new feature this is in its first iteration. Our community has already asked for further integration, such as creating branches and commits from within Trello cards as well. Give the new Power-Up a try and let us know how we can improve on it by opening [a feature request](https://gitlab.com/gitlab-org/trello-power-up/issues). As part of our [Community Edition](https://gitlab.com/gitlab-org/gitlab-ce), the code for the Power-Up is hosted on [gitlab.com/gitlab-org/trello-power-up](https://gitlab.com/gitlab-org/trello-power-up), and anyone can contribute to future iterations 🚀\n\n## Get started\n\nOur documentation contains everything you need to know to get the Power-Up running. [Read the documentation for GitLab Power-Up for Trello here](https://docs.gitlab.com/ee/integration/trello_power_up.html).\n",[9],{"slug":1795,"featured":6,"template":696},"gitlab-trello-power-up-launch","content:en-us:blog:gitlab-trello-power-up-launch.yml","Gitlab Trello Power Up Launch","en-us/blog/gitlab-trello-power-up-launch.yml","en-us/blog/gitlab-trello-power-up-launch",{"_path":1801,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1802,"content":1808,"config":1814,"_id":1816,"_type":13,"title":1817,"_source":15,"_file":1818,"_stem":1819,"_extension":18},"/en-us/blog/gitlab-uses-anthropic-for-smart-safe-ai-assisted-code-generation",{"title":1803,"description":1804,"ogTitle":1803,"ogDescription":1804,"noIndex":6,"ogImage":1805,"ogUrl":1806,"ogSiteName":683,"ogType":684,"canonicalUrls":1806,"schema":1807},"GitLab uses Anthropic for smart, safe AI-assisted code generation","Anthropic’s Claude AI model supports the delivery of helpful, trusted code in GitLab Duo Code Suggestions.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669095/Blog/Hero%20Images/gitlabduo.png","https://about.gitlab.com/blog/gitlab-uses-anthropic-for-smart-safe-ai-assisted-code-generation","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab uses Anthropic for smart, safe AI-assisted code generation\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Kevin Chu\"}],\n        \"datePublished\": \"2024-01-16\",\n      }",{"title":1803,"description":1804,"authors":1809,"heroImage":1805,"date":1811,"body":1812,"category":1568,"tags":1813},[1810],"Kevin Chu","2024-01-16","GitLab recently launched GitLab Duo Code Suggestions into general availability. Code Suggestions includes the ability to generate algorithms or code blocks directly within the developer's IDE, a capability that uses [Anthropic's](https://www.anthropic.com/) generative AI model, [Claude](https://www.anthropic.com/index/claude-2-1). Integrated into the GitLab Duo portfolio of AI-assisted features, Claude is compatible with GitLab’s principles of [transparency and privacy](https://about.gitlab.com/the-source/ai/building-a-transparency-first-ai-strategy-7-questions-to-ask-your-devops/) by design and provides a high-integrity foundation for code generation.\n\nIn this post, you'll learn the advantages of code generation and how GitLab, together with Anthropic, is leveraging AI to responsibly boost developer productivity.\n\n## How AI-assisted code generation works\n\nCode Suggestions is incredibly useful as a coding companion that shows the suggestions as a developer types. It helps save developer time and keystrokes, reducing the effort for rote tasks and giving developers time back in their day. But what if a developer wants to do even more with generative AI?\n\nEnter code generation.\n\nImagine needing to write a new complex function based on an unfamiliar algorithm, or write a large amount of boilerplate code. Instead of struggling through these tasks with gritted teeth, code generation allows developers to simply define what they want to do in comments or multi-line comment blocks, and then Code Suggestions generates the code from there.\n\nHere is an example of Code Suggestions generating a JavaScript function that calculates the Levenshtein distance, a string metric useful for comparing the difference between two sequences:\n\n\u003Cimg src=\"https://res.cloudinary.com/about-gitlab-com/image/upload/v1752175962/Blog/lkrk16unp4dcy3c4zwvw.gif\" alt=\"Code Suggestions generating JavaScript function\" width=\"100%\" height=\"auto\">\n\nHere is another example showing a multi-line comment in Python. We want Code Suggestions to generate a Tornado Web Server that does three things: log in, run a scan, and review the results. By providing the specific instructions, including details such as the framework and the components to use,, Code Suggestions was able to generate a Tornado App, despite this author being unfamiliar with Tornado.\n\n\u003Cimg src=\"https://res.cloudinary.com/about-gitlab-com/image/upload/v1752175967/Blog/pxcdppnpzwfhgopxh999.gif\" alt=\"Code Suggestions generating Tornado app\" width=\"100%\" height=\"auto\">\n\nSafety through focus and trustworthiness\nDevelopers expect AI coding assistants to not only be helpful, but also accurate and safe. The system should generate precisely what is asked for while limiting deviation and [hallucination](https://www.ibm.com/topics/ai-hallucinations). Customers want assurances that AI-generated code can be trusted.\n\nThroughout GitLab's evaluation of certain code generation models, Claude stood out for its ability to mitigate distracting, unsafe, or deceptive behaviors. Claude also demonstrated consistent and accurate code generation throughout our testing.\n\nGitLab's use of Anthropic's Claude enables Code Suggestions to balance automation with trust. Code Suggestions helps users become more efficient without sacrificing reliability — a win for augmented development.\n\n## What’s next\n\nReady to experience the future of code generation? Start your [free trial of GitLab Duo](https://about.gitlab.com/gitlab-duo/) today and unlock the power of AI-assisted development!",[934,9,976,851],{"slug":1815,"featured":90,"template":696},"gitlab-uses-anthropic-for-smart-safe-ai-assisted-code-generation","content:en-us:blog:gitlab-uses-anthropic-for-smart-safe-ai-assisted-code-generation.yml","Gitlab Uses Anthropic For Smart Safe Ai Assisted Code Generation","en-us/blog/gitlab-uses-anthropic-for-smart-safe-ai-assisted-code-generation.yml","en-us/blog/gitlab-uses-anthropic-for-smart-safe-ai-assisted-code-generation",{"_path":1821,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1822,"content":1828,"config":1834,"_id":1836,"_type":13,"title":1837,"_source":15,"_file":1838,"_stem":1839,"_extension":18},"/en-us/blog/gitlab-vscode-extension",{"title":1823,"description":1824,"ogTitle":1823,"ogDescription":1824,"noIndex":6,"ogImage":1825,"ogUrl":1826,"ogSiteName":683,"ogType":684,"canonicalUrls":1826,"schema":1827},"A VS Code extension for GitLab: GitLab Workflow","Senior Frontend Engineer Fatih Acet created a VS Code extension, GitLab Workflow, which allows you to do many GitLab-specific tasks quickly and easily.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680196/Blog/Hero%20Images/vs-code-extension-gitlab-workflow.jpg","https://about.gitlab.com/blog/gitlab-vscode-extension","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"A VS Code extension for GitLab: GitLab Workflow\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fatih Acet\"}],\n        \"datePublished\": \"2018-03-01\",\n      }",{"title":1823,"description":1824,"authors":1829,"heroImage":1825,"date":1831,"body":1832,"category":739,"tags":1833},[1830],"Fatih Acet","2018-03-01","\n\nWe recently did a survey within the Frontend team to see which tools we were using and how we were using them, in order to learn from one another and to build better development workflows. Through this survey, we determined that [Visual Studio Code (VS Code)](https://code.visualstudio.com/) is the most used integrated development environment (IDE) within the team. This led to the idea for a GitLab extension for VS Code that could help reduce context switching and boost productivity.\n\nUpdate: Read [eight tips for using the GitLab VS Code extension](https://about.gitlab.com/blog/vscode-workflows-for-working-with-gitlab/) and about [how GitLab + VS Code can be used for extension development](/blog/vscode-extension-development-with-gitlab/).\n{: .alert .alert-info .text-center}\n\nThis is not a [GitLab feature](/pricing/feature-comparison/) (we're actually working on building our own integrated [web IDE](https://docs.gitlab.com/ee/user/project/web_ide/)), but the extension is a quick and easy way to perform a lot of useful actions you would usually visit [GitLab.com](https://gitlab.com/) to do, directly within your VS Code editor. Watch the demo below and read on for more about how I developed the extension.\n\n## Demo\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/XcxsF0lWBhA\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n## First iteration of GitLab Workflow\n\nThis was my first attempt at writing a VS Code extension, and I wanted to build something simple as a first iteration. I built an extension that allowed users to see issues and merge requests assigned to them on GitLab.com. The detailed documentation and powerful APIs of VS Code enabled me to build my first version in less than two hours! It was an enjoyable experience.\n\n## Further iterations\n\nThis led to the creation of my second iteration: showing MR URLs, providing the pipeline status on the status bar, opening the current file and current MR on GitLab.com. I shared this second iteration with my fellow GitLab team-members on our internal Slack and received a lot of positive feedback. After that, I released new iterations and it got more than 5,000 installations in just a month. It was so well received that it was featured on the \"Trending this week\" section of Visual Studio Marketplace and is still currently being featured on the \"Trending this month\" section 🎉\n\n\u003Ccenter>\u003Cimg src=\"/images/blogimages/gitlab-vscode-extension/trending-this-month.png\" alt=\"GitLab Workflow on Visual Studio Marketplace\" style=\"width: 700px;\"/>\u003C/center>{: .shadow}\n\nThe current version of this extension allows you to:\n\n- See pipeline status, open MR and close issue links in the status bar. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#status-bar).\n- Automatically update pipeline status on the status bar so you don't need to open GitLab to see your pipeline status.\n- Advanced pipeline actions allow you to view a pipeline on GitLab, create a new pipeline, and retry or cancel current pipeline. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#pipeline-actions).\n- Issue and MR search including simple and advanced search. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#advanced-search).\n- View an MR and close an issue on GitLab with a single click from your status bar.\n- View an active file on GitLab with highlighting active line number and selected text block. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#open-active-file).\n- Create public, internal or private snippet from entire file or selection. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#create-snippet).\n- Compare your branch with master and view changes on GitLab. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#compare-with-master).\n- Validate GitLab CI configuration file `.gitlab-ci.yml`. [Read more](https://gitlab.com/fatihacet/gitlab-vscode-extension/tree/master#validate-gitlab-ci-configuration).\n\nSee below for more tasks you can perform quickly with the extension.\n\n\u003Ccenter>\u003Cimg src=\"/images/blogimages/gitlab-vscode-extension/gitlab-vscode.png\" alt=\"GitLab Workflow Commands\" style=\"width: 700px;\"/>\u003C/center>{: .shadow}\n\nYou can find the source code [here](https://gitlab.com/fatihacet/gitlab-vscode-extension) and see the extension [on the Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=fatihacet.gitlab-workflow). You can read the documentation [here](https://docs.gitlab.com/ee/user/project/repository/vscode.html) and check the CHANGELOG [here](https://gitlab.com/fatihacet/gitlab-vscode-extension/blob/master/CHANGELOG.md). There is also a [Product Hunt page](https://www.producthunt.com/posts/gitlab-workflow) for the extension.\n\nPhoto by [Iker Urteaga](https://unsplash.com/photos/TL5Vy1IM-uA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/tools?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n{: .note}\n",[1408,693,9],{"slug":1835,"featured":6,"template":696},"gitlab-vscode-extension","content:en-us:blog:gitlab-vscode-extension.yml","Gitlab Vscode Extension","en-us/blog/gitlab-vscode-extension.yml","en-us/blog/gitlab-vscode-extension",{"_path":1841,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1842,"content":1848,"config":1854,"_id":1856,"_type":13,"title":1857,"_source":15,"_file":1858,"_stem":1859,"_extension":18},"/en-us/blog/gitlab-workflow-with-jira-jenkins",{"title":1843,"description":1844,"ogTitle":1843,"ogDescription":1844,"noIndex":6,"ogImage":1845,"ogUrl":1846,"ogSiteName":683,"ogType":684,"canonicalUrls":1846,"schema":1847},"Demo: GitLab + Jira + Jenkins","See how you can use our Jira and Jenkins integrations to reduce context switching and streamline your workflow.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680048/Blog/Hero%20Images/gitlab-jira-jenkins-cover.png","https://about.gitlab.com/blog/gitlab-workflow-with-jira-jenkins","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Demo: GitLab + Jira + Jenkins\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Joel Krooswyk\"}],\n        \"datePublished\": \"2018-07-30\",\n      }",{"title":1843,"description":1844,"authors":1849,"heroImage":1845,"date":1851,"body":1852,"category":298,"tags":1853},[1850],"Joel Krooswyk","2018-07-30","\n\nOne of the things we love about GitLab is that while it can replace all your other software development lifecycle tools [(no, really)](/); it doesn't have to. Whether you want to rip and replace everything or use it for one or two stages of your workflow, [alongside your existing toolset](/partners/technology-partners/integrate/) (for now, or forever), we've got you covered.\n\nOne of the things we're most often asked about is how GitLab works together with [Jira](/solutions/jira/) for issue tracking, and [Jenkins](/solutions/jenkins/) for CI. This could be for one of two reasons:\n\n1. Your organization is happy with your issue tracking and CI solutions, and just want to use GitLab for other features, or\n2. You plan to move to GitLab for your end-to-end software development lifecycle, but that's a significant undertaking and it may be less disruptive to migrate on a project-by-project basis.\n\nNo matter the reason, what's important is maintaining the context of work without having to switch between applications frequently. With these integrations you can transition Jira issue states via GitLab, as well as see GitLab commits, branches, and merge requests in the Jira development panel. You can also view the status of Jenkins pipelines in GitLab to optimize your use of GitLab Merge Requests.\n\nI recorded this demo to show what a workflow using all three would look like.\n\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/Jn-_fyra7xQ\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n",[785,1408,9,872],{"slug":1855,"featured":6,"template":696},"gitlab-workflow-with-jira-jenkins","content:en-us:blog:gitlab-workflow-with-jira-jenkins.yml","Gitlab Workflow With Jira Jenkins","en-us/blog/gitlab-workflow-with-jira-jenkins.yml","en-us/blog/gitlab-workflow-with-jira-jenkins",{"_path":1861,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1862,"content":1868,"config":1873,"_id":1875,"_type":13,"title":1876,"_source":15,"_file":1877,"_stem":1878,"_extension":18},"/en-us/blog/gitlab-zapier-integration",{"title":1863,"description":1864,"ogTitle":1863,"ogDescription":1864,"noIndex":6,"ogImage":1865,"ogUrl":1866,"ogSiteName":683,"ogType":684,"canonicalUrls":1866,"schema":1867},"There's a Zap for that. Automate your workflows with GitLab + Zapier","With Zapier's GitLab integration you can create new Issues directly from within Gmail, get Slack notifications for new Issues and much more.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671323/Blog/Hero%20Images/zapier-gitlab-integration.jpg","https://about.gitlab.com/blog/gitlab-zapier-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"There's a Zap for that. Automate your workflows with GitLab + Zapier\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2017-08-23\",\n      }",{"title":1863,"description":1864,"authors":1869,"heroImage":1865,"date":1870,"body":1871,"category":298,"tags":1872},[1790],"2017-08-23","\n\nZapier has just launched an integration with GitLab – hurrah! With a host of Zap templates, like triggering tweets for new commits, Slack messages when Merge Requests are opened or closed, or creating new Issues from starred emails in Gmail, this is great news for teams wanting to automate their workflows and collaborate more effectively.\n\n\u003C!-- more -->\n\nIf you're not a Zapier user yet, essentially it's a tool you can use to create integrations between your other tools which don't generally talk to each other, including Gmail, Slack, Twitter, Trello, Asana and now [GitLab](https://zapier.com/zapbook/gitlab/)! It's endlessly customizable, as you can create any integration you want using the \"Make a Zap\" button on the Zapier homepage. [See how to get started](https://zapier.com/zapbook/updates/1165/gitlab-integrations/?rebuild=yes).\n\nOur UX Lead [Sarrah Vesselov](/company/team/#SVesselov) gave the integration a spin and had this to say:\n\n>Overall, the number of pre-set zaps for GitLab was excellent. Trello, Asana, Gmail, Twitter integrations were easy to set up and are helpful for a number of potential workflows. There is great opportunity to use Issues and MRs to trigger automated workflows and increase collaboration and productivity for teams.\n\nCurious about those pre-set Zaps? These are our favorites:\n\n\u003Cscript src=\"https://zapier.com/zapbook/embed/widget.js?services=gitlab&container=true&limit=10\">\u003C/script>\n\nYou can [browse popular Zaps for GitLab here](https://zapier.com/zapbook/gitlab/). Missing something? [Create your own](https://zapier.com/app/editor/25451800/nodes/25451800/action) or tweet [@zapier](https://twitter.com/zapier) with your ideas.\n",[9,872],{"slug":1874,"featured":6,"template":696},"gitlab-zapier-integration","content:en-us:blog:gitlab-zapier-integration.yml","Gitlab Zapier Integration","en-us/blog/gitlab-zapier-integration.yml","en-us/blog/gitlab-zapier-integration",{"_path":1880,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1881,"content":1886,"config":1891,"_id":1893,"_type":13,"title":1894,"_source":15,"_file":1895,"_stem":1896,"_extension":18},"/en-us/blog/gitops-with-gitlab-connecting-the-cluster",{"title":1882,"description":1883,"ogTitle":1882,"ogDescription":1883,"noIndex":6,"ogImage":754,"ogUrl":1884,"ogSiteName":683,"ogType":684,"canonicalUrls":1884,"schema":1885},"GitOps with GitLab: Connect with a Kubernetes cluster","In our third article in our GitOps series, learn how to connect a Kubernetes cluster with GitLab for pull and push-based deployments.","https://about.gitlab.com/blog/gitops-with-gitlab-connecting-the-cluster","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitOps with GitLab: Connect with a Kubernetes cluster\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Viktor Nagy\"}],\n        \"datePublished\": \"2021-11-18\",\n      }",{"title":1882,"description":1883,"authors":1887,"heroImage":754,"date":1888,"body":1889,"category":739,"tags":1890},[824],"2021-11-18","_It is possible to use GitLab as a best-in-class GitOps tool, and this blog\npost series is going to show you how. These easy-to-follow tutorials will\nfocus on different user problems, including provisioning, managing a base\ninfrastructure, and deploying various third-party or custom applications on\ntop of them. You can find the entire \"Ultimate guide to GitOps with GitLab\"\ntutorial series\n[here](/blog/the-ultimate-guide-to-gitops-with-gitlab/)._\n\n\n## GitOps with GitLab: connecting a Kubernetes cluster\n\n\nThis [GitOps](/topics/gitops/) with GitLab post shows how to connect a\nKubernetes cluster with GitLab for pull and push based deployments and easy\nsecurity integrations. In order to do so, the following elements are\nrequired:\n\n\n- A Kubernetes cluster that you can access and can create new resources,\nincluding `Role` and `RoleBinding` in it. \n\n- You will need `kubectl` and your local environment configured to access\nthe beforementioned cluster.\n\n- (Optional, recommended) Terraform and a Terraform project set up as shown\n[in the previous\narticle](/blog/gitops-with-gitlab-infrastructure-provisioning/)\nto retrieve an agent registration token from GitLab.\n\n- (Optional, recommended) `kpt` and `kustomize` to install the Agent into\nyour cluster.\n\n- (Optional, quickstart) If you prefer a less \"gitopsy\" approach, you will\nneed `docker` (Docker Desktop is not needed). This is simpler to follow, but\nprovides less control to you.\n\n\n## How to connect a cluster to GitLab\n\n\nThere are many ways how one can connect a cluster to GitLab:\n\n\n- you can set up a `$KUBECONTEXT` variable manually, manage all the related\nconnections and use GitLab CI/CD to push changes into your cluster\n\n- you can use a 3rd party tool, like\n[ArgoCD](https://argo-cd.readthedocs.io/en/stable/) or\n[Flux](https://fluxcd.io) to get pull based deployments\n\n- you can use the legacy, certificate-based cluster integration within\nGitLab in which case GitLab will manage the `$KUBECONTEXT` for you and you\ncan get easy metrics, log and monitoring integrations\n\n- or you can use the recommended approach, the [GitLab Agent for\nKubernetes](https://docs.gitlab.com/ee/user/clusters/agent/), to have pull\nand push based deployment support, network security policy integrations and\nthe possibility of metrics and monitoring too\n\n\nWe are going to focus on the Agent-based setup here as we believe that it\nserves and will serve our users best, hopefully you included.\n\n\n## How does the Agent work\n\n\nThe Agent has a component that needs to be installed into your cluster. We\ncall this component `agentk`. Once `agentk` is installed it reaches out to\nGitLab, and authenticates itself with an access token. So, the first step is\nto get a token from GitLab. We call this step \"the Agent registration.\" If\nthe authentication succeeds, `agentk` sets up a bidirectional GRPC channel\nbetween itself and GitLab. The emphasis here is on \"bidirectional.\" This\nenables requests and messages to be sent by either side and provides the\npossibility of much deeper integrations than the other approaches while\nstill being a nice citizen within your cluster.\n\n\nOnce the connection is established, the Agent retrieves its own\nconfiguration from GitLab. This configuration is a `config.yaml` file under\na repository, and you actually register the location of this configuration\nfile when you register a new Agent. The configuration describes the various\ncapabilities enabled of an Agent.\n\n\nOn the GitLab side, `agentk` communicates with - what we call - the\nKubernetes Agent Server, or `kas`. As most users do not have to deal with\nsetting up `kas`, I won't write about it here. You need to be a GitLab\nadministrator [to set up and manage\n`kas`](https://docs.gitlab.com/ee/administration/clusters/kas.html). If you\nare on gitlab.com, `kas` is available to you at `kas.gitlab.com`, thanks to\nour amazing SRE team.\n\n\nSo the steps we are going to take in this article are the following:\n\n\n1. Create a configuration file for the Agent\n\n1. Register the Agent and retrieve its authentication token\n\n1. Install `agentk` into the cluster together with the token\n\n\nFinally, we will set up an example pull-based deployment just to test that\neverything worked as expected. Let's get started!\n\n\n## How many Agents do you need for a larger setup\n\n\nWe recommend having a separate Agent registered at least against each of\nyour environments. If you have multiple clusters, have at least one agent\nregistered with each cluster. While it is possible to have many `agentk`\ndeployments with the same authentication token and thus configuration file,\nthis is not supported and might lead to syncronization problems!\n\n\nThe different agent configurations can use the same Kubernetes manifests for\ndeployments. So maintaining a multi-region cluster where all the clusters\nshould be identical does not require much effort. \n\n\nWe designed `agentk` to be very lightweight so you should not worry about\ndeploying multiple instances of it into a cluster. \n\n\nWe know users who use separate `agentk` instances by squad for example. In\nthese situations, the `squad` owns some namespaces in the cluster and each\nAgent can access only the namespaces available for their squad. This way\n`agentk` is not just a good citizen in your cluster, but is like a team\nmember in your squad.\n\n\n## Create a configuration file for the Agent\n\n\nNote:\n\nYou can use either the Terraform project from the previous step or start\nwith a new project. I will assume that we build on top of the Terraform\nsetup from the previous article, linked above, that will come in handy when\nwe want to register the Agent using Terraform. I won't go through setting up\nall the environment variables here for local Terraform run.\n\n\nDecide about your agent name, and create an empty file in your project under\n`.gitlab/agents/\u003Cyour agent name>/config.yaml`. Nota bene, that the\nextension is `yaml` not `yml` and your agent name must follow the [DNS label\nstandard from RFC\n1123](https://docs.gitlab.com/ee/user/clusters/agent/install/#create-an-agent-configuration-file).\nI'll call my agent `demo-agent`, so the file is under\n`.gitlab/demo-agent/config.yaml`.\n\n\n## Register the Agent\n\n\nThe next step is to register the Agent with GitLab. You can do this either\nthrough the GitLab UI or using Terraform. I will show you both approaches.\n\n\n### Registering through the UI\n\n\nOnce the configuration file is in place, visit `Infrastructure/Kubernetes`\nand add a new cluster using the Agent. A dialog will pop up where you can\nselect your agent.\n\n\nOnce you hit \"next,\" you will see the registration token and a `docker`\ncommand for easy installation. The `docker` command includes the token too\nand you can run it to quickly set up an `agentk` inside of your cluster.\n(You might need to create a namespace first!) Feel free to run the command\nfor a quickstart or follow the tutorial for a truly code-based approach.\n\n\n### Registering through code\n\n\nWe will use Terraform to register the Agent through code. Let's create the\nfollowing files:\n\n\n- Under `terraform/gitlab-agent/main.tf`\n\n\n```hcl\n\nterraform {\n  backend \"http\" {\n  }\n  required_version = \">= 0.13\"\n  required_providers {\n    gitlab = {\n      source = \"gitlabhq/gitlab\"\n      version = \"~>3.6.0\"\n    }\n  }\n}\n\n\nprovider \"gitlab\" {\n    token = var.gitlab_password\n}\n\n\nmodule \"gitlab_kubernetes_agent_registration\" {\n  source = \"gitlab.com/gitlab-org/kubernetes-agent-terraform-register-agent/local\"\n  version = \"0.0.2\"\n\n  gitlab_project_id = var.gitlab_project_id\n  gitlab_username = var.gitlab_username\n  gitlab_password = var.gitlab_password\n  gitlab_graphql_api_url = var.gitlab_graphql_api_url\n  agent_name = var.agent_name\n  token_name = var.token_name\n  token_description = var.token_description\n}\n\n```\n\n\nAs you can see we will use a module here. The module is hosted using the\nTerraform registry provided by GitLab. You can check out [the module source\ncode\nhere](https://gitlab.com/gitlab-org/configure/examples/kubernetes-agent-terraform-register-agent).\nYou might have guessed correctly that under the hood the module uses the\nGitLab GraphQL API to register the agent and retrieve a token. We will need\nto set up variables for it to work.\n\n\n- Create `terraform/gitlab-agent/variables.tf`\n\n\n```hcl\n\nvariable \"gitlab_project_id\" {\n  type = string\n}\n\n\nvariable \"gitlab_username\" {\n  type = string\n}\n\n\nvariable \"gitlab_password\" {\n  type = string\n}\n\n\nvariable \"agent_name\" {\n  type = string\n}\n\n\nvariable \"token_name\" {\n  type    = string\n  default = \"kas-token\"\n}\n\n\nvariable \"token_description\" {\n  type    = string\n  default = \"Token for KAS Agent Authentication\"\n}\n\n\nvariable \"gitlab_graphql_api_url\" {\n  type    = string\n  default = \"https://gitlab.com/api/graphql\"\n}\n\n```\n\n\n- Create `terraform/gitlab-agent/outputs.tf`\n\n\n```hcl\n\noutput \"agent_id\" {\n  value     = module.gitlab_kubernetes_agent_registration.agent_id\n}\n\n\noutput \"token_secret\" {\n  value     = module.gitlab_kubernetes_agent_registration.token_secret\n  sensitive = true\n}\n\n```\n\n\nOnce the registration is over, you'll be able to retrieve the agent ID and\nthe token using these Terraform outputs.\n\n\n### Run the Terraform project\n\n\nOnce the above code is in place, we need to run it to actually register the\nAgent. Here, I am going to extend the setup from the previous article.\n\n\n#### Running locally\n\n\n- Create `terraform/gitlab-agent/.envrc`  as you did for the network\nproject.\n\n\n```\n\nexport TF_STATE_NAME=${PWD##*terraform/}\n\nsource_env ../../.main.env\n\n```\n\n\nNow run Terraform\n\n\n```bash\n\nterraform init\n\nterraform plan\n\nterraform apply\n\n```\n\n\n#### Running from CI/CD pipeline\n\n\nExtend the `.gitlab-ci.yml` file with the following 3 jobs:\n\n\n```hcl\n\ngitlab-agent:init:\n  extends: .terraform:init\n  stage: init\n  variables:\n    TF_ROOT: terraform/gitlab-agent\n    TF_STATE_NAME: gitlab-agent\n  only:\n    changes:\n      - \"terraform/gitlab-agent/*\"\n\ngitlab-agent:review:\n  extends: .terraform:build\n  stage: build\n  variables:\n    TF_ROOT: terraform/gitlab-agent\n    TF_STATE_NAME: gitlab-agent\n  resource_group: tf:gitlab-agent\n  only:\n    changes:\n      - \"terraform/gitlab-agent/*\"\n\ngitlab-agent:deploy:\n  extends: .terraform:deploy\n  stage: deploy\n  variables:\n    TF_ROOT: terraform/gitlab-agent\n    TF_STATE_NAME: gitlab-agent\n  resource_group: tf:gitlab-agent\n  environment:\n    name: demo-agent\n  when: manual\n  only:\n    changes:\n      - \"terraform/gitlab-agent/*\"\n    variables:\n      - $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n```\n\n\nAs you can see these are the same jobs that we saw already, they are just\nparameterized for the `gitlab-agent` terraform project.\n\n\nNota bene, even if you use GitLab to register the Agent, you will need your\ncommand line to install `agentk` for the first time! As a result, you can\nnot avoid a local setup as you will need to run at least `terraform output`\nto retrieve the token!\n\n\n## Install `agentk`\n\n\nIn this tutorial we are going to follow [the advanced installation\ninstructions](https://docs.gitlab.com/ee/user/clusters/agent/install/index.html#advanced-installation)\nfrom the GitLab documentation. This approach is highly customizable using\n`kustomize` and `kpt`.\n\n\nFirst, let's retrieve the basic Kubernetes resource definitions using `kpt`:\n\n\n- Create a directory `packages` using `mkdir packages`\n\n- Run `kpt pkg get\nhttps://gitlab.com/gitlab-org/cluster-integration/gitlab-agent.git/build/deployment/gitlab-agent\npackages/gitlab-agent`\n\n\nThis will retrieve the most recent version of the `agentk` installation\nresources. You can request a tagged version with the well-known `@` syntax,\nfor example by running `kpt pkg get\nhttps://gitlab.com/gitlab-org/cluster-integration/gitlab-agent.git/build/deployment/gitlab-agent@v14.4.0\npackages/gitlab-agent`. You can see [all the available versions\nhere](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/tags).\n\n\n### Why `kpt` - could we make this a box?\n\n\nThe choice of `kpt` is because it allows sane upstream package management to\nyou. With `kpt` you will be able to regularly update your packages using\nsomething like `kpt pkg update packages/gitlab-agent@\u003Cnew version>\n--strategy=resource-merge`. It basically allows you to modify your package\nlocally, and will try to merge upstream changes into it. Read the `kpt pkg\nupdate -h` output for more information and alternative merge strategies.\n\n\n### Continue with the installation - if it's a box, this is not needed\n\n\nThe `kpt` packages you retrieved are actually a set up `kustomize` overlays.\nThe `base` defines only the `agentk` deployment and namespace; the `cluster`\ndefines some default RBAC around the deployment. Feel free to add your own\noverlays and use those. We will extend this package with custom overlays in\na part 6 of the series.\n\n\nTo configure the package, see the available configuration options using:\n\n\n```bash\n\nkustomize cfg list-setters packages/gitlab-agent\n        NAME                 VALUE               SET BY                  DESCRIPTION              COUNT   REQUIRED   IS SET  \n  agent-version       stable                 package-default   Image tag for agentk container     1       No         No      \n  kas-address         wss://kas.gitlab.com   package-default   kas address. Use                   1       No         No      \n                                                               grpc://host.docker.internal:8150                              \n                                                               if connecting from within Docker                              \n                                                               e.g. from kind.                                               \n  name-prefix                                                  Prefix for resource names          1       No         No      \n  namespace           gitlab-agent           package-default   Namespace to install GitLab        2       No         No      \n                                                               Kubernetes Agent into                                         \n  prometheus-scrape   true                   package-default   Enable or disable Prometheus       1       No         No      \n                                                               scraping of agentk metrics.                              \n```\n\n\nThe package default will be different if you used a tagged version for\ngetting the package. Let's set the version as using `stable` is not\nrecommended.\n\n\n```bash\n\nkustomize cfg set packages/gitlab-agent agent-version v14.4.1\n\nset 1 field(s) of setter \"agent-version\" to value \"v14.4.1\"\n\n```\n\n\nFeel free to adjust the other configuration options too or add you own\noverlays if that is needed.\n\n\n### Which agent-version to use - could we make this a box?\n\n\nIf possible the version of `agentk` should match the major and minor version\nof your GitLab instance. You can find our the version of your GitLab\ninstance under the Help menu on the UI.\n\n\nIf there is no agent version with your major and minor version, then pick\nthe agent with the highest major and minor below the version of your GitLab.\n\n\n### Continue with the installation - if it's a box, this is not needed\n\n\nWarning:\n\nBefore the next step, I want to warn you about never, ever committing\nunencrypted secrets into git, and the agent registration token is a secret!\n\n\nLet's retrieve the agent registration token from our Terraform project. Run\nthe following command in the `terraform/gitlab-agent` directory:\n\n\n```bash\n\nterraform output -raw token_secret >\n../../packages/gitlab-agent/base/secrets/agent.token\n\n```\n\n\nThis writes the registration token to a file on your local computer. Do not\ncommit these changes to git!\n\n\nAt this point, we are ready to deploy `agentk` into the cluster, so run:\n\n\n```bash\n\nkustomize build packages/gitlab-agent/cluster | kubectl apply -f -\n\n```\n\n\nLet's get rid of the secret:\n\n\n```bash\n\necho \"Invalid token\" > packages/gitlab-agent/base/secrets/agent.token\n\n```\n\n\nYou are good to commit your changes to `git` now!\n\n\n## Testing the setup\n\n\nWe have installed the Agent, now what? How can we start using it? In the\nnext article we will see in detail how to deploy a more serious application\ninto the cluster. Still, to check that cluster syncronization actually\nworks, let's deploy a `ConfigMap`.\n\n\n- Create `kubernetes/test_config.yaml` with the following content:\n\n\n```yaml\n\napiVersion: v1\n\nkind: ConfigMap\n\nmetadata:\n  name: gitlab-gitops\n  namespace: default\ndata:\n  key: It works!\n```\n\n\n- Modify your Agent configuration file under\n`.gitlab/demo-agent/config.yaml`, and add the following to it:\n\n\n```yaml\n\ngitops:\n  # Manifest projects are watched by the agent. Whenever a project changes,\n  # GitLab deploys the changes using the agent.\n  manifest_projects:\n  - id: path/to/your/project\n    default_namespace: gitlab-agent\n    # Paths inside of the repository to scan for manifest files.\n    # Directories with names starting with a dot are ignored.\n    paths:\n    - glob: 'kubernetes/test_config.yaml'\n    #- glob: 'kubernetes/**/*.yaml'\n```\n\n\nChange the `- id: path/to/your/project` line above to point to your\nproject's path!\n\n\nThe above configuration tells the Agent to kepp the\n`kubernetes/test_config.yaml` file in sync with the cluster. I've left a\ncommented line at the end to show how you could use wildcards. This will\ncome handy in future steps of this article. The`default_namespace` is used\nif no namespace is provided in the Kuberentes manifests. There are many\nother options to configure as well even for the `gitops` use case. You can\nread more about these in [the configuration file reference\ndocumentation](https://docs.gitlab.com/ee/user/clusters/agent/work_with_agent.html).\n\n\nOnce you commit the above changes, GitLab notifies `agentk` about the\nchanged files. First, `agentk` updates its configuration; second, it\nretrieves the `ConfigMap`.\n\n\nWait a few seconds, and run `kubectl describe configmap gitlab-gitops` to\ncheck that the changes got appliedd to your cluster. You should see\nsomething similar:\n\n\n```\n\nName:         gitlab-gitops\n\nNamespace:    default\n\nLabels:       \u003Cnone>\n\nAnnotations:  config.k8s.io/owning-inventory: 502-28431043\n              k8s-agent.gitlab.com/managed-object: managed\n\nData\n\n====\n\nkey:\n",[1040,9,1161],{"slug":1892,"featured":6,"template":696},"gitops-with-gitlab-connecting-the-cluster","content:en-us:blog:gitops-with-gitlab-connecting-the-cluster.yml","Gitops With Gitlab Connecting The Cluster","en-us/blog/gitops-with-gitlab-connecting-the-cluster.yml","en-us/blog/gitops-with-gitlab-connecting-the-cluster",{"_path":1898,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1899,"content":1905,"config":1910,"_id":1912,"_type":13,"title":1913,"_source":15,"_file":1914,"_stem":1915,"_extension":18},"/en-us/blog/gke-gitlab-integration",{"title":1900,"description":1901,"ogTitle":1900,"ogDescription":1901,"noIndex":6,"ogImage":1902,"ogUrl":1903,"ogSiteName":683,"ogType":684,"canonicalUrls":1903,"schema":1904},"GitLab + Google Cloud Platform = simplified, scalable deployment","We’ve teamed up with Google Cloud Platform – here’s what that means for you.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671280/Blog/Hero%20Images/gitlab-gke-integration-cover.png","https://about.gitlab.com/blog/gke-gitlab-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab + Google Cloud Platform = simplified, scalable deployment\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2018-04-05\",\n      }",{"title":1900,"description":1901,"authors":1906,"heroImage":1902,"date":1907,"body":1908,"category":298,"tags":1909},[1790],"2018-04-05","\n\nGet super-simple deployment for your app with GitLab and Google Cloud Platform (GCP): thanks to our integration with Google Kubernetes Engine (GKE), you can now get CI/CD and Kubernetes deployment set up with just a few clicks, and [$500 credit](#get-seamless-integration-with-gke-and-500-credit-for-your-project) to get you started.\n\n## Now everyone can get automatic code quality, security testing, and no-configuration deployment\n\nWith increasing adoption of [cloud native](/topics/cloud-native/) practices, the use of [microservices](/topics/microservices/) and containers has become critical to modern software development. Kubernetes has emerged as the first choice for container orchestration, allowing apps to scale elastically from a couple of users to millions. It's been possible to deploy to Kubernetes from GitLab for quite a while, but the process of setting up and managing everything was manual and time intensive.\n\nToday, we’re happy to announce we've been collaborating with Google to make Kubernetes easy to set up on GitLab. Now, with our native [Google Kubernetes Engine integration](/partners/technology-partners/google-cloud-platform/), you can automatically spin up a cluster to deploy applications, with just a few clicks. Simply connect your Google account, enter a few details, and you're good to go! GitLab will create the clusters for you. The clusters are fully managed by Google and run on Google Cloud Platform's best-in-class infrastructure.\n\nThis also means you can easily take advantage of GitLab [Auto DevOps](https://docs.gitlab.com/ee/topics/autodevops/). This feature does all the hard work for you, by automatically configuring CI/CD pipelines to build, test, and deploy your application. To make use of Auto DevOps, it used to be necessary to have an in-depth understanding of Kubernetes, and you had to manage your own clusters. Not any more!\n\nWith the integration between GitLab and GKE, we’ve made it simple to set up a managed deployment environment on Google Cloud Platform and access our robust [DevOps capabilities](/topics/devops/). That’s all the benefits of fully automated code quality, security testing, and deployment, with none of the headache of managing and updating your clusters (Google does that all for you!). More than half of developers and 78 percent of managers in our [2018 Global Developer Report](/developer-survey/) agreed that automating more of the software development lifecycle is a top priority for their organization. We hope that this integration gives you a head start, by offering automation out of the box with Kubernetes and Auto DevOps.\n\n## What’s next for GitLab?\n\nWe’re not just excited about offering this integration for you to use, we’re excited to use it ourselves! We’re already in the process of migrating GitLab.com to Google Cloud Platform. For us, the primary reason to migrate was because it has the most mature Kubernetes platform. By moving, we get access to security functionality like default encrypted data at rest, a broad, ever-expanding list of localities served globally, and tight integration with our existing CDN for faster caching. Be on the lookout for more information on our migration as it progresses.\n\n## Get seamless integration with GKE and $500 credit for your project\n\nEvery new Google Cloud Platform account receives $300 in credit [upon signup](https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral). In partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab’s GKE integration. Here's a link to [apply for your $200 credit](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form).\n\n## Join Google and GitLab for a live demo\n\nOn April 26th, join Google’s [William Denniss](https://www.linkedin.com/in/williamdenniss/) and GitLab’s [William Chia](https://www.linkedin.com/in/williamchia/) for a walkthrough of the new GKE integration. You’ll learn how easy it is to set up a Kubernetes cluster, how to deploy your app using GitLab CI/CD, and how GKE enables you to deploy, update, and manage containerized applications at scale.\n\n[Register today](/webcast/scalable-app-deploy/)!\n",[1447,741,9,1040,851],{"slug":1911,"featured":6,"template":696},"gke-gitlab-integration","content:en-us:blog:gke-gitlab-integration.yml","Gke Gitlab Integration","en-us/blog/gke-gitlab-integration.yml","en-us/blog/gke-gitlab-integration",{"_path":1917,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1918,"content":1924,"config":1929,"_id":1931,"_type":13,"title":1932,"_source":15,"_file":1933,"_stem":1934,"_extension":18},"/en-us/blog/gko-on-ocp",{"title":1919,"description":1920,"ogTitle":1919,"ogDescription":1920,"noIndex":6,"ogImage":1921,"ogUrl":1922,"ogSiteName":683,"ogType":684,"canonicalUrls":1922,"schema":1923},"How to install and use the GitLab Kubernetes Operator","Follow these step-by-step instructions to set up the GitLab Kubernetes Operator on a Kubernetes cluster.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682191/Blog/Hero%20Images/GKO-Thumbnail.png","https://about.gitlab.com/blog/gko-on-ocp","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to install and use the GitLab Kubernetes Operator\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Cesar Saavedra\"}],\n        \"datePublished\": \"2021-11-16\",\n      }",{"title":1919,"description":1920,"authors":1925,"heroImage":1921,"date":1926,"body":1927,"category":739,"tags":1928},[1565],"2021-11-16","\n\nThe GitLab Kubernetes Operator was released on October 12, 2021.\n\n## What is the GitLab Kubernetes Operator?\n\nThe GitLab Operator allows you to install and run an instance of GitLab in a vanilla Kubernetes or OpenShift cluster. Kubernetes operators increase the reliability and availability of your applications by automating Day 2 operations such as upgrading components, management of data integrity, application reconfiguration, automatic recovery from a failure, and autoscaling.\n\n## Installing the GitLab Kubernetes Operator on an OpenShift Container Platform cluster\n\nIn this short post, we show you how to install and run the GitLab Operator to create a GitLab instance on an OpenShift Container Platform cluster, which we have already preinstalled:\n\n![OCP console](https://about.gitlab.com/images/blogimages/gko-on-ocp/0-ocp-console.png){: .shadow.medium.center.wrap-text}\nThe OpenShift Container Platform console\n{: .note.text-center}\n\nInspecting the running pods of the OpenShift cluster, we see that Prometheus is already being used as the metrics server, which is a prerequisite for the installation of the GitLab Operator:\n\n![Prometheus up and running](https://about.gitlab.com/images/blogimages/gko-on-ocp/1-prometheus-up.png){: .shadow.medium.center.wrap-text}\nPrometheus up and running on cluster\n{: .note.text-center}\n\nAlso, we verify that the gitlab-system namespace does not yet exist:\n\n![gitlab namespace not present](https://about.gitlab.com/images/blogimages/gko-on-ocp/2-no-gitlab-sys-namespace.png){: .shadow.medium.center.wrap-text}\ngitlab-system namespace non-existent\n{: .note.text-center}\n\nAnother prerequisite is cert-manager, which automates the management and issuance of TLS certificates. Let’s use the OpenShift OperatorHub to install and instantiate an instance of cert-manager. We first verify that one is not running. Then we head to the OperatorHub and install the cert-manager Operator:\n\n![cert-manager in OperatorHub](https://about.gitlab.com/images/blogimages/gko-on-ocp/3-cert-mgr-in-operatorhub.png){: .shadow.medium.center.wrap-text}\nInstalling cert-manager using its operator in OperatorHub\n{: .note.text-center}\n\n**NOTE:** Once the GitLab Kubernetes Operator is certified with OpenShift, it will have its own tile in the OperatorHub.\n{: .alert .alert-info}\n\nThen we create an instance of cert-manager by using its newly installed operator:\n\n![cert-manager instance creation](https://about.gitlab.com/images/blogimages/gko-on-ocp/4-create-instance-cert-mgr.png){: .shadow.medium.center.wrap-text}\nCreating an instance of cert-manager using its operator\n{: .note.text-center}\n\nIn preparation of the GitLab Operator installation, we create the namespace gitlab-system, under which all of the GitLab resources will be:\n\n![gitlab-system namespace creation](https://about.gitlab.com/images/blogimages/gko-on-ocp/5-create-gitlab-sys-namespace.png){: .shadow.medium.center.wrap-text}\nCreating the gitlab-system namespace\n{: .note.text-center}\n\nTo install the GitLab Operator, we define two environment variables: one is to set the version of the GitLab Operator we want to use and the other one is to set the platform for which we are targeting the Operator. In this case, it is OpenShift. We then apply the GitLab Operator Custom Resource Definition or CRD to the cluster, which creates the operator, by entering the following command:\n\n```\nexport GL_OPERATOR_VERSION=\"0.1.0\" \nexport PLATFORM=\"openshift\"\nkubectl apply -f https://gitlab.com/api/v4/projects/18899486/packages/generic/gitlab-operator/${GL_OPERATOR_VERSION}/gitlab-operator-${PLATFORM}-${GL_OPERATOR_VERSION}.yaml\n```\n\nAnd here's is an example screenshot of what the output of this command would be like:\n\n![application of the CRD to the cluster](https://about.gitlab.com/images/blogimages/gko-on-ocp/6-applying-the-crd.png){: .shadow.medium.center.wrap-text}\nApplying the GitLab Kubernetes Operator to the OpenShift cluster\n{: .note.text-center}\n\nAs we watch the pods in the gitlab-system namespace, we see the creation of two pods for the gitlab-controller-manager:\n\n![operator pods](https://about.gitlab.com/images/blogimages/gko-on-ocp/7-watching-operator-pods-creation.png){: .shadow.medium.center.wrap-text}\nGitLab Kubernetes Operator pods being created on the OpenShift cluster\n{: .note.text-center}\n\nThe GitLab Kubernetes Operator is now installed on the OpenShift Container Platform cluster. Next, we need to use this newly installed operator to create an instance of GitLab.\n\n## Creating a GitLab instance on the cluster using the GitLab Kubernetes Operator\n\nTo create an instance of GitLab, we create a Custom Resource file called mygitlab.yaml to provide information, such as domain name and certmanager issuer email, for the GitLab Operator to use during the creation of the GitLab instance. Here is a parameterized example of the contents for this file:\n\n```\napiVersion: apps.gitlab.com/v1beta1\nkind: GitLab\nmetadata:\n  name: gitlab\nspec:\n  chart:\n    version: \"[REPLACE WITH THE CHART VERSION]\"\n    values:\n      global:\n        hosts:\n          domain: [REPLACE WITH YOUR DOMAIN NAME]\n        ingress:\n          configureCertmanager: true\n      certmanager-issuer:\n        email: [REPLACE WITH YOUR EMAIL]\n```\n\nAnd here is an example screenshot of what this file would look like with actual values for the parameters:\n\n![creating-gitlab-yaml-file](https://about.gitlab.com/images/blogimages/gko-on-ocp/8-creating-mygitlab-yaml.png){: .shadow.small.center.wrap-text}\nCreating mygitlab.yaml, the custom resource file\n{: .note.text-center}\n\nWe then apply the Custom Resource to the cluster. This action will kickstart the creation of all the pods needed for the instantiation of a GitLab instance on the cluster:\n\n![applying the custom resource to the cluster](https://about.gitlab.com/images/blogimages/gko-on-ocp/9-applying-the-cr.png){: .shadow.medium.center.wrap-text}\nApplying the custom resource file to the cluster\n{: .note.text-center}\n\nAfter a few minutes, when the GitLab instance is up and running, we obtain its external IP address from the nginx ingress controller installed by the GitLab Operator by entering the following command:\n\n> kubectl -n gitlab-system get services -o wide gitlab-nginx-ingress-controller\n\nHere's an example screenshot of its output:\n\n![getting the external ip](https://about.gitlab.com/images/blogimages/gko-on-ocp/10-get-external-ip.png){: .shadow.medium.center.wrap-text}\nObtaining the external IP address for our newly created GitLab instance\n{: .note.text-center}\n\nWe use this IP address to create DNS A records to map the DNS names of three (minio, registry, and gitlab) of the GitLab instance subsystems to it. Here is a snapshot for the gitlab one (you need to do the same for the minio and registry subsystems):\n\n![creating dns record](https://about.gitlab.com/images/blogimages/gko-on-ocp/11-creating-dns-record.png){: .shadow.medium.center.wrap-text}\nCreating DNS A record for the gitlab subsystem\n{: .note.text-center}\n\n**NOTE:** I owned the domain ocpgitlab.com. You would use a domain that you own.\n{: .alert .alert-info}\n\n## Logging in to the newly created instance running on the OpenShift Container Platform cluster\n\nBefore logging in to our newly created GitLab instance running on OpenShift Container Platform, we need to obtain the initial root password, which is a secret stored under the gitlab-system namespace. You obtain the initial root password for the newly created GitLab instance by entering the following command:\n\n> kubectl -n gitlab-system get secret gitlab-gitlab-initial-root-password -ojsonpath='{.data.password}' \\| base64 --decode ; echo\n\nAt this moment, we can point our browser to our newly created GitLab instance on OpenShift and login as root:\n\n![logging in to GitLab](https://about.gitlab.com/images/blogimages/gko-on-ocp/13-log-in-to-gitlab.png){: .shadow.medium.center.wrap-text}\nLogging in to the newly created GitLab instance running on the OpenShift Container Platform cluster\n{: .note.text-center}\n\nThat’s it!\n\n## Conclusion\n\nWe have shown you how to install and run the GitLab Operator to create a GitLab instance on an OpenShift Container Platform cluster. View [this demo](https://youtu.be/sEBnuhzYD2I) to see how this feature works.\n\n## Read more on Kubernetes\n\n- [Threat modeling the Kubernetes Agent: from MVC to continuous improvement](/blog/threat-modeling-kubernetes-agent/)\n\n- [How to deploy the GitLab Agent for Kubernetes with limited permissions](/blog/setting-up-the-k-agent/)\n\n- [A new era of Kubernetes integrations on GitLab.com](/blog/gitlab-kubernetes-agent-on-gitlab-com/)\n\n- [Understand Kubernetes terminology from namespaces to pods](/blog/kubernetes-terminology/)\n\n- [What we learned after a year of GitLab.com on Kubernetes](/blog/year-of-kubernetes/)\n\n",[1040,742,9],{"slug":1930,"featured":6,"template":696},"gko-on-ocp","content:en-us:blog:gko-on-ocp.yml","Gko On Ocp","en-us/blog/gko-on-ocp.yml","en-us/blog/gko-on-ocp",{"_path":1936,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1937,"content":1943,"config":1949,"_id":1951,"_type":13,"title":1952,"_source":15,"_file":1953,"_stem":1954,"_extension":18},"/en-us/blog/google-cloud-integrations-for-secure-cloud-run-deployments-at-gitlab",{"title":1938,"description":1939,"ogTitle":1938,"ogDescription":1939,"noIndex":6,"ogImage":1940,"ogUrl":1941,"ogSiteName":683,"ogType":684,"canonicalUrls":1941,"schema":1942},"Google Cloud integrations for secure Cloud Run deployments at GitLab","This tutorial demonstrates how to use GitLab’s Google Artifact Management integration to deploy to Google Cloud Run, a serverless runtime for containers application.\n","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099336/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945_fJKX41PJHKCfSOWw4xQxm_1750099336757.png","https://about.gitlab.com/blog/google-cloud-integrations-for-secure-cloud-run-deployments-at-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Google Cloud integrations for secure Cloud Run deployments at GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Regnard Raquedan\"},{\"@type\":\"Person\",\"name\":\"Matt Genelin\"}],\n        \"datePublished\": \"2025-01-15\",\n      }",{"title":1938,"description":1939,"authors":1944,"heroImage":1940,"date":1946,"body":1947,"category":1019,"tags":1948},[1365,1945],"Matt Genelin","2025-01-15","*This tutorial is from a recent Arctiq, GitLab, and Google in-person\nworkshop. The goal was to explore common security challenges faced by\norganizations as they journey to the cloud.*\n\n\nThis tutorial will help you learn about the [Google Cloud integrations in\nGitLab](https://cloud.google.com/docs/gitlab). These features are meant to\nhelp accelerate and improve security of deployments to Google Cloud.\n\n\n![Google integrations\nlist](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750099345/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750099345112.png)\n\n\n## Prerequisites\n\n\n1. [Google Cloud\nproject](https://cloud.google.com/resource-manager/docs/creating-managing-projects)  \n\n2. Appropriate [IAM permissions](https://cloud.google.com/iam/docs/) for\nsecurity, Artifact Registry, and Cloud Run usage. For this tutorial, ensure\nyou have the \"Owner\" role with the aforementioned project.\n\n\n## Setting up Workload Identity Federation\n\n\nIn this step, we configure GitLab to connect Google Cloud's Workload\nIdentity Federation to reduce the need for service accounts and let the two\nplatforms use short-lived credentials on-demand.\n\n\n1. On the left sidebar, select **Search** or go to and find your group or\nproject. If you configure this in a group, settings apply to all projects\nwithin by default.  \n\n2. Select **Settings \\> Integrations**.  \n\n3. Select **Google Cloud IAM**.  \n\n4. Input the Project ID and Project number in the respective fields. This\ninformation can be obtained from the Google Cloud console\n[Welcome](https://console.cloud.google.com/welcome) page of your project.  \n\n5. Input the desired Pool ID and Provider ID in the respective fields. These\nare values that you provide and must be unique from other Pool and Provider\nIDs.  \n\n6. Copy the generated command and then go to the **Google Cloud console**.  \n\n7. Run **Cloud Shell** and execute the generated command from the Workload\nIdentity Federation integration page.  \n\n8. Once successful, the **Google Cloud IAM** integration will be designated\nas active in the Integrations list at the GitLab project.\n\n\n## Artifact Registry configuration\n\n\nAs an alternative to GitLab's own place to host artifacts, deploying to\nGoogle Cloud's Artifact Registry is another way to leverage their\ninfrastructure. This section will provide steps on how to use GitLab's\nnative integration with Artifact Registry. Note that Workload Identity\nFederation must already be configured prior to this.\n\n\n1. At the **Google Cloud** console, go to **Artifact Registry** via search\nor the main navigation.  \n\n2. Create a new repository by clicking the **\"+\"** icon. At the creation\npage, provide a name and keep the **Docker** format and **Standard** mode\nselected. Select **Region** and choose **us-central1**. Leave the rest at\nthe default settings and click **Create**.  \n\n3. Once the repository is created and confirmed, go back to your GitLab\nproject.  \n\n4. In your GitLab project, on the left sidebar, select **Settings >\nIntegrations**. Then select **Google Artifact Registry**.  \n\n5. Under Enable integration, select the **Active** checkbox, then complete\nthe fields:  \n   * Google Cloud project ID: The ID of the Google Cloud project where your Artifact Registry repository is located.  \n   * Repository name: The name of your Artifact Registry repository.  \n   * Repository location: The location of your Artifact Registry repository. (`us-central1` is assumed.)  \n6. In **Configure Google Cloud IAM policies**, follow the onscreen\ninstructions to set up the IAM policies in Google Cloud. These policies are\nrequired to use the Artifact Registry repository in your GitLab project.\nSelect **Save** changes.  \n\n7. To view your Google Cloud artifacts, on the left sidebar, select **Deploy\n> Google Artifact Registry**.\n\n\n## Cloud Run configuration\n\n\n1. Enable the Cloud Run API, if not done already. Go to **APIs & Services >\nEnabled APIs & Services**. From there, click **Enable APIs & Services** at\nthe top and search for **Cloud Run Admin API**. Select the search result and\nenable the API.  \n\n2. Configure the IAM policies in Google Cloud to grant permissions to allow\nthe Cloud Run CI/CD component to deploy to Cloud Run.\n\n\n```\n\nGCP_PROJECT_ID=\"\u003CPROJECT ID>\"\n\nGCP_PROJECT_NUMBER=\"\u003CPROJECT NUMBER>\"\n\nGCP_WORKLOAD_IDENTITY_POOL=\"\u003CPOOL ID>\"\n\n\ngcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} \\\n  --member=\"principalSet://iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${GCP_WORKLOAD_IDENTITY_POOL}/attribute.developer_access/true\" \\\n  --role='roles/run.admin'\n\ngcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} \\\n  --member=\"principalSet://iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${GCP_WORKLOAD_IDENTITY_POOL}/attribute.developer_access/true\" \\\n  --role='roles/iam.serviceAccountUser'\n\ngcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} \\\n  --member=\"principalSet://iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${GCP_WORKLOAD_IDENTITY_POOL}/attribute.developer_access/true\" \\\n  --role='roles/cloudbuild.builds.editor'\n```\n\n\n## Deploy to Cloud Run\n\n\nIn this section, you will use Gitlab's CI/CD components to deploy to Cloud\nRun, Google Cloud's serverless runtime for containers.\n\n\n1. Go to the GitLab project and from the list of files in the source code,\nfind `.gitlab-ci.yaml`. Click the **file name** and the single file editor\nwill show up. Click the **Edit** button and select the **Open in Web IDE**\noption.  \n\n2. In Web IDE, copy-paste the following code:\n\n\n```\n\nstages:\n    - build\n    - upload\n    - deploy\n```\n\n\nThis code snippet sets up three stages in the pipeline: build, upload, and\ndeploy.\n\n\n1. The next step is to create two CI/CD variables in the same YAML file:\n\n\n```\n\nvariables:\n    GITLAB_IMAGE: $CI_REGISTRY_IMAGE/main:$CI_COMMIT_SHORT_SHA\n    AR_IMAGE: $GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_LOCATION-docker.pkg.dev/$GOOGLE_ARTIFACT_REGISTRY_PROJECT_ID/$GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_NAME/main:$CI_COMMIT_SHORT_SHA\n```\n\n\nThe first variable, `GITLAB\\_IMAGE`, denotes the container image that the\npipeline creates by default. The second one, `AR\\_IMAGE`, denotes the\nlocation at Google Cloud's Artifact Registry where the container image will\nbe pushed to.\n\n\n2. Next, define the code that will build the container image:\n\n\n```\n\nbuild:\n    image: docker:24.0.5\n    stage: build\n    services:\n        - docker:24.0.5-dind\n    before_script:\n        - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    script:\n        - docker build -t $GITLAB_IMAGE .\n        - docker push $GITLAB_IMAGE\n```\n\n\nThis code uses [pre-defined CI/CD\nvariables](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)\nfor the Docker commands.\n\n\n3. The final step is using two CI/CD components to deploy to Google Cloud.\nThe first component integrates with Artifact Registry and the second is the\ndeployment to Cloud Run:\n\n\n```\n\ninclude:\n    - component: gitlab.com/google-gitlab-components/artifact-registry/upload-artifact-registry@main\n      inputs:\n        stage: upload\n        source: $GITLAB_IMAGE\n        target: $AR_IMAGE\n\n    - component: gitlab.com/google-gitlab-components/cloud-run/deploy-cloud-run@main\n      inputs:\n        stage: deploy\n        project_id: \"\u003CPROJECT_ID>\"\n        service: \"tanuki-racing\"\n        region: \"\u003CREGION>\"\n        image: $AR_IMAGE\n```\n\n\nReplace \u003CPROJECT_ID> with your Google Cloud Project ID. Replace with the\n[Google Cloud region](https://cloud.google.com/compute/docs/regions-zones)\nmost appropriate to your location. `us-central1` is assumed.\n\n\nCommit the changes and push to the main branch. For reference, the final\n`.gitlab-ci.yaml` should look like this, noting to replace the \u003CPROJECT ID>\nand \u003CREGION> with the appropriate values:\n\n\n```\n\nstages:\n    - build\n    - upload\n    - deploy\nvariables:\n    GITLAB_IMAGE: $CI_REGISTRY_IMAGE/main:$CI_COMMIT_SHORT_SHA\n    AR_IMAGE: $GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_LOCATION-docker.pkg.dev/$GOOGLE_ARTIFACT_REGISTRY_PROJECT_ID/$GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_NAME/main:$CI_COMMIT_SHORT_SHA\n\nbuild:\n    image: docker:24.0.5\n    stage: build\n    services:\n        - docker:24.0.5-dind\n    before_script:\n        - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY\n    script:\n        - docker build -t $GITLAB_IMAGE .\n        - docker push $GITLAB_IMAGE\n\ninclude:\n    - component: gitlab.com/google-gitlab-components/artifact-registry/upload-artifact-registry@main\n      inputs:\n        stage: upload\n        source: $GITLAB_IMAGE\n        target: $AR_IMAGE\n\n    - component: gitlab.com/google-gitlab-components/cloud-run/deploy-cloud-run@main\n      inputs:\n        stage: deploy\n        project_id: \"\u003CPROJECT_ID>\"\n        service: \"tanuki-racing\"\n        region: \"\u003CREGION>\"\n        image: $AR_IMAGE\n```\n\n\n1. Go back to the main GitLab project and view the pipeline that was just\ninitiated. Take note of the stages that should be the same stages that were\ndefined in Step 2.  \n\n2. Once the pipeline is complete, go to the Google Cloud console and then\n**Cloud Run** via search or navigation. A new Cloud Run service called\n`tanuki-racing` should be created.  \n\n3. Click the **service name** and then go to the **Security** tab. Ensure\nthat the service is set to **Allow unauthenticated invocations**. This will\nmake the deployed app publicly available. The app URL posted on screen is\nnow available and should open a new browser tab when clicked.\n\n\nBy utilizing GitLab’s CI/CD pipelines to build and push a containerized\napplication to Google Artifact Registry, you can see the power of GitLab’s\nAI-powered DevSecOps Platform as a means to building secure applications.\nGitLab also deployed the containerized application to Google’s Cloud Run as\na low-cost running application on the public internet. Using GitLab to\ninstrument building an application, pushing a container and triggering a\ncloud run deployment allows DevOps engineers to have the assurance that\nsecure applications are being run on the public-facing internet.\n\n\n> [Sign up for a free trial of GitLab\nUltimate](https://about.gitlab.com/free-trial/devsecops/) to begin working\nwith these integrations. Also, check out our [solutions architecture\narea](https://about.gitlab.com/blog/tags/solutions-architecture/) for more\nGitlab and Google Cloud tutorials.\n",[9,741,1447,807,998],{"slug":1950,"featured":6,"template":696},"google-cloud-integrations-for-secure-cloud-run-deployments-at-gitlab","content:en-us:blog:google-cloud-integrations-for-secure-cloud-run-deployments-at-gitlab.yml","Google Cloud Integrations For Secure Cloud Run Deployments At Gitlab","en-us/blog/google-cloud-integrations-for-secure-cloud-run-deployments-at-gitlab.yml","en-us/blog/google-cloud-integrations-for-secure-cloud-run-deployments-at-gitlab",{"_path":1956,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1957,"content":1962,"config":1969,"_id":1971,"_type":13,"title":1972,"_source":15,"_file":1973,"_stem":1974,"_extension":18},"/en-us/blog/google-gitlab-serverless-webinar",{"title":1958,"description":1959,"ogTitle":1958,"ogDescription":1959,"noIndex":6,"ogImage":1764,"ogUrl":1960,"ogSiteName":683,"ogType":684,"canonicalUrls":1960,"schema":1961},"Container apps on serverless: Write once, deploy anywhere","Containers, serverless, and microservices, oh my! Cut to the chase and learn how to write apps once and deploy anywhere with emerging technologies.","https://about.gitlab.com/blog/google-gitlab-serverless-webinar","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Write once, deploy anywhere: Containerized applications on modern serverless platforms\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tina Sturgis\"}],\n        \"datePublished\": \"2019-06-13\",\n      }",{"title":1963,"description":1959,"authors":1964,"heroImage":1764,"date":1966,"body":1967,"category":298,"tags":1968},"Write once, deploy anywhere: Containerized applications on modern serverless platforms",[1965],"Tina Sturgis","2019-06-13","\n\nUsing containers has become standard practice in app development today. We all get the value of why you want to build with containers. But as a developer, why should you care about [serverless](/topics/serverless/)? It’s simple, you can eliminate worry about the infrastructure that your app is going to run on and focus on the impact of the app itself. Specifically the business logic of how the app will interact with things like the end users and/or operating systems.\n\nThe concepts of serverless quickly move the conversation towards one around a microservices architecture. As we move away from building applications in a monolith, moving towards serverless and eliminating the need to worry about that infrastructure begin to make a lot more sense.\n\nSo now, how do we take these concepts that we hear and/or read about that increase velocity, flexibility, and scalability, and put them into action for your own application development?\n\nFind out at our webinar, \"Running containerized applications on modern serverless platforms\" on Jun. 25, 2019 with GitLab and Google experts. We'll take a deep dive into how new and emerging technologies like Kubernetes, Knative, Cloud Run, and GitLab Serverless can provide great stability and scalability while lowering costs and increasing the pace of innovation.\n\n[Reserve your spot.](https://webinars.devops.com/running-containerized-applications-on-modern-serverless-platforms)\n{: .alert .alert-gitlab-purple .text-center}\n",[741,851,9,108,1040],{"slug":1970,"featured":6,"template":696},"google-gitlab-serverless-webinar","content:en-us:blog:google-gitlab-serverless-webinar.yml","Google Gitlab Serverless Webinar","en-us/blog/google-gitlab-serverless-webinar.yml","en-us/blog/google-gitlab-serverless-webinar",{"_path":1976,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1977,"content":1983,"config":1990,"_id":1992,"_type":13,"title":1993,"_source":15,"_file":1994,"_stem":1995,"_extension":18},"/en-us/blog/google-next-post",{"title":1978,"description":1979,"ogTitle":1978,"ogDescription":1979,"noIndex":6,"ogImage":1980,"ogUrl":1981,"ogSiteName":683,"ogType":684,"canonicalUrls":1981,"schema":1982},"What to check out at Google Cloud Next 2019","Support women who code by stopping by our booth, learn from a host of GitLab experts, and more.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679235/Blog/Hero%20Images/cloud-native-predictions-2019.jpg","https://about.gitlab.com/blog/google-next-post","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"What to check out at Google Cloud Next 2019\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mayank Tahilramani\"}],\n        \"datePublished\": \"2019-04-04\",\n      }",{"title":1978,"description":1979,"authors":1984,"heroImage":1980,"date":1985,"body":1986,"category":298,"tags":1987},[1769],"2019-04-04","\n\nIt’s that time of the year to indulge in all things innovative and new at Google Cloud Next 2019.\nAs an attendee last year, I was excited to learn about Google’s vision on ‘bringing the cloud to you’\nwith a focus on hybrid cloud and unveiling of GKE On-Prem. GitLab’s partnership with Google\nhas grown a lot since we launched our quick and easy [integration with GKE](/partners/technology-partners/google-cloud-platform/)\nlast year and we hope you will come out to see some of the new things we have going on.\n\n### Don't be shy, come say hi 👋\n\nCome visit us at our booth (#S1607), get scanned, and GitLab will donate $5 to your\ncharity of choice: [Rail Girls](http://railsgirls.com/) or [Django Girls](https://djangogirls.org/).\nThis also enters you for a chance to win an iPad Pro!\n\nWhile you're there, we would love to showcase and talk about:\n\n* GitLab’s [AutoDevOps](https://docs.gitlab.com/ee/topics/autodevops/) functionality.\n* Using GitLab to [secure your applications](/stages-devops-lifecycle/secure/).\n* How to get started with [GitLab for GCP on GKE](/partners/technology-partners/google-cloud-platform/) and GKE On-Prem.\n* GitLab [Serverless with Knative](/topics/serverless/) and [Cloud Run](https://cloud.google.com/blog/products/serverless/announcing-cloud-run-the-newest-member-of-our-serverless-compute-stack),\n* ... and much more!\n\n### Sit back, relax, and listen to some of our experts live\n\n* Check out [Brandon Jung](/company/team/#brandoncjung) (VP of Alliances) discuss [GitLab’s move from Azure to GCP](https://cloud.withgoogle.com/next/sf/sessions?session=ARC207) which includes a technical\noverview of the migration as well as lessons learned. Check out our customer case study [here](https://cloud.google.com/customers/gitlab/).\n\n* Come listen to [Kathy Wang](/company/team/#wangkathy) (Senior Director of Security) tell our journey [Towards Zero Trust at GitLab.com](https://cloud.withgoogle.com/next/sf/sessions?session=SEC220) along with key lessons learned. ([You can read more about the evolution of Zero Trust here](/blog/evolution-of-zero-trust/).)\n\n* Learn something new with [Daniel Gruesso](/company/team/#danielgruesso) (Product Manager) showcasing GitLab’s serverless functionality to [Run a consistent serverless platform anywhere with Kubernetes and Knative](https://cloud.withgoogle.com/next/sf/sessions?session=HYB218).\n\n### Get hands on with Qwiklabs\n\nLearn from [Dan Gordon](/company/team/#dbgordon) (Senior Technical Marketing Manager) at our [Spotlight Lab: Introduction to GitLab on GKE](https://cloud.withgoogle.com/next/sf/sessions?session=301353-133371). Here you will have the chance to deploy GitLab on GKE, migrate a GitHub repository into a GitLab Project, and set up a CI/CD pipeline with AutoDevOps to deploy your code to GKE.\n\nSo stop by and say hello!\n\nWe are proud to be a sponsor at this event and would love to see as many of you at our booth (S1607) to discuss GitLab [Serverless](/topics/serverless/) with Knative and Cloud Run, GitLab’s integration with GKE, GitLab AutoDevOps for CI/CD, Security functionalities, as well as GitLab’s support for GKE On-Prem.\n",[1988,1040,108,851,9,693,716,1989],"agile","testing",{"slug":1991,"featured":6,"template":696},"google-next-post","content:en-us:blog:google-next-post.yml","Google Next Post","en-us/blog/google-next-post.yml","en-us/blog/google-next-post",{"_path":1997,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":1998,"content":2003,"config":2009,"_id":2011,"_type":13,"title":2012,"_source":15,"_file":2013,"_stem":2014,"_extension":18},"/en-us/blog/gpg-key-for-gitlab-package-repositories-metadata-changing",{"title":1999,"description":2000,"ogTitle":1999,"ogDescription":2000,"noIndex":6,"ogImage":863,"ogUrl":2001,"ogSiteName":683,"ogType":684,"canonicalUrls":2001,"schema":2002},"The GPG key used to sign GitLab package repositories' metadata is changing","The GPG key used to sign repository metadata on GitLab's Packagecloud instance at packages.gitlab.com is changing – find out what this means for you.","https://about.gitlab.com/blog/gpg-key-for-gitlab-package-repositories-metadata-changing","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"The GPG key used to sign GitLab package repositories' metadata is changing\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Balasankar 'Balu' C\"}],\n        \"datePublished\": \"2020-03-30\",\n      }",{"title":1999,"description":2000,"authors":2004,"heroImage":863,"date":2006,"body":2007,"category":763,"tags":2008},[2005],"Balasankar 'Balu' C","2020-03-30","\n\nGitLab uses a [Packagecloud instance](https://packages.gitlab.com) to\ndistribute official [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab.git)\nand [gitlab-runner](https://gitlab.com/gitlab-org/gitlab-runner.git) packages.\nTo ensure integrity of packages shipped through this instance, the metadata of\nthe various apt and yum repositories managed in this instance are signed using\na GPG key, in addition to the packages themselves being signed by a separate key.\n\nThe current key used for the metadata signing, with the fingerprint `1A4C 919D B987 D435 9396 38B9 1421 9A96 E15E 78F`,\nis set to expire on Apr. 15, 2020. So, GitLab is rotating this GPG key in\nfavor of a newer one which will be active for another two years. The GPG\nfingerprint of this new key is `F640 3F65 44A3 8863 DAA0 B6E0 3F01 618A 5131 2F3F`.\nPlease check the [official documentation](https://docs.gitlab.com/omnibus/update/package_signatures#package-repository-metadata-signing-keys) for\nmore details on the key.\n\n## When will it be changed?\n\nThe key will be changed on **Apr. 6, 2020**.\n\n## What does this mean for existing users?\n\nAny existing users who have already configured these repositories in their\nmachines (using any method that uses packages.gitlab.com like the `curl` script mentioned in the [GitLab installation page](/install/)\nor [gitlab-runner installation docs](https://docs.gitlab.com/runner/install/linux-repository.html))\nwill be affected and will be unable to fetch packages from these repositories\nafter the key is changed until they install the new public key. This is because once the GPG key is changed, the\nmetadata will be signed with the new key, and because the user doesn't have the\ncorresponding public key, `apt`/`yum` will fail to verify the integrity of\nthese repositories and will not fetch packages from them.\n\n## What does this mean for new users?\n\nFor users who are configuring the repositories for the first time, the `curl` script to install\nrepositories will automatically fetch the new key – so new users who are\nconfiguring repositories for the first time after the switch are unaffected\nand do not need to do anything beyond following official installation docs.\n\n## What should I do?\n\nIf you have already configured GitLab repositories on your machine\nbefore Apr. 6, 2020, please check out the official documentation on\n[how to fetch and add the new key](https://docs.gitlab.com/omnibus/update/package_signatures#package-repository-metadata-signing-keys)\nto your machine. \n\nIf you are a new user, there is nothing specific for you to do\nother than follow the [GitLab installation page](https://about.gitlab.com/install/)\nor the [gitlab-runner installation docs](https://docs.gitlab.com/runner/install/linux-repository.html).\n\n## I still have problems, what do I do?\n\nPlease open an issue in the [omnibus-gitlab issue tracker](https://gitlab.com/gitlab-org/omnibus-gitlab/issues).\n",[9],{"slug":2010,"featured":6,"template":696},"gpg-key-for-gitlab-package-repositories-metadata-changing","content:en-us:blog:gpg-key-for-gitlab-package-repositories-metadata-changing.yml","Gpg Key For Gitlab Package Repositories Metadata Changing","en-us/blog/gpg-key-for-gitlab-package-repositories-metadata-changing.yml","en-us/blog/gpg-key-for-gitlab-package-repositories-metadata-changing",{"_path":2016,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2017,"content":2023,"config":2028,"_id":2030,"_type":13,"title":2031,"_source":15,"_file":2032,"_stem":2033,"_extension":18},"/en-us/blog/guide-to-rest-api",{"title":2018,"description":2019,"ogTitle":2018,"ogDescription":2019,"noIndex":6,"ogImage":2020,"ogUrl":2021,"ogSiteName":683,"ogType":684,"canonicalUrls":2021,"schema":2022},"Guide to REST API","Learn what REST API is, how it works, and what its benefit is in software development. Also find out the underlying principles of this important technology.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098516/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945_2N8JxZDeeDLlzrsJ4boteB_1750098516673.png","https://about.gitlab.com/blog/guide-to-rest-api","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Guide to REST API\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab\"}],\n        \"datePublished\": \"2024-10-18\",\n      }",{"title":2018,"description":2019,"authors":2024,"heroImage":2020,"date":2025,"body":2026,"category":739,"tags":2027},[889],"2024-10-18","Whether it's developing an online booking app, a mobile payment solution, or a messaging service, chances are your team is using a REST API. In this article, you'll learn what a REST API is and how it works, as well as its benefits and uses.\n\n## What is a REST API?\n\nREST API, RESTful API, or RESTful web API: These names designate APIs that adhere to a particular standard, which is the REST architecture. Before going any further, remember that an API, or application programming interface, is software that allows two applications to communicate with each other. In computing, APIs are essential to allow various applications to work together.\n\nTo create an API, developers follow strictly defined methods and principles, so that the whole can work. Before the 2000s, developers used [SOAP](https://www.techtarget.com/searchapparchitecture/definition/SOAP-Simple-Object-Access-Protocol) (Simple Object Access Protocol), a protocol built on XML (Extensible Markup Language), which was complex to coordinate and resource-intensive. While SOAP is still used today, it has been largely replaced by REST API.\n\nDesigned in 2000 by American computer scientist Roy Fielding during his doctoral thesis, REST (REpresentational State Transfer) has become the dominant model for creating APIs, and an essential milestone in the development of the World Wide Web. Today, the vast majority of APIs are based on REST, particularly to offer web, interactive, or mobile services. Let's find out how RESTful APIs work, their advantages, and their wide-ranging applications.\n\n## How does a REST API work?\n\nIn practice, the REST API works on the principle of the client-server environment. The RESTful API retrieves and transmits a user's or application's requests on one end and the information rendered by the server (application or database) on the other end.\n\nSome key concepts make it possible to understand how a RESTful API works. The client is the entity making a request. This is the case, for example, of a user searching within a product catalog on their browser. The API is responsible for communicating the request to the server, and returning the requested information to the client. The information that passes through the API is the resources. The server processes requests. In this case, it will return the list of products matching the search criteria.\n\nThe client's requests are made through the HTTP (Hypertext Transfer Protocol) protocol. Here are the main methods and tasks it enables you to accomplish:\n- GET: retrieve data sent by the server.\n- POST: send and publish information to the server (registration form data, for example).\n- PUT: update the server information.\n- PATCH: partially modify an existing resource.\n- DELETE: delete information from the server.\n\nThere are various data formats for using a REST API. The JSON (JavaScript Object Notation) format is a lightweight format, which is easy to understand and usable by many programming languages. XML makes it possible to manage complex data structures and is compatible with other standards such as RSS. YAML and HTML are other formats often used to communicate resources.\n\n## What are the principles of the REST API?\n\nA REST API follows the REST principles regarding software architecture. These principles create a guideline for creating flexible and lightweight APIs, which are perfectly adapted to data transmission over the internet.\n\nHere are the six architectural principles that govern a REST interface:\n- Client-server decoupling. The client only knows the URI (Uniform Resource Identifier) of the resource to be retrieved. The server interacts only by transmitting its data via HTTP.\n- Uniform interface. The REST architecture standardizes how information is identified, managed, and transmitted, and uses hyperlinks to bring additional resources to the client.\nCode on demand. The server can transmit code to the client to expand its functionality, such as to help identify errors in a form.\n- Layered system. A RESTful API can run on several servers organized hierarchically, to provide a more stable and efficient service to the client.\n- Cacheable. The REST server can cache data to better serve the client, for example by storing the images of a site to then serve them again.\n- Stateless. Each client request is stand-alone and processed independently by the server. Therefore, each request must contain all the elements necessary for its processing.\n\n## What are the benefits of a REST API?\n\nBy following the REST API framework requirements, developers make use of the many advantages of the RESTful API to develop effective and powerful applications:\n- Versatility: There are no restrictions on which programming language to use, and there is a wide selection of data formats (XML, PYTHON, JSON, HTML, etc.).\n- Lightweight: The lightweight data formats of a REST API make it ideal for mobile applications or the Internet of Things (IoT).\n- Portability: Client-server separation enables the exchange of data between platforms.\nFlexibility: This API does not have the complexities of a protocol since it is an architectural style.\n- Independence: Developers can work separately on the client or server part.\n\nThe benefits of the REST API translate into increased productivity and scalability for development teams. Scaling systems using REST API is easier. The features are therefore better able to support a large load of users and operations.\n\n## Security constraints\n\nCreating and managing a RESTful web API is not without challenges. User authentication can become complex when it uses several different methods, by HTTP, API keys, or OAuth (Open Authorization). On large and complex applications, the multiplication of endpoints between the server and the client can impair overall consistency, as can updates if they leave old touchpoints still active.\n\nAdditionally, the REST interface has a weakness because it transmits potentially sensitive data, such as identifiers, through the endpoint URL. Securing it requires specific measures such as Transport Layer Security (TLS) encryption, a robust user authentication model, and a system for managing malicious requests and limiting throughput.\n\n## Uses of a REST API\n\nDevelopers use APIs with the REST architecture to create and maintain many services. Therefore, most web and mobile applications use REST APIs to access and share resources and information. In the cloud, this API makes it possible to connect the services of distributed and hybrid architectures quickly. Within large companies, it enables interoperability between information system components.\n\nRefreshing an e-commerce site's prices, automating publications, orchestrating Kubernetes clusters, etc. The RESTful APIs' scope of use is limited only by the imagination of digital application developers and creators.\n\n## The GitLab REST API\n\nGitLab offers a comprehensive suite of tools and APIs for integrating and automating external applications. It includes GraphQL, webhooks, IDE extensions, and of course, a REST API. The GitLab REST API can be authenticated in many ways, such as by access token, OAuth, or session cookies. Endpoints are available for Dockerfile, .gitignore, GitLab CI/CD YAML, and open source templates. To take full advantage of all the possibilities for developing your agile and cloud-native applications, see the complete [GitLab REST API documentation](https://docs.gitlab.com/ee/api/rest/index.html).\n\n## REST API FAQs\n\n### REST vs. SOAP\n\nREST and SOAP are two API standards. REST (REpresentational State Transfer) API uses the REST architectural principles, which allow a server and a client to communicate in a lightweight and scalable way. The REST API is the most common type of API. The SOAP (Simple Object Access Protocol) protocol is older, more rigid, and only available in XML format. This old standard can still be used for applications that require a high level of security.\n\n### What is the difference between REST and REST API?\n\nREST is a style of software architecture intended to facilitate the creation of web services and the exchange of data over the internet, by ensuring interoperability between computers and servers. The RESTful web API is a type of API that is based on the main principles of REST.\n\n### What are the principles of a REST API?\n\nA REST API follows the six main principles of the REST architecture. These principles are uniform interface, code on demand, layered system, cacheable, stateless, and client-server decoupling. The latter principle forms the basis of the structure of a RESTful API; it is essential to the success of this API in the world of web applications.\n\n## Learn more\n- [GitLab Rest API documentation](https://docs.gitlab.com/ee/api/rest/)\n- [Extend with GitLab](https://docs.gitlab.com/ee/api/)",[9,851],{"slug":2029,"featured":6,"template":696},"guide-to-rest-api","content:en-us:blog:guide-to-rest-api.yml","Guide To Rest Api","en-us/blog/guide-to-rest-api.yml","en-us/blog/guide-to-rest-api",{"_path":2035,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2036,"content":2042,"config":2049,"_id":2051,"_type":13,"title":2052,"_source":15,"_file":2053,"_stem":2054,"_extension":18},"/en-us/blog/high-availability-git-storage-with-praefect",{"title":2037,"description":2038,"ogTitle":2037,"ogDescription":2038,"noIndex":6,"ogImage":2039,"ogUrl":2040,"ogSiteName":683,"ogType":684,"canonicalUrls":2040,"schema":2041},"Meet Praefect: The traffic manager making your Git data highly available","This router and transaction manager ensures there are multiple copies of each Git repository available in the event of an outage – no NFS required.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669204/Blog/Hero%20Images/traffic-intersection.jpg","https://about.gitlab.com/blog/high-availability-git-storage-with-praefect","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Meet Praefect: The traffic manager making your Git data highly available\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Zeger-Jan van de Weg\"}],\n        \"datePublished\": \"2021-01-21\",\n      }",{"title":2037,"description":2038,"authors":2043,"heroImage":2039,"date":2045,"body":2046,"category":739,"tags":2047},[2044],"Zeger-Jan van de Weg","2021-01-21","\nAs critical software projects grow, scaling infrastructure to make the service [highly available](https://en.wikipedia.org/wiki/High_availability) is key. At GitLab, our biggest struggle in scaling was right in our name: Git.\n\n## The trouble with scaling Git\n\nGit is software that is distributed, but not usually run in a ‘highly available cluster,’ which is what GitLab needs. At first, we solved this with a [boring solution](https://handbook.gitlab.com/handbook/values/#boring-solutions), NFS – which exposes a shared filesystem across multiple machines and generally worked. As we’d soon find out, most NFS appliances were for bulk storage and not fast enough. This led to problems with GitLab’s Git access being slow.\n\nTo solve the speed problem we built [Gitaly, our service that provides high-level RPC access to Git repositories](https://docs.gitlab.com/ee/administration/gitaly/). \n\nWhen we started with [Gitaly v1.0](/blog/the-road-to-gitaly-1-0/), our goal was to remove the need for a network-attached filesystem access for Git data. When that was complete, the next problem to tackle was that all your data is only stored once. So, if you have a server down, or your hard disk dies, or something happens to this one copy, you're in deep trouble until a backup is restored. This is an issue for GitLab.com, but it’s also a big risk for our customers and community.\n\nBack at our [Summit in Cape Town](/company/culture/contribute/previous/#summit-in-cape-town-south-africa) in 2018, the Gitaly team (at the time, that was [Jacob Vosmaer](/company/team/?department=all#jacobvosmaer-gitlab) and me) and some other engineers discussed pursuing a fault-tolerant, highly available system for Git data. For about a month we went back and forth about how we would go about it – ranging from wild ideas to smaller iterations towards what we want. The challenge here was that the ultimate aim is always going to be 100% availability, but you’re never going to make that. So let's aim for a lot of nines (three nines being 99.9%, five being 99.999%, etc.) Ideally, we'd be able to iterate to 10 nines if we wanted to. \n\nEventually we chose the design of a proxy: introduce a new component in the GitLab architecture, which is Praefect, and then route all the traffic through it to Gitaly storage nodes to provide a [Gitaly Cluster](https://docs.gitlab.com/ee/administration/gitaly/praefect.html). Praefect inspects the request and tries to route it to the right Gitaly backend, checks that Gitaly is up, makes sure the copies of your data are up to date, and so on. \n\n## First iteration: Eventual consistency\n\nTo cut the scope, for our first iterations we settled on eventual consistency, which is fairly common – we even use it for some GitLab features. With Git data, if we are behind a minute, it's not a big deal because at GitLab at least 90% of operations on our Git data are just reads, compared to a very small volume of writes. If I run `git pull` and I'm one commit behind master, that's not ideal, but not a deal breaker in most cases. \n\nWith eventual consistency, each repository gets three copies: one primary and two secondary. We replicate your data from the primary to the other copies, so that if your primary is inaccessible, we can at least give you read access to the secondary copies until we recover the primary. There’s a chance the secondaries are one or two commits behind your primary, but it’s better than no access.\n\nWe rolled this out in [13.0](/releases/2020/05/22/gitlab-13-0-released/#gitaly-cluster-for-high-availability-git-storage) as generally available. \n\n## Strong consistency\n\nThe next stage was to work on strong consistency, where all of your three copies are always up to date. \n\nWhen you write to your Git repository, there’s a moment where Praefect says, “OK, I'm going to update branch A from #abc to #cbd.” If all three copies agree on the updates, then Praefect tells everyone to apply this update and now, almost at the same moment in time, they'll update the data to the same thing. Now you've got three copies that are up to date.\n\nSo, if one copy is offline for some reason – let’s say a network partition, or the disk is corrupted – we can serve from the other two copies. Then the data remains available, and you have more time to recover the third copy as an admin. Effectively, while you always have a designated primary, it's actually more like having _three_ primaries, because they are all in the same state. \n\nIf the default state of a system is consistent it requires maintaining this consistency on each mutation to the data that's performed. All possible requests to Gitaly are grouped into two classes: mutators and accessors. Meaning that there was a risk we had to migrate each mutator RPC individually. That would've been a major effort, and if possible, we wanted to push this problem to Git. Gitaly uses Git for the majority of write operations, and was thus the largest common denominator.\n\nSo Git had to become aware of transactions, which ideally isn't part of Git. There are more areas where it would be nice if Git was aware of business logic, but if we're honest with ourselves, it's not really Git's concern: authentication and authorization. At GitLab we use [Git Hooks](https://git-scm.com/docs/githooks.html#_hooks) for that. So the idea [applied and contributed](https://public-inbox.org/git/1de96b96e3448c8f7e7974f7c082fd08d2d14e96.1592475610.git.ps@pks.im/T/#m9ae42f583968aa1d8ca43bd3007333cf51a618cc) (thanks, [Patrick Steinhardt](/company/team/#pks-gitlab)!) was the same: when events happen with Git, execute a hook and allow Gitaly to execute business logic. Through the exit code of the hook, Git is signaled on how to proceed. In Git, these events are updates of any reference (for example, branches or tags). When this happens Git will then allow Gitaly to participate in a [three-phase commit](https://en.wikipedia.org/wiki/Three-phase_commit_protocol) transaction by communicating back to Praefect, and enforce consistency. So we got that released in Git, fixed a bug, and now we’re [rolling it out to almost all write requests](https://gitlab.com/gitlab-org/git/-/issues/79).\n\n## A defensible cost increase\n\nNow strong consistency is great, but we are effectively asking our customers, “Instead of one copy, why don't you triple your storage costs and your server costs and whatnot, and you have zero benefits unless something goes wrong.” That wasn't really appealing for most customers, but now we’ve sweetened the deal with increased performance and making the cost increase more manageable. \n\nSo, if you have three copies of your data that are up to date, then all of them could serve any request that doesn't mutate the data, right? Because you know they're up to date. Right now, [Pavlo](/company/team/?department=gitaly-team#8bitlife) is working on [read distribution, which we are making generally available in 13.8](https://gitlab.com/gitlab-com/www-gitlab-com/-/merge_requests/71960) (coming Jan. 22, 2021). [We rolled it out briefly before](https://gitlab.com/gitlab-com/www-gitlab-com/-/merge_requests/58694), but it didn’t scale as expected, so we’ve worked with QA to mitigate that.\n\nRight now, Praefect is rolled out to a very limited subset of projects on GitLab.com, because running it is expensive already. When I first proposed rolling it out for everyone, it was very quick to calculate that that will triple our Gitaly Clusters – not within the budget at all! So we're trying to iterate towards that goal. The first step is to work on allowing a [variable replication factor](https://docs.gitlab.com/ee/administration/gitaly/praefect.html#variable-replication-factor). It can be expensive to store a lot of data multiple times, so why don't we make it so that you can store some repositories three times and some just one time, and you don't get the guarantees and the availability of those with three copies.\n\n## Challenges and lessons learned\n\nSo we have Praefect, this new component, but it's not installed by default on GitLab Omnibus –\nyou have to enable it yourself. The [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) uses it as well as the tests on GitLab.com, for GitLab projects, but that wasn’t always the case. When you have an optional part in your architecture, if you’re debugging or talking with customers, there is the additional mental burden of verifying what the architecture looks like. Without it, you can make much quicker assumptions on what's going on and why it's working or why it isn't. Officially, we have deprecated NFS, so it makes sense to make it a required component so we can depend on it being there.\n\nAlso, as we add more features to Praefect, if it’s still optional then some customers get those added benefits and some don’t.\n\n### We should have put it in production sooner\n\nOur first iteration was just proxying the traffic, doing nothing with it, and verifying that it works. We didn't put it in production because it offered nothing to the community. But, it includes new components in your architecture, which our SREs need to know about, and there were a couple of bugs we found out much later. I was hesitant to put something in production that didn't offer anything in return, but if we’d been a little more aggressive with putting it out there – even just for a small subset of projects – we would understand more quickly what we're running, what was working, and what wasn't. \n\n### Applying big architectural changes takes time\n\nIf you ask customers to make giant architectural changes, it's going to take longer than you think. When we released Praefect and Gitaly Clusters in 13.0, it was fairly rough around the edges and some things weren't working as you would expect, but it was a good time to release because now, six months later, we see customers finally starting to implement it. They want to validate, try it out on a subset, and then finally roll it out for their whole GitLab instance. While that took longer than I expected, it's cool to see the numbers going up now, and adoption is growing quite rapidly.\n\n## More than just a traffic manager\n\nPraefect does much more than just inspect the traffic. If Gitaly goes down, ideally you want to notice that before you actually fire a request, which Praefect does. It does failover, so if one fails and it was designated as a primary, then it fails over to a secondary, which is now designated as a primary. \n\nI'm really excited for the next few years and the kind of things we are planning to build in Praefect and what that will deliver to GitLab.com and our customers and community. Where before we didn’t have very granular control over what we were doing or why we were doing it, now we can intercept and optimize.\n\n## What's next\n\nWe're shipping [HA Distributed Reads](https://gitlab.com/gitlab-org/gitaly/-/issues/3334) in GitLab 13.8 (Jan. 22, 2021). For 13.9, we're shooting for [strong consistency in the Gitaly Cluster](https://gitlab.com/groups/gitlab-org/-/epics/1189) and [variable replication factor](https://gitlab.com/groups/gitlab-org/-/epics/3372).\n\nFor GitLab self-managed users, consider enabling Praefect if you have high availability requirements. Visit our [Gitaly Clusters documentation](https://docs.gitlab.com/ee/administration/gitaly/praefect.html) to get started.\n\n_Major thanks to [Rebecca Dodd](/company/team#rebecca) who contributed to this post._\n\nCover image by [Yoel J Gonzalez](https://unsplash.com/@yoeljgonzalez?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\") on [Unsplash](https://unsplash.com/s/photos/traffic?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText)\n{: .note}\n",[1989,2048,1161,9,693],"git",{"slug":2050,"featured":6,"template":696},"high-availability-git-storage-with-praefect","content:en-us:blog:high-availability-git-storage-with-praefect.yml","High Availability Git Storage With Praefect","en-us/blog/high-availability-git-storage-with-praefect.yml","en-us/blog/high-availability-git-storage-with-praefect",{"_path":2056,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2057,"content":2063,"config":2070,"_id":2072,"_type":13,"title":2073,"_source":15,"_file":2074,"_stem":2075,"_extension":18},"/en-us/blog/how-enterprise-dev-teams-use-gitlab-mattermost-chatops",{"title":2058,"description":2059,"ogTitle":2058,"ogDescription":2059,"noIndex":6,"ogImage":2060,"ogUrl":2061,"ogSiteName":683,"ogType":684,"canonicalUrls":2061,"schema":2062},"Teams speed development with GitLab & Mattermost ChatOps","A complete DevOps toolchain plus open source messaging and ChatOps – what’s not to love?","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680983/Blog/Hero%20Images/mattermost-gitlab.png","https://about.gitlab.com/blog/how-enterprise-dev-teams-use-gitlab-mattermost-chatops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How enterprise dev teams use GitLab and Mattermost ChatOps to accelerate development\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jason Blais – Mattermost\"}],\n        \"datePublished\": \"2020-01-13\",\n      }",{"title":2064,"description":2059,"authors":2065,"heroImage":2060,"date":2067,"body":2068,"category":691,"tags":2069},"How enterprise dev teams use GitLab and Mattermost ChatOps to accelerate development",[2066],"Jason Blais – Mattermost","2020-01-13","\n\nThere has never been more pressure on development teams to build software faster and more efficiently. The rise in popularity of DevOps has largely been the result of its promise to speed up dev cycles, increase agility, and help teams resolve issues more quickly. And while the availability and sophistication of DevOps tools have improved greatly in the last few years, simply choosing the latest and greatest tools is no guarantee of a smooth, problem-free development lifecycle.\n\n## Why GitLab\n\nIn an ecosystem with exponentially increasing choice and complexity, GitLab provides a complete open source [DevOps platform](/solutions/devops-platform/) that can speed up cycles, reduce development costs, and improve developer efficiency. From planning and code to deployment and monitoring (and back again), GitLab brings a myriad of tools together into one open source toolset.\n\n## Why Mattermost ChatOps\n\nWe’re big fans of GitLab here at Mattermost, which is why Mattermost is packaged with GitLab Omnibus and why we work to make sure Mattermost is easy to [set up with GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/doc/gitlab-mattermost).\n\n[Mattermost’s open source ChatOps platform](https://mattermost.com/blog/introducing-mattermost-chatops/) allows you to surface relevant information to your team and enables you to take action directly where you’re having conversations. When an issue comes in, a ChatOps workflow can alert relevant team members, who all work together to make a fix directly within Mattermost.\n\nChatOps provides a method to interact with CI/CD jobs through messaging. Many organizations’ discussion, collaboration, and troubleshooting is taking place in messaging services these days, and having a method to run CI/CD jobs with output posted back to the channel can significantly accelerate a team’s workflow. ChatOps not only increases communication and collaboration, but a searchable history of the conversations associated with your development cycle increases transparency and creates a repository of valuable information for the team.\n\n## Mattermost + GitLab\n\nA complete DevOps toolchain plus open source messaging and ChatOps – what’s not to love? With GitLab and Mattermost, teams can not only simplify their DevOps process, but also bring their processes into the same chat interface where team members are discussing issues, collaborating, and making decisions.\n\nHere are a couple of examples of how development teams use Mattermost and GitLab together to accelerate developer productivity through ChatOps.\n\n### itk uses GitLab and Mattermost to ship more code on time and 6x production deployments per year\n\n[Itk](https://www.itk.fr/en/), based in Montpellier, France, develops tools and applications to help farmers optimize yields, increase the quality of crops, and manage risks more effectively.\n\nThey began using GitLab around 2014 and primarily used a legacy chat tool for day-to-day collaboration, messaging, and video calling. However, as the company grew, this tool didn’t scale with them; there was no persistent, easily searchable messaging, and collaboration across the team became more difficult. They began to look for an alternative.\n\nShortly thereafter, they discovered that the GitLab Omnibus package ships with an open source messaging platform for developers: Mattermost. They immediately fell in love with its easy code-sharing capabilities – including automatic syntax highlighting and full Markdown support, and the ease of sharing knowledge, searching past conversations, and collaborating on ideas across the team to develop new solutions all integrated together with GitLab.\n\nBefore switching to Mattermost, team members hadn’t been able to easily get notified about their development process. But they wanted to be able to visibly track projects, merge requests, and other activities from GitLab.\n\nThis is when Romain Maneschi, a software developer at itk, began writing a GitLab plugin for Mattermost that would further enable his team to subscribe to GitLab notifications in Mattermost and receive notifications about new issue assignments and review requests in one place.\n\nToday, [the plugin supports](https://github.com/mattermost/mattermost-plugin-gitlab):\n\n- **Daily reminders** – get informed on what issues and merge requests need your attention\n- **Notifications** – get notified in Mattermost when someone mentions you, requests your review, or assigns an issue to you on GitLab\n- **Sidebar buttons** – stay up-to-date with how many reviews, unread messages, assignments and open merge requests you have with buttons in the Mattermost sidebar\n- **Subscribe to projects** – use slash commands to subscribe a Mattermost channel to receive notifications of new merge requests or issues in a GitLab project\n\nNow, his whole company uses both GitLab and Mattermost to accelerate workflows through ChatOps. As a result, they now ship more code on time, resulting in 3x growth in the number of projects and microservices managed by the team and 6x growth in the number of production deployments within a year – all while growing their dev and agronomist teams by 5x.\n\n![GitLab Mattermost plugin](https://about.gitlab.com/images/blogimages/gitlab-mattermost-plugin.png){: .shadow.medium.center}\n\u003C!-- image: https://user-images.githubusercontent.com/13119842/70714554-5b52cc80-1cb6-11ea-9cd6-705a68f9ac1b.png -->\n\n### A software development company increases productivity through better transparency and visibility into code and configuration changes\n\nA software development and data services company based in the state of Maryland has also rolled out Mattermost integrated with GitLab to increase productivity and seamlessly collaborate.  They provide analytics, data management, and software development services to biomedical researchers and organizations worldwide.\n\nGitLab is heavily used across their team and they consider it a huge asset in their DevOps workflows.\n\nThey have also integrated GitLab and Mattermost together by pushing GitLab commits to a single Mattermost channel via webhooks, enabling senior management to get a bird’s-eye view of everything that’s rolling through in a given day. It includes updates for configuration management and version control, giving a snapshot of different changes made to internal infrastructure and systems throughout the day.\n\nThe team has also set up separate “Heartbeat” channels to send notifications on application events. Having these messages funnel to specific Heartbeat channels avoids distracting the flow of conversations in regular project collaboration channels while empowering team members to jump on issues posted in the Heartbeat channels.\n\nOne of the key benefits this integration brings to the team is the visibility of changes made to versions and configuration management in real time; as soon as a change is committed and pushed live, a notification is sent to the Heartbeat channel which anyone can subscribe to. No more switching between apps, asking team members, or tracking down commits – it’s now all in one place inside Mattermost while configuration management and app development takes place in GitLab.\n\n### GitLab and Mattermost ChatOps improve transparency and productivity to accelerate development\n\nMattermost [ships as part of the GitLab Omnibus package](https://docs.gitlab.com/omnibus/gitlab-mattermost/), providing out-of-the box support for GitLab SSO, pre-packaged GitLab integrations, and PostgreSQL support, along with a Prometheus integration that enables systems monitoring and [incident response management](https://docs.gitlab.com/ee/user/project/integrations/prometheus.html#taking-action-on-incidents). Finally, Mattermost can now also be deployed [with GitLab Cloud Native](https://docs.mattermost.com/install/install-mmte-helm-gitlab-helm.html).\n\nThere’s never been a better time for DevOps teams to get the full benefits of open source ChatOps. Try it out by installing GitLab Omnibus with Mattermost today.",[717,9,693],{"slug":2071,"featured":6,"template":696},"how-enterprise-dev-teams-use-gitlab-mattermost-chatops","content:en-us:blog:how-enterprise-dev-teams-use-gitlab-mattermost-chatops.yml","How Enterprise Dev Teams Use Gitlab Mattermost Chatops","en-us/blog/how-enterprise-dev-teams-use-gitlab-mattermost-chatops.yml","en-us/blog/how-enterprise-dev-teams-use-gitlab-mattermost-chatops",{"_path":2077,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2078,"content":2084,"config":2090,"_id":2092,"_type":13,"title":2093,"_source":15,"_file":2094,"_stem":2095,"_extension":18},"/en-us/blog/how-gitlabs-red-team-automates-c2-testing",{"title":2079,"description":2080,"ogTitle":2079,"ogDescription":2080,"noIndex":6,"ogImage":2081,"ogUrl":2082,"ogSiteName":683,"ogType":684,"canonicalUrls":2082,"schema":2083},"How GitLab's Red Team automates C2 testing ","Learn how to apply professional development practices to Red Teams using open source command and control tools.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665667/Blog/Hero%20Images/built-in-security.jpg","https://about.gitlab.com/blog/how-gitlabs-red-team-automates-c2-testing","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How GitLab's Red Team automates C2 testing \",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Josh Feehs\"}],\n        \"datePublished\": \"2023-11-28\",\n      }",{"title":2079,"description":2080,"authors":2085,"heroImage":2081,"date":2087,"body":2088,"category":716,"tags":2089},[2086],"Josh Feehs","2023-11-28","At GitLab, our [Red Team](https://handbook.gitlab.com/handbook/security/threat-management/red-team/) conducts security exercises that emulate real-world threats. By emulating real-world threats, we help assess and improve the effectiveness of the people, processes, and technologies used to keep our organization secure. To operate effectively, we must utilize professional development practices like the threat actors we emulate.\n\n[Threat actors](https://www.securonix.com/blog/threat-labs-security-advisory-new-starkvortex-attack-campaign-threat-actors-use-drone-manual-lures-to-deliver-merlinagent-payloads/) use open source command and control (C2) tools such as [Merlin](https://github.com/Ne0nd0g/merlin). While convenient, these tools have intentionally detectable features to discourage illegitimate use. Red Teams often need to customize and combine different open source options to evade detections in the environments they target.\n\nIn this blog, you'll learn how our team applies professional development practices to using open source C2 tools. We'll share how we implement continuous testing for the Mythic framework, our design philosophy, and a public project you can fork and use yourself.\n\nOur solution, available in [this public project](https://gitlab.com/gitlab-com/gl-security/threatmanagement/redteam/redteam-public/continuousmage), improves our Red Team operations in two ways. First, it contains a suite of **pytest** tests for the Mythic C2 framework. These validate functionality of both the Mythic server and multiple Mythic-compatible agents. Second, it leverages **GitLab CI/CD pipelines** to automatically run these tests after each code change. This enables iterative development and rapid validation of updates to Mythic or Mythic-compatible C2 agents.\n\n## Prerequisites\n\nCurrently, a few prerequisites fall outside the scope of test automation:\n\n- A Linux VM with Mythic, its Python requirements, and the HTTP profile installed. See the [Mythic installation guide](https://docs.mythic-c2.net/installation). We suggest binding Mythic's admin interface to localhost only.\n- A fork of [the ContinuousMage GitLab project](https://gitlab.com/gitlab-com/gl-security/threatmanagement/redteam/redteam-public/continuousmage) in GitLab.com or your own GitLab instance. You'll build on top of this to run your own automation. We highly suggest making this fork private, so you don't expose your test infrastructure or C2 code changes.\n- GitLab Runner installed on the VM (configured with the [shell executor](https://docs.gitlab.com/runner/executors/shell.html)) and registered with your GitLab instance. See the docs on [installing](https://docs.gitlab.com/runner/install/) and [registering](https://docs.gitlab.com/runner/register/) a runner or follow the instructions provided when configuring your pipeline later in this blog. You'll assign this runner to your project when we configure CI/CD.\n- Your forked project cloned onto your VM. This allows testing code changes (or new tests) before triggering the pipeline.\n\n## Project structure\n\nThe project contains three main portions that we will detail in this blog post:\n\n1. `pytest` test code for running integration tests for Mythic and Mythic-compatible C2 agents\n2. The source of those Mythic-compatible C2 agents, as git submodules\n3. The GitLab CI/CD pipeline configuration that ties it all together\n\n## Part 1: pytests\n\n[pytest](https://docs.pytest.org/en/7.4.x/) is a framework for writing tests in Python. We can leverage pytest to do integration testing of Mythic since it has its own [Python package](https://pypi.org/project/mythic/). The test suite goals are:\n\n1. Be simple and atomic.\n2. Provide adequate coverage to validate tool readiness.\n\nWe'll walk through a simple test verifying an agent can run the `ls` command, highlighting key code sections for customization.\n\n### Implementation\n\n#### pytest file\n\nWhen run on a directory, `pytest` automatically discovers tests in files prefixed with `test_` and test functions starting with `test_`. Our tests are asynchronous, needing the `pytest.mark.asyncio` decorator, because the Mythic APIs we are testing are asynchronous. If your machine is missing test dependencies, run `python3 -m pip install mythic pytest pytest-asyncio`.\n\nA test function skeleton is as follows:\n\n```python\n@pytest.mark.asyncio\nasync def test_agent_ls():\n    # Will do the test here\n    continue\n```\n\n#### The GlMythic class\n\nThe `GlMythic` class wraps Mythic APIs for ease of use in testing. Because its `init` function is async, a coroutine creates the object:\n\n```python\n@pytest.mark.asyncio\nasync def test_agent_ls():\n    glmythic = await gl_mythic.create_glmythic()\n```\n\nBy default, it connects to the Mythic DB using the `MYTHIC_ADMIN_PASSWORD` environment variable and is configured to test the agent specified via the `AGENT_TYPE` environment variable. We will set these in the CI/CD config later.\n\n#### Interacting with Mythic via GlMythic\n\nWe'll include the remainder of the test code here, with comments, and then discuss the most important parts.\n\nAs a reminder, one of the key goals of this project was to make completely atomic tests. Each test only relies on a running Mythic server with the specific agent and HTTP containers loaded. As the test suite grows, it may be worth running a secondary set of tasks that relies on an already-existing agent connection. Currently, every test creates, downloads, and executes a new agent.\n\n### Test and deploy\n\n```python\n@pytest.mark.asyncio\nasync def test_agent_ls():\n\n    glmythic = await gl_mythic.create_glmythic()\n\n    # Unique payload_path per test\n    payload_path = \"/tmp/test_agent_ls\"\n\n    # Wraps agent create, download, and execute\n    proc = await glmythic.generate_and_run(payload_path=payload_path)\n\n    # Wait for callback\n    time.sleep(10)\n\n    # Uses the display_id field to determine most recent callback\n    # Assumes that the most recent callback is the one created by this test\n    callback = await glmythic.get_latest_callback()\n\n    # Issue the ls command, blocking on output\n    output = await mythic.issue_task_and_waitfor_task_output(\n        mythic=glmythic.mythic_instance,\n        command_name=\"ls\",\n        parameters=\"\",\n        callback_display_id=callback[\"display_id\"],\n        timeout=20,\n    )\n\n    # Clean up (no longer need the agent)\n    proc.terminate() \n    os.remove(payload_path)\n\n    # If the ls failed, there will be no output\n    # This test could also look for files in the repo (where the agent runs)\n    assert len(output) > 0\n\n```\n\nThe longest running portion of this test will be the call to `generate_and_run`, as agent builds within Mythic can take from seconds to minutes or even hang altogether. For your initial set of tests, sign in to the Mythic server and watch the **Payloads** screen for potential issues. In our testing, agent builds failed to complete around 5% of the time, depending on the agent. If you experience repeated build failures, reload your agent container with `sudo ./mythic-cli install folder \u003Cagent_directory> -f`.\n\nTo run the tests, run `pytest \u003Ctestfile_directory>`.\n\n## Part 2: Agent source as submodules\n\nBecause Mythic agents are often updated, we include the agent repos as git submodules in our test project. This allows us to update to new agent versions when they are released and use our project's version control to keep tool versions static for known good builds. These submodules are all located in the `agents` folder.\n\nWe'll discuss adding more agents to this project later in this blog.\n\n## Part 3: GitLab CI/CD pipeline\n\nNow that you have working pytests, you can automate your tests to run whenever you want. In our case, we chose to run our tests on merge requests and tagged commits (which are likely to be tool releases). We will be using [GitLab CI/CD pipelines](https://docs.gitlab.com/ee/ci/pipelines/) to perform our automated tests.\n\n### Configuring the pipeline\n\nNow is the time to set your GitLab CI/CD settings. To find these settings, go to your repository -> `Settings` -> `CI/CD`.\n\nThe first setting you'll want to set is your `Runner`. If you set up a runner as one of your prerequisite steps earlier, you can assign it here. If not, click `New project runner` and work through that process to create and set up your runner on your Mythic server. When you are prompted to choose a runner type on install, choose the [shell executor](https://docs.gitlab.com/runner/executors/shell.html). If your team uses shared runners for other CI/CD pipelines, you will want to make sure that shared runners are disabled for this project, given that your shared runners are unlikely to be able to talk to Mythic directly.\n\n![runner-settings](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683075/Blog/Content%20Images/runner-settings.png)\n\nNext, you need to set your `Variables`. The `GlMythic` class uses the `MYTHIC_ADMIN_PASSWORD` environment variable to be able to actually sign into Mythic, so you need to make sure that the pipeline runner's environment is set up correctly.\n\nTo do this, click the `Add variable` button and add the `MYTHIC_ADMIN_PASSWORD` variable with the appropriate value. If you don't know your Mythic admin password, on the Mythic server in the directory where you installed Mythic, `cat .env | grep MYTHIC_ADMIN_PASSWORD` will give you the password.\n\nBecause GitLab handles merge requests in a detached state, you need to unclick the `Protect Variable` box, because that would prevent the pipeline from viewing the variable on a merge request otherwise. Because the variable is not protected, any branch committed back to your server can access your CI variables. This may pose a security risk if you allow remote access to your Mythic server (versus binding to localhost) and if you allow arbitrary users to access your repository. For this reason, our public repo does not have the environment variables. We use a private copy to perform testing, and suggest you do the same.\n\nAdditionally, set the `AGENT_TYPE` variable to the name of the agent you want to use. At time of release, valid agent types are `poseidon` or `merlin`. The section about adding more agents to the test suite will go into more detail.\n\nYou can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.\n\nNow that the pipeline is configured to use the runner and pick up the environment variables that you need, the only thing left to do is to set up your pipeline. This step is quite simple: If you add the `.gitlab-ci.yml` file to the root of your repository, GitLab will pick that up as the pipeline config on your next commit. Here is our example pipeline, which we will explain momentarily.\n\n```yaml\ninstall:\n  stage: install\n  script:\n    - sudo /opt/Mythic/mythic-cli install folder \"${CI_PROJECT_DIR}\"/agents/\"${AGENT_TYPE}\" -f\n  rules:\n    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'\n    - if: $CI_COMMIT_TAG\n\ntest:\n  stage: test\n  script:\n    - pytest \"${CI_PROJECT_DIR}\"/mythic-test\n  rules:\n    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'\n    - if: $CI_COMMIT_TAG\n```\n\nAll of the variables set above are made available by GitLab as part of every pipeline. This pipeline has two stages, `install` and `test`. Both stages are set to only run on merge requests or if the commit being evaluated has a specific tag. The `install` stage will install your C2 agent into Mythic using its local folder install. This makes sure that the Mythic server has your latest C2 code changes installed. Next, the `test` stage runs the set of pytest tests that we created. The `install` stage will run very quickly, and the `test` stage will run a little more slowly, given that it's doing the work of creating and interacting with Mythic agents.\n\n### Pipeline in action\n\nYou can do a couple of things to validate that your pipeline is working. First, if you are performing a merge request, there will be a section at the beginning of the merge request that will link to the pipeline. The screenshot below shows that the pipeline has passed, but you can click into the pipeline by clicking on its number even when it's running.\n\n![Pipeline passing](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683075/Blog/Content%20Images/merge-pipeline-pass.png)\n\nYou can then click into the stage that's running (or one that has already run) to view its output.\n\n![Pipeline task output](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683075/Blog/Content%20Images/pipeline-task-output.png)\n\nAnd there you are! You now have working `pytest` tests for a Mythic agent that run every time you make a merge request.\n\n## Adapting for other agents\n\nWe tested our test suite against Poseidon and Merlin. Although the initial tests (generate, download and exec, ls) work the same for both agents, Poseidon and Merlin require different parameters for their `upload` commands. Unfortunately, this means that not all tests will be agent agnostic.\n\nAs a result, each `GlMythic` object that is created is told what type of agent it is testing. The coroutine for creating an object allows you to pass in the agent type as a variable, and defaults to using the `AGENT_TYPE` environment variable to determine which agent is being tested.\n\n```python\nasync def create_glmythic(  username=\"mythic_admin\",\n                            password=os.getenv(\"MYTHIC_ADMIN_PASSWORD\"),\n                            server_ip=\"127.0.0.1\",\n                            server_port=7443,\n                            agent_type=os.getenv(\"AGENT_TYPE\")):\n```\n\n### Agent source\n\nTo add more agents for testing, the first thing to do is to import your agent as a git submodule:\n\n```bash\ncd agents\ngit submodule add \"${URL_TO_YOUR_AGENT}\"\n```\n\nCommit your changes, and your agent is tracked as part of the repo.\n\n### Test compatibility\n\nYou'll need to validate that existing tests work with your agent. For tests to work, the parameters passed to the commands must match those in the test suite, with `upload` to be most likely to fail.\n\nThis is okay! Within the `test_agent_upload` test function, you'll see example code that specifies a different upload command for Merlin and Poseidon. Simply follow this structure for your own agent, passing your agent's parameters to the `mythic.issue_task_and_waitfor_task_output` function call.\n\nIf you are using another open source C2 and are unsure of the correct parameters to pass, you can use the Mythic UI. Interact with one of your agents and run the `upload` command to see what params you need to pass. If you do this for Poseidon, it will look like the following:\n\n![upload-parameters](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683075/Blog/Content%20Images/upload-parameters.png)\n\nOur test suite should be pretty easy to add to any Linux-based Mythic agent that supports the [HTTP C2 profile](https://github.com/MythicC2Profiles/http). Because the GitLab Runner installs the agent into Mythic (and Mythic is made to run on Linux), the runner is expecting to be on a Linux machine. Additional effort and test modifications will be required to run the test suite against a Windows or MacOS agent.\n\n## A quick win\n\nAs we worked on this project, we were continuously running our test suite against both Poseidon and Merlin. Unexpectedly, in early October 2023, our test for Poseidon's `upload` function started to fail. After a quick investigation, we identified that a bug had been introduced, present in Poseidon 2.0.2, that caused file uploads to fail.\n\nWe took our information to one of the Poseidon developers, Cody Thomas ([@its_a_feature_](https://twitter.com/its_a_feature_)), and he quickly identified the underlying issue and [fixed the problem](https://github.com/MythicAgents/poseidon/commit/83de4712448d7ed948b3e2d2b2f378d530b3a42a).\n\nThis highlights the usefulness of continuous testing. Instead of running into a potential bug during a Red Team exercise, we identified the issue beforehand and were able to report the bug so the issue was fixed.\n\nWe sincerely thank the Mythic, Merlin, and Poseidon developers for open sourcing their hard work. Many Red Teams around the world are able to perform high-quality security assessments in part because of the hard work of C2 developers who open source their tools. We also want to specifically thank Cody Thomas for addressing this bug within 20 minutes of notification. His responsiveness and attention to detail are unmatched.\n\n## Share your feedback\n\nThis post has demonstrated both the value of continuous testing and shown how to implement continuous testing for your own use, using GitLab. If you have worked alongside these examples, you've implemented some continuous testing for the Mythic framework and have tests that you can use for Merlin, Poseidon, or your own Mythic agent(s).\n\nAt GitLab, we always seek feedback on our work. If you have any questions or comments, please open an issue on [our project](https://gitlab.com/gitlab-com/gl-security/threatmanagement/redteam/redteam-public/continuousmage). You can also propose improvements via a merge request. We believe that everyone should be able to contribute, so we welcome any contributions, big or small.\n\n> [Try GitLab Ultimate for free today.](https://gitlab.com/-/trials/new)\n\n## Related reading\n- [Stealth operations: The evolution of GitLab's Red Team](https://about.gitlab.com/blog/stealth-operations-the-evolution-of-gitlabs-red-team/)\n- [How we run Red Team operations remotely](https://about.gitlab.com/blog/how-we-run-red-team-operations-remotely)\n- [Use GitLab and MITRE ATT&CK Navigator to visualize adversary techniques](https://about.gitlab.com/blog/gitlab-mitre-attack-navigator)\n- [Monitor web attack surface with GitLab](https://about.gitlab.com/blog/monitor-web-attack-surface-with-gitlab)\n",[716,1989,9,807],{"slug":2091,"featured":90,"template":696},"how-gitlabs-red-team-automates-c2-testing","content:en-us:blog:how-gitlabs-red-team-automates-c2-testing.yml","How Gitlabs Red Team Automates C2 Testing","en-us/blog/how-gitlabs-red-team-automates-c2-testing.yml","en-us/blog/how-gitlabs-red-team-automates-c2-testing",{"_path":2097,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2098,"content":2103,"config":2109,"_id":2111,"_type":13,"title":2112,"_source":15,"_file":2113,"_stem":2114,"_extension":18},"/en-us/blog/how-grammatech-and-gitlab-enables-better-devsecops",{"title":2099,"description":2100,"ogTitle":2099,"ogDescription":2100,"noIndex":6,"ogImage":754,"ogUrl":2101,"ogSiteName":683,"ogType":684,"canonicalUrls":2101,"schema":2102},"How a new integration helps GitLab customers secure their code","GitLab Ultimate customers can use CodeSonar from GrammaTech for SAST and to bake protection into every stage of software development.","https://about.gitlab.com/blog/how-grammatech-and-gitlab-enables-better-devsecops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How a new integration helps GitLab customers secure their code\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Christian Simko\"}],\n        \"datePublished\": \"2021-08-20\",\n      }",{"title":2099,"description":2100,"authors":2104,"heroImage":754,"date":2106,"body":2107,"category":739,"tags":2108},[2105],"Christian Simko","2021-08-20","\n\nSoftware development teams that embrace agile and [DevSecOps](/topics/devsecops/) are able to code with a security-first mindset, which is essential for industries that build particularly complicated products where security is paramount, like: Aerospace and defense, automotive, industrial controls, medical devices, and more.\n\nStatic application security testing (SAST) solutions, like [CodeSonar® from GrammaTech](https://www.grammatech.com/products/source-code-analysis), integrate directly into CI/CD pipelines to bake security into every step of the software development life cycle (SDLC) – protecting your products every step of the way. Security solutions like GrammaTech pair well with an all-in-one DevOps Platform like GitLab, and allow development teams to follow best practices and industry standards to develop code that is better quality and more secure.\n\n## The GrammaTech and GitLab integration\n\nThe GrammaTech module for [GitLab Ultimate](/pricing/ultimate/) provides native SAST capabilities that scan code for defects in CI/CD pipelines and eliminates the need for any integration and maintenance by users. It allows developers to assess code continuously, avoiding costly mistakes and the duplicative work associated with waiting until the testing phase to scan for security problems.\n\nWe recognize that developers face pressure to meet aggressive deadlines for delivering new software, as rolling releases and agile development practices have developers pushing new features and code into production faster. Integrating SAST tools like CodeSonar into a DevOps Platform like GitLab Ultimate is a natural consequence to more iterative development in companies that embrace DevSecOps practices. CodeSonar helps developers shift security left by detecting and eliminating bugs and vulnerabilities at the earliest stages of the SDLC.\n\n## SAST with CodeSonar\n\nCodeSonar uses a unified data flow and symbolic execution analysis to examine the computation of the complete application. This approach is deeper than typical pattern-matching syntax analysis, and discovers 3-5x more defects on average.\n\nStatic analysis is unlike other software development tools (i.e., testing tools, compilers, and configuration management) becuase it can be integrated into the development process at any time with ease. CodeSonar simply attaches to your existing build environments to add analysis information to your verification process.\n\n### How does CodeSonar work?\n\nLike a compiler, CodeSonar does a \"build\" of your code using the existing build environment, but instead of creating object code, CodeSonar creates an abstract model of your entire program. From the derived model, CodeSonar's symbolic execution engine explores program paths, reasoning about program variables, and how they relate. Advanced theorem-proving technology prunes infeasible program paths from the exploration.\n\n![How CodeSonar works to secure code](https://about.gitlab.com/images/blogimages/codesonar.png){: .shadow.center}\nSee how CodeSonar secures code.\n{: .note.text-center}\n\nCheckers in CodeSonar perform static code analysis to find common defects, violations of policies, etc. Checkers operate by traversing or querying the model and looking for particular properties or patterns that indicate defects. Sophisticated symbolic execution techniques explore paths through a control-flow graph – the data structure representing paths that might be traversed by a program during its execution. When the path exploration notices an anomaly, a warning is generated.\n\nAn astronomical number of combinations of circumstances must be modeled and explored, so CodeSonar employs a variety of strategies to ensure scalability. For example, procedure summaries are refined and compacted during the analysis, and paths are explored in a way that minimizes paging.\n\n## Continuous Integration enabled by GitLab\n\nIntegrating CodeSonar into GitLab's pipeline is done with each [merge request (MR)](https://docs.gitlab.com/ee/user/project/merge_requests/), automatically analyzing your code and returning any vulnerabilities found via the GitLab SAST interface. Users can consult the GitLab Security Dashboard to get an overview of code security, and the Vulnerability Report gets into the details.\n\n![How CodeSonar integrates with GitLab CI pipelines](https://about.gitlab.com/images/blogimages/codesonar2.png){: .shadow.center}\nHow CodeSonar integrates with GitLab CI pipelines.\n{: .note.text-center}\n\n### Review CodeSonar warnings in GitLab Vulnerability Reports\n\nCodeSonar displays vulnerabilities right in the GitLab UI – you can review a warning, create a GitLab issue, and assign it to a developer – all in a single application. You can also dismiss vulnerabilities. CodeSonar's fingerprinting technology ensures that GitLab won't ever show dismissed vulnerabilities to you again.\n\n### Get a more detailed warning view\n\nSometimes you need more information to decide how to handle a particular warning. CodeSonar and GitLab make this easy. The CodeSonar warning message can be viewed directly in GitLab, and CodeSonar's detailed warning reports with annotated source code are just a click away – no copy and pasting, or searching for line numbers.\n\n![Example of GitLab vulnerability report](https://about.gitlab.com/images/blogimages/codesonar3.png){: .shadow.center}\nSee example of a GitLab vulnerability report and detailed view of warnings.\n{: .note.text-center}\n\n## How to get started\n\nA typical way to use the GitLab CI/CD pipeline is to set it up to run whenever new Git commits are submitted to a MR. When you add CodeSonar static analysis to your MR pipeline, GitLab will display the new analysis warnings on the MR page. The full set of warnings is always available on the pipeline page.\n\n### Prerequisites to use CodeSonar\n\n1. The CodeSonar integration requires a working instance of *GitLab Ultimate edition*.\n2. You must have a source code project in your GitLab instance that you wish to analyze. Set up a [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) pipeline for your project that can build your source code. This will include the configuration of one or more GitLab pipeline jobs ([more on how to configure GitLab Runners](https://docs.gitlab.com/runner/configuration/)).\n3. If you use Docker, ensure you have [Docker Engine](https://docs.docker.com/engine/install/) version 19.03.12 or later.\n4. Use the CodeSonar software package that is appropriate for your GitLab pipeline job runner's operating platform.\n5. Set up a dedicated, \"persistent\" CodeSonar Hub to coordinate and receive the results of your analysis. See your CodeSonar manual for how to set up and license a Hub.\n6. You will need a valid CodeSonar Hub license that is appropriate to your configuration and the CodeSonar GitLab Integration software package.\n\nRead the [instructions on installing the CodeSonar GitLab integration](https://support.grammatech.com/documentation/codesonar/integrations/gitlab/).\n\n_Christian Simko is the Director of Product Marketing at GrammaTech._\n",[716,9,1161],{"slug":2110,"featured":6,"template":696},"how-grammatech-and-gitlab-enables-better-devsecops","content:en-us:blog:how-grammatech-and-gitlab-enables-better-devsecops.yml","How Grammatech And Gitlab Enables Better Devsecops","en-us/blog/how-grammatech-and-gitlab-enables-better-devsecops.yml","en-us/blog/how-grammatech-and-gitlab-enables-better-devsecops",{"_path":2116,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2117,"content":2123,"config":2129,"_id":2131,"_type":13,"title":2132,"_source":15,"_file":2133,"_stem":2134,"_extension":18},"/en-us/blog/how-is-ai-ml-changing-devops",{"title":2118,"description":2119,"ogTitle":2118,"ogDescription":2119,"noIndex":6,"ogImage":2120,"ogUrl":2121,"ogSiteName":683,"ogType":684,"canonicalUrls":2121,"schema":2122},"How is AI/ML changing DevOps?","Can DevOps help AI/ML find maturity? Here are questions to consider.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667540/Blog/Hero%20Images/devops-team-structure.jpg","https://about.gitlab.com/blog/how-is-ai-ml-changing-devops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How is AI/ML changing DevOps?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brendan O'Leary\"}],\n        \"datePublished\": \"2022-11-16\",\n      }",{"title":2118,"description":2119,"authors":2124,"heroImage":2120,"date":2125,"body":2126,"category":848,"tags":2127},[1424],"2022-11-16","\n\nThe last few years have seen an explosion in artificial intelligence, [machine learning](/blog/top-10-ways-machine-learning-may-help-devops/), and other types of projects. Companies like Hugging Face and applications like [DALL-E 2](https://openai.com/dall-e-2/) have brought to the mainstream what the power of AI/ML can bring to the next generation of computing and software. As every company has become a software company over the last few decades, the ability to innovate and leverage the ever-growing amount of data that organizations have access to have become where enterprises turn to compete.\n\nHowever, a lot of AI/ML projects get stalled from several challenges that may seem familiar to software professionals who have been around since [the early days of DevOps](/blog/the-journey-to-a-devops-platform/).  Adoption and optimization of artificial intelligence and machine learning have been hampered by a lack of repeatability for experiments, a disparity of tools and information silos, and a lack of team collaboration.\n\n## A new model for data modeling\n\nOne of the first ways to look at this problem is to make sure that the mental model is in place to allow the team to reason about both the strategic vision for AI/ML at your organization. And once that has been established, also think about the tactical “jobs to be done” to lay the foundation for that work.\n\nStrategically, there are many teams that have to come together for a successful AI/ML program. First, the data has to both be acquired and transformed into a usable set of clean data. Often referred to as [“DataOps”](/blog/introducing-modelops-to-solve-data-science-challenges/) this involves the typical “ETL” or extract, load, transform processes data has to go through to be useful for teams. From there, you have to productionize the data workloads through MLOps - the experimentation, training, testing, and deployment of meaningful models based on the extracted and transformed data.\n\nAnd once those two steps are complete, you can finally understand how to make production use cases for your data. You can use AI Assisted features to focus on improving user experiences, for financial forecasting, or for general trends and analysis of various parts of your business. Given the complexity of this value chain, the various teams and skills involved, and the current mishmash of tooling, there is a lot that teams can learn from the history of DevOps as they tackle these problems.\n\n## DevOps and AI/ML\n\nMuch like the various stages of obtaining and applying AI/ML for business uses, software development consists of many varied steps with different teams and skills sets to achieve the business goals outlined. That is why years ago, folks came up with this [concept of “DevOps”](/topics/devops/)– combining teams and having them work together in a cycle of continuous improvement towards the same goals – to combat silos and inefficiencies. \n\nData science teams are using specialized tools that don't integrate with the existing software development lifecycle tools they already use. This causes teams to work in silos, creating handoff friction and resulting in finger-pointing and lack of predictability. Businesses and software teams often fail to take advantage of data, and it takes months for models to get into production by which time they may be out of date or behind competitors.  Security and data ethics are frequently treated as an afterthought. This creates risk for organizations and slows innovation. \n\n## Learning from the past\n\nIf the past decades of “DevOps” evolution have taught us anything, it's that breaking down the silos between teams through the tools and processes they are using pays off dividends for business. As your team begins their [AI/ML journey](/blog/why-ai-in-devops-is-here-to-stay/) — or if you've found yourself stalling in AI/ML initiatives already — you should consider how you can consolidate teams together, ensure they are working efficiently together, and able to collaborate without boundaries.\n\nAn explosion of tools in the space is tantalizing with the promise of “getting started” quickly. But it may not set your organization up for long-term success in these areas if those tools have the effect of separating parts of your organization from one another. Creating and sustaining an AI/ML program will require intentionality behind both the processes and tools your team is using. That allows your teams to extract, transform and load data efficiently, tune, test and deploy models effectively, and leverage AI/ML to drive value for your stakeholders for the long haul.\n",[851,9,2128,934],"performance",{"slug":2130,"featured":6,"template":696},"how-is-ai-ml-changing-devops","content:en-us:blog:how-is-ai-ml-changing-devops.yml","How Is Ai Ml Changing Devops","en-us/blog/how-is-ai-ml-changing-devops.yml","en-us/blog/how-is-ai-ml-changing-devops",{"_path":2136,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2137,"content":2143,"config":2148,"_id":2150,"_type":13,"title":2151,"_source":15,"_file":2152,"_stem":2153,"_extension":18},"/en-us/blog/how-to-access-gitlab-on-a-private-network-with-tailscale",{"title":2138,"description":2139,"ogTitle":2138,"ogDescription":2139,"noIndex":6,"ogImage":2140,"ogUrl":2141,"ogSiteName":683,"ogType":684,"canonicalUrls":2141,"schema":2142},"How to access GitLab on a private network with Tailscale","If issues around a private network were preventing a permanent GitLab installation, Brendan O'Leary has the solution with Tailscale.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679348/Blog/Hero%20Images/locks.jpg","https://about.gitlab.com/blog/how-to-access-gitlab-on-a-private-network-with-tailscale","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to access GitLab on a private network with Tailscale\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brendan O'Leary\"}],\n        \"datePublished\": \"2022-07-21\",\n      }",{"title":2138,"description":2139,"authors":2144,"heroImage":2140,"date":2145,"body":2146,"category":739,"tags":2147},[1424],"2022-07-21","\nGitLab provides an easy-to-install package for most Linux distributions and even for devices like the [Raspberry Pi](https://docs.gitlab.com/omnibus/settings/rpi.html). However, if you want to install GitLab in a home lab or similar private network, you would then be faced with a new issue: how do you access the instance from outside that private network?\n\nTraditionally, you would set up your router to forward traffic from your public IP address to the server inside your network. However, this comes with several drawbacks:\n\n- Opening a port on your home or private network comes with a sustainable amount of risk.\n- It can be hard or impossible for folks to do depending on their internet service provider and what routing equipment they use.\n- It can be especially tough if your ISP doesn't provide you with a statically assigned IP address which means your address can change from time to time, and you'll need to either update DNS manually or through some third-party [dynamic DNS](https://www.cloudflare.com/learning/dns/glossary/dynamic-dns/) service.\n\nFor me, all of these challenges have meant that I've only ever really run GitLab \"for fun\" on my local network. Given the challenges above, running a permanent installation wasn't an option. That is until [Tailscale](https://tailscale.com) entered my life.\n\n## Tailscale\n\nTailscale isn't necessarily the \"newest\" technology. In fact, it is based on the [WireGuard protocol](https://www.wireguard.com/), which has existed in one form or another since 2015 and has seen native kernel support added to various Linux distributions as well as the kernel itself over the past several years.  Wireguard VPN technology makes considerable improvements in the usability and setup of virtual private networks over earlier protocols like IPsec. Even with being easier to use, the \"problem\" with WireGuard, at least for me, was always that it was still too complex to set up and maintain. Much like configuring my ISP's router for port forwarding, it wasn't _impossible_, but it just wasn't practical.\n\nEnter Tailscale. Tailscale provides a simple piece of client software, available for Linux, Mac, and Windows (and iOS and Android!), which implements the WireGuard protocol and allows you to control your VPN network from a handy web interface. Not only that, it's [free to use](https://tailscale.com/pricing/) for individuals and small networks. When I started using Tailscale, it was to make sure I could connect back to my home network and troubleshoot it while traveling for work. As the only system administrator in my house, this was fantastic.\n\nHowever, Tailscale also offers the ability to easily access services inside of various networks as well by setting up a mesh VPN between them, all with IP addresses in the 100.x.y.z range. That means for any web service or other service on my network, I can access it with a statically assigned IP address from any other device connected to Tailscale, and create a DNS record to have a domain point to the IP address. At last, I could run GitLab (and other open source tools) at home and safely connect to them from outside my house with as little hassle as possible. So how did I get it to work?\n\n## Tailscale and GitLab together\n\nAssuming you already have a GitLab [installation](/install/) up and running on your network, getting it working through Tailscale involves a few steps:\n\n- Installing Tailscale\n- Setting up DNS for the private address\n- Configuring HTTPS encryption\n\n### Installing Tailscale\n\nPackages are [available](https://tailscale.com/kb/1031/install-linux/) for many Linux distributions. To install Tailscale, you can select your [specific distribution](https://tailscale.com/kb/1031/install-linux/) for detailed instructions. There are also [static binaries](https://tailscale.com/kb/1053/install-static/) if you can't find your particular distribution - they are available for x86 and ARM CPUs for both 32- and 64-bit variants.\n\nOnce Tailscale is installed, getting it running is as simple as running the following command on the CLI:\n\n```bash\nsudo tailscale up\n```\n\nThe setup dialogue will walk you through the authentication process and get Tailscale running. After that process, you can see your new IP address for this node on your network with the CLI command `tailscale ip -4`. You'll need that IP address for the next steps.\n\nBy default, Tailscale will set an expiration date for the token it issues to your device during the authentication process. This is desirable for typical devices that may be transient or portable. However, suppose your device is secured inside your home or another secure place AND is a server you're not accessing all the time. In that case, you can optionally [disable key expiry](https://tailscale.com/kb/1028/key-expiry/) for that particular device.\n\n### Setting up DNS\n\nYou should be able to now access your device from any other Tailscale-connected device via the IP address from the last step. However, my goal was to make it easy for me to connect to GitLab, reference it by an URL, and encrypt the traffic end-to-end with TLS. As the next step I set up DNS.\n\nEven though the 100.x.y.z address is a private IP address, you can still create a public DNS record and have the hostname to point to it. That won't mean the whole world can access your server - it just means once you're connected to your Tailscale network, you can resolve that hostname to the IP address and access the web server. For me, I set up an A record for `gitpi.boleary.dev` to resolve to an IPv4 address:\n\n```\n;; QUESTION SECTION:\n;gitpi.boleary.dev.\t\tIN\tA\n\n;; ANSWER SECTION:\ngitpi.boleary.dev.\t300\tIN\tA\t100.64.205.40\n```\n\nAn important note here is that I use Cloudflare as my DNS provider - and I usually love Cloudflare's proxying service to make my \"real\" IP addresses private. In this case, you have to disable that proxying to make sure that you can resolve the correct address - Cloudflare can't proxy traffic into your Tailscale network.\n\n### Configuring HTTPS\n\nLastly, configuring HTTPS for your GitLab instance will ensure that all traffic is encrypted end-to-end. While Tailscale encrypts the traffic over the network, this will ensure there are no gaps between your device and your GitLab server.\n\nTo accomplish this, we'll use [`certbot`](https://certbot.eff.org/) from the EFF that lets us create and manage [Let's Encrypt](https://letsencrypt.org/) certificates. First, install `certbot` with `sudo apt install certbot` or follow the [instructions for your distribution](https://certbot.eff.org/instructions).\n\nAfter certbot is installed, issue a certificate to use with GitLab using a DNS challenge. Follow the steps to complete the DNS challenge after running this command:\n\n```bash\nsudo certbot certonly --manual --preferred-challenges dns\n```\n\nThe output will show you the specific location of the certificate it created (in my case, in a `gitpi.boleary.dev` folder), and you should link that certificate to GitLab's SSL directory by running:\n\n```bash\nsudo mkdir /etc/gitlab/ssl/\nsudo ln -s /etc/letsencrypt/live/gitpi.boleary.dev/fullchain.pem /etc/gitlab/ssl/gitpi.boleary.dev.crt\nsudo ln -s /etc/letsencrypt/live/gitpi.boleary.dev/privkey.pem /etc/gitlab/ssl/gitpi.boleary.dev.key\n```\n\nNext, configure GitLab to use the new certificate by opening the `gitlab.rb` with\n\n```bash\nsudo vi /etc/gitlab/gitlab.rb\n```\n\nAnd change the `external_url` value to match the URL for the certificate (e.g. `https://gitpi.boleary.dev`). That \"https\" will tell GitLab to enable TLS/SSL and use your linked certificate.\n\n## Finishing up\n\nThat's it! Now with a simple `gitlab-ctl reconfigure`, GitLab will pick up the new certificate and start responding to requests at that URL. From any device - iOS, Android, laptop, etc. - connected to your Tailscale network, you can access your GitLab installation (securely) from anywhere!\n",[807,693,9],{"slug":2149,"featured":6,"template":696},"how-to-access-gitlab-on-a-private-network-with-tailscale","content:en-us:blog:how-to-access-gitlab-on-a-private-network-with-tailscale.yml","How To Access Gitlab On A Private Network With Tailscale","en-us/blog/how-to-access-gitlab-on-a-private-network-with-tailscale.yml","en-us/blog/how-to-access-gitlab-on-a-private-network-with-tailscale",{"_path":2155,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2156,"content":2162,"config":2169,"_id":2171,"_type":13,"title":2172,"_source":15,"_file":2173,"_stem":2174,"_extension":18},"/en-us/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase",{"title":2157,"description":2158,"ogTitle":2157,"ogDescription":2158,"noIndex":6,"ogImage":2159,"ogUrl":2160,"ogSiteName":683,"ogType":684,"canonicalUrls":2160,"schema":2161},"How to bring DevOps to the database with GitLab and Liquibase","Learn how to build a continuous delivery pipeline for database code changes with this tutorial.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749672677/Blog/Hero%20Images/metalgears_databasecasestudy.jpg","https://about.gitlab.com/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to bring DevOps to the database with GitLab and Liquibase\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tsvi Zandany\"}],\n        \"datePublished\": \"2022-01-05\",\n      }",{"title":2157,"description":2158,"authors":2163,"heroImage":2159,"date":2165,"body":2166,"category":739,"tags":2167},[2164],"Tsvi Zandany","2022-01-05","In the [Accelerate State of DevOps 2021\nReport](https://cloud.google.com/devops/state-of-devops/), the DevOps\nResearch and Assessment (DORA) team reveals “elite DevOps performers are 3.4\ntimes more likely to exercise database change management compared to their\nlow-performing counterparts.” Tracking changes with version control is not\njust for application code, though. It’s crucial for managing changes for one\nof your most important assets: your database.   \n\n\nThe GitLab DevOps platform enables database management teams to leverage\nCI/CD to track, manage, and deploy database changes, along with application\ndevelopment and automation and infrastructure as code. Database change\nmanagement tools have become more advanced in recent years, supporting\neasier collaboration and communication, which are the keys to successful\nDevOps. In this blog post, I’ll take you through a tutorial using\n[Liquibase](https://www.liquibase.com), a tool that integrates seamlessly\ninto the GitLab DevOps platform so your teams can deliver database code\nchanges as fast as application code changes (without compromising on quality\nand security). \n\n\n## What is Liquibase?\n\n\nLiquibase was founded as an open source project over 15 years ago to address\ngetting database changes into version control. With more than 75 million\ndownloads, the company behind Liquibase expanded to paid editions and\nsupport to help teams release software faster and safer by bringing the\ndatabase change process into their existing CI/CD automation.  \n\n\nIntegrating Liquibase with GitLab CI/CD enables database teams to leverage\nDevOps automation and best practices for database management. Liquibase\nhelps teams build automated database scripts and gain insights into when,\nwhere, and how database changes are deployed. In this tutorial, we’ll\ndemonstrate how to check database scripts for security and compliance\nissues, speed up database code reviews, perform easy rollbacks, and provide\ndatabase snapshots to check for malware.\n\n\n## Adding Liquibase to GitLab’s DevOps Platform\n\n\nTeams can add Liquibase to GitLab to enable true CI/CD for the database.\nIt’s easy to integrate Liquibase into your GitLab CI/CD pipeline. Before\njumping into the tutorial, let’s take a look at the [example Liquibase\nGitLab project\nrepository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/sql_server)\nyou’ll be using.\n\n\n### Understanding the example Liquibase GitLab project repository\n\n\n![A CI/CD pipeline\ndiagram](https://about.gitlab.com/images/blogimages/1_CICD_Pipeline_Diagram.png){:\n.shadow.small.center}\n\n\nFor this example, the GitLab CI/CD pipeline environments include DEV, QA,\nand PROD. This pipeline goes through several stages: build, test, deploy,\nand compare. A post stage comes into play later to capture a snapshot of\nyour database in Production.\n\n\nStages:\n  - build\n  - test\n  - deploy\n  - compare\n\n### Liquibase commands in the pipeline\n\n\nFor each of the predefined jobs in the GitLab repository, you’ll be using\nseveral Liquibase commands to help manage database changes quickly and\nsafely:\n\n\n- liquibase_job:\n\n  before_script:\n    - functions\n    - isUpToDate\n    - liquibase checks run\n    - liquibase updateSQL\n    - liquibase update\n    - liquibase rollbackOneUpdate --force\n    - liquibase tag $CI_PIPELINE_ID\n    - liquibase --logFile=${CI_JOB_NAME}_${CI_PIPELINE_ID}.log --logLevel=info update\n    - liquibase history\n\n  script:\n    - echo \"Comparing databases DEV --> QA\"\n    - liquibase diff\n    - liquibase --outputFile=diff_between_DEV_QA.json diff --format=json\n\n  script:\n    - echo \"Snapshotting database PROD\"\n    - liquibase --outputFile=snapshot_PROD.json snapshot --snapshotFormat=json\n\nLearn more about each of these commands in the [README file in the GitLab\nrepository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/sql_server/-/blob/main/README.md). \n\n\n## Tutorial\n\n\nThe following tutorial demonstrates how to run Liquibase in a GitLab CI/CD\npipeline. Follow along by watching this companion video:\n\n\n\u003C!-- blank line -->\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/ZBFhDayoRYo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n\u003C!-- blank line -->\n\n\n### Prerequisites\n\n\nTo start, I’m using a Linux machine with the following:\n\n\n- [A GitLab account](https://www.gitlab.com)\n\n- Self-managed Runner on a Linux machine\n\n- Git\n\n- Java 11\n\n- Access to a SQL Server database with multiple environments\n\n\n### Download, install, and configure Liquibase\n\n\n[Download Liquibase v4.6.1+](https://www.liquibase.org/download)\n\n\n[Install\nLiquibase](https://docs.liquibase.com/concepts/installation/installation-linux-unix-mac.html)\n\n\n[Get a free Liquibase Pro license key](https://www.liquibase.com/trial). No\ncredit card is required, so you can play with all the advanced features and\nget support for 30 days. You’ll use this key later when you configure\nenvironment variables within GitLab.\n\n\nEnsure Liquibase is installed properly by running the liquibase --version\ncommand. If everything is good you’ll see the following:\n\n\nStarting Liquibase at 18:10:06 (version 4.6.1 #98 built at 2021-11-04\n20:16+0000)\n\nRunning Java under /usr/lib/jvm/java-11-openjdk-11.0.13.0.8-1.el7_9.x86_64\n(Version 11.0.13)\n\n\nLiquibase Version: 4.6.1\n\nLiquibase Community 4.6.1 by Liquibase\n\n\n### Prepare your GitLab project\n\n\nFork this [example GitLab project\nrepository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/sql_server).\n([See more information about forking a\nrepository](https://docs.gitlab.com/ee/user/project/repository/forking_workflow.html).)\n\n\n[Create a self-managed GitLab Runner](https://docs.gitlab.com/runner/) on\nyour Linux instance with your newly forked GitLab project.\n\n\nClone your newly forked project repository:\n\ngit clone https://gitlab.com/\u003Cusername>/sql_server.git\n\n\nGo to the “sql_server” project folder.\n\ncd sql_server\n\n\nRun the following command to change your git branch to staging:\n\ngit checkout staging\n\n\nConfigure the GitLab CI/CD pipeline environment variables.\n\n\nYour configuration will include [CI/CD\nvariables](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project),\n[Liquibase\nproperties](https://www.liquibase.com/blog/secure-database-developer-flow-using-gitlab-pipelines),\ndatabase credentials, and the Liquibase Pro trial license key so you can use\nall the advanced Liquibase commands.\n\n\nFrom the main sql_server project, go to Settings → CI/CD\n\n\nUnder Variables, click Expand and add the following variables:\n\n\n![A CI/CD pipeline\ndiagram](https://about.gitlab.com/images/blogimages/liquibasevariables.png){:\n.shadow.small.center}\n\n\n![A CI/CD pipeline\ndiagram](https://about.gitlab.com/images/blogimages/liquibasevariables2.png){:\n.shadow.small.center}\n\n\n### Configure the self-managed GitLab runner\n\n\nFrom the main sql_server project, go to Settings → CI/CD\n\n\nExpand the runners section, click the pencil edit icon, and add the\nfollowing runner tags (comma separated):\n\n\ndev_db,prod_db,test_db\n\n\nNote: Tags are created to help choose which runner will do the job. In this\nexample, we are associating all tags to one runner. Learn more about\n[configuring\nrunners](https://docs.gitlab.com/ee/ci/runners/configure_runners.html). \n\n\n### Make changes to the database\n\n\nEdit the changelog.sql file and add the following changeset after \n\n\n```\n\nliquibase formatted sql:\n\n-- changeset SteveZ:createTable_salesTableZ\n\nCREATE TABLE salesTableZ (\n   ID int NOT NULL,\n   NAME varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,\n   REGION varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,\n   MARKET varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL\n)\n\n--rollback DROP TABLE salesTableZ\n\nAdd, commit, and push all new database changes.\n\ngit add changelog.sql\n\ngit commit -m “added changelog id and a create table salesTableZ changeset”\n\ngit push -u origin staging\n\n```\n\n\n### Merge the changes and run the pipeline\n\n\nLet’s merge the changes from branch staging → main to trigger the pipeline\nto run all jobs.\n\n\nClick Merge requests → New merge request\n\n\nSelect staging as Source branch and main as Target branch\n\n\nClick Compare branches and continue\n\n\nOn the next screen, click Create merge request\n\n\nClick Merge to finish merging the changes\n\n\n![A look at the merge\nrequest](https://about.gitlab.com/images/blogimages/2_Merge_Request1.png){:\n.shadow.small.center}\n\n\n![Another look at the merge\nrequestt](https://about.gitlab.com/images/blogimages/3_Merge_Request2.png){:\n.shadow.small.center}\n\n\nOnce these steps are completed, the code is merged into main and the\npipeline is triggered to run.\n\n\n![The pipeline is\ntriggered](https://about.gitlab.com/images/blogimages/4_Merge_Request3.png){:\n.shadow.small.center}\n\n\nTo see the pipeline running, click Pipelines.\n\n\nTo view the pipeline progress, click the pipeline ID link. You can view each\njob’s log output by clicking on each job name.\n\n\n![The pipeline in\nprogress](https://about.gitlab.com/images/blogimages/5_Pipeline_Progress.png){:\n.shadow.small.center}\n\n\nClicking into the build-job example:\n\n\nThe liquibase checks run command validates the SQL for any violations.\n\n\n```\n\n57Starting Liquibase at 22:19:14 (version 4.6.1 #98 built at 2021-11-04\n20:16+0000)\n\n58Liquibase Version: 4.6.1\n\n59Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun\n27 04:59:59 UTC 2022\n\n60Executing Quality Checks against changelog.sql\n\n61Executing all checks because a valid Liquibase Pro license was found!\n\n62Changesets Validated:\n\n63  ID: createTable_salesTableZ; Author: SteveZ; File path: changelog.sql\n\n64Checks run against each changeset:\n\n65  Warn on Detection of 'GRANT' Statements\n\n66  Warn on Detection of 'REVOKE' Statements\n\n67  Warn when 'DROP TABLE' detected\n\n68  Warn when 'DROP COLUMN' detected\n\n69  Check for specific patterns in sql (Short Name: SqlCreateRoleCheck)\n\n70  Warn when 'TRUNCATE TABLE' detected\n\n71  Warn on Detection of grant that contains 'WITH ADMIN OPTION'\n\n72Liquibase command 'checks run' was executed successfully.\n\n```\n\n\nThe liquibase update command deploys the changes. If you choose, you can\nview a full report of your changes in [Liquibase\nHub](https://docs.liquibase.com/tools-integrations/liquibase-hub/setup.html).\nThe update command also saves the deployment log output file as an artifact.\n\n\n```\n\n227Starting Liquibase at 22:19:34 (version 4.6.1 #98 built at 2021-11-04\n20:16+0000)\n\n228Liquibase Version: 4.6.1\n\n229Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon\nJun 27 04:59:59 UTC 2022\n\n230----------------------------------------------------------------------\n\n231View a report of this operation at https://hub.liquibase.com/r/I7ens13ooM\n\n232* IMPORTANT: New users of Hub first need to Sign In to your account\n\n233with the one-time password sent to your email, which also serves as\n\n234your username.\n\n235----------------------------------------------------------------------\n\n236Logs saved to\n/home/gitlab-runner/builds/3-UvD4aX/0/szandany/sql_server/build-job_405710044.log\n\n237Liquibase command 'update' was executed successfully.\n\n```\n\n\nHere’s what your Liquibase Hub report will look like:\n\n\n![The hub report, part\none](https://about.gitlab.com/images/blogimages/6_LiquibaseHub_Report.png){:\n.shadow.small.center}\n\n\n![The hub report, part\ntwot](https://about.gitlab.com/images/blogimages/7_LiquibaseHub_Report.png){:\n.shadow.small.center}\n\n\nThe Liquibase history command will show what changes are currently in the\ndatabase.\n\n\n```\n\n255Starting Liquibase at 22:19:40 (version 4.6.1 #98 built at 2021-11-04\n20:16+0000)\n\n256Liquibase Version: 4.6.1\n\n257Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon\nJun 27 04:59:59 UTC 2022\n\n258Liquibase History for\njdbc:sqlserver://localhost:1433;sendTemporalDataTypesAsStringForBulkCopy=true;delayLoadingLobs=true;useFmtOnly=false;useBulkCopyForBatchInsert=false;cancelQueryTimeout=-1;sslProtocol=TLS;jaasConfigurationName=SQLJDBCDriver;statementPoolingCacheSize=0;serverPreparedStatementDiscardThreshold=10;enablePrepareOnFirstPreparedStatementCall=false;fips=false;socketTimeout=0;authentication=NotSpecified;authenticationScheme=nativeAuthentication;xopenStates=false;sendTimeAsDatetime=true;trustStoreType=JKS;trustServerCertificate=false;TransparentNetworkIPResolution=true;serverNameAsACE=false;sendStringParametersAsUnicode=true;selectMethod=direct;responseBuffering=adaptive;queryTimeout=-1;packetSize=8000;multiSubnetFailover=false;loginTimeout=15;lockTimeout=-1;lastUpdateCount=true;encrypt=false;disableStatementPooling=true;databaseName=DEV;columnEncryptionSetting=Disabled;applicationName=Microsoft\nJDBC Driver for SQL Server;applicationIntent=readwrite;\n\n259- Database updated at 11/9/21, 10:19 PM. Applied 1 changeset(s),\nDeploymentId: 6496372605\n\n260  liquibase-internal::1636496372758::liquibase\n\n261- Database updated at 11/9/21, 10:19 PM. Applied 1 changeset(s),\nDeploymentId: 6496375151\n\n262  changelog.sql::createTable_salesTableZ::SteveZ\n\n263Liquibase command 'history' was executed successfully.\n\n```\n\n\n### Clicking into the DEV->QA job example from your pipeline\n\n\nWe run the liquibase diff command to compare the DEV and QA databases. This\nhelps detect any drift between the databases.\n\n\nNotice in the log output that there are some unexpected changes: \n\n\ntable named bad_table\n\n\nprocedure named bad_proc\n\n\n![The diff\nreport](https://about.gitlab.com/images/blogimages/8_LiquibaseDiff_Report.png){:\n.shadow.small.center}\n\n\nBy using the [Liquibase Pro trial license\nkey](https://www.liquibase.com/trial), you’re able to detect any stored\nlogic objects included in the diff report. Liquibase Pro also allows you to\ngenerate a parsable JSON output file and save it as an artifact for later\nuse.\n\n\n```\n\n137Starting Liquibase at 22:21:10 (version 4.6.1 #98 built at 2021-11-04\n20:16+0000)\n\n138Liquibase Version: 4.6.1\n\n139Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon\nJun 27 04:59:59 UTC 2022\n\n140Output saved to\n/home/gitlab-runner/builds/3-UvD4aX/0/szandany/sql_server/diff_between_DEV_QA.json\n\n141Liquibase command 'diff' was executed successfully.\n\n```\n\n\nJSON artifact output file example:\n\n\n```\n\n{\n    \"diff\": {\n        \"diffFormat\": 1,\n        \"created\": \"Wed Dec 08 20:16:53 UTC 2021\",\n        \"databases\": {\n            \"reference\": {\n                \"majorVersion\": \"14\",\n                \"minorVersion\": \"00\",\n                \"name\": \"Microsoft SQL Server\",\n                \"url\": \"jdbc:sqlserver://localhost:1433;databaseName=DEV; ...\"\n            },\n            \"target\": {\n                \"majorVersion\": \"14\",\n                \"minorVersion\": \"00\",\n                \"name\": \"Microsoft SQL Server\",\n                \"url\": \"jdbc:sqlserver://localhost:1433;databaseName=QA; ...\"\n            }\n        },\n        \"unexpectedObjects\": [\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"bad_proc\",\n                    \"type\": \"storedProcedure\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"bad_table\",\n                    \"type\": \"table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"MARKET\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"ID\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"NAME\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            },\n            {\n                \"unexpectedObject\": {\n                    \"name\": \"REGION\",\n                    \"type\": \"column\",\n                    \"relationName\": \"bad_table\",\n                    \"schemaName\": \"dbo\",\n                    \"catalogName\": \"QA\"\n                }\n            }\n        ],\n        \"changedObjects\": [\n            {\n                \"changedObject\": {\n                    \"name\": \"QA\",\n                    \"type\": \"catalog\",\n                    \"differences\": [\n                        {\n                            \"difference\": {\n                                \"comparedValue\": \"QA\",\n                                \"field\": \"name\",\n                                \"message\": \"name changed from 'DEV' to 'QA'\",\n                                \"referenceValue\": \"DEV\"\n                            }\n                        }\n                    ]\n                }\n            }\n        ]\n    }\n}\n\n\n```\n\n\nNote that the [Liquibase\ndiffChangelog](https://docs.liquibase.com/commands/diffchangelog.html) can\nhelp any baseline environments that have drifted. \n\n\nClicking into the snapshot PROD job example, the snapshot file contains all\nthe current schema changes represented in a JSON file. You can obtain the\nPROD database snapshot file to compare two states of the same database to\nprotect against malware with drift detection.\n\n\n```\n\n58Starting Liquibase at 22:21:32 (version 4.6.1 #98 built at 2021-11-04\n20:16+0000)\n\n59Liquibase Version: 4.6.1\n\n60Liquibase Pro 4.6.1 by Liquibase licensed to customersuccess until Mon Jun\n27 04:59:59 UTC 2022\n\n61Output saved to\n/home/gitlab-runner/builds/3-UvD4aX/0/szandany/sql_server/snapshot_PROD.json\n\n62Liquibase command 'snapshot' was executed successfully. \n\n64Uploading artifacts for successful job00:01\n\n70Cleaning up project directory and file based variables00:00\n\n72Job succeeded\n\n```\n\n\n### Congratulations! The pipeline ran successfully.\n\n\nIf all the jobs are successful, you’ll see a green checkmark right next to\neach one.\n\n\nHere’s what your database changes will look like with a database SQL query\ntool.\n\n\n![The\ndatabase](https://about.gitlab.com/images/blogimages/9_Database_Changes_SQL_Query_Tool.png){:\n.shadow.small.center}\n\n\n## Summing it up\n\n\nYou’ve now successfully run Liquibase in a GitLab pipeline to enable true\nCI/CD for the database. You can easily keep adding more changes to the\ndatabase by adding more Liquibase changesets to the changelog, commit them\nto GitLab version control, and repeat the merge request process described in\nthis tutorial to add the changes. \n\n\nStill have questions or want support integrating Liquibase with your Gitlab\nCI/CD Pipeline? Our team of database DevOps experts is happy to help! \n\n\n[Contact Liquibase](https://www.liquibase.com/contact)\n\n\n[Contact GitLab](/sales/)\n\n\nContact a [certified GitLab channel\npartner](https://www.google.com/url?q=https://partners.gitlab.com/English/directory/&sa=D&source=docs&ust=1641393355697069&usg=AOvVaw0R5mPukwMBR2dKsn3eQzqp)\n\n\nContact a [Liquibase channel partner](https://www.liquibase.com/partners)\n\n\nOther useful links: \n\n\n[Gitlab CI/CD setup Liquibase\ndocumentation](https://docs.liquibase.com/concepts/installation/setup-gitlab-cicd.html)\n\n\n[GitLab - Liquibase\nrepository](https://gitlab.com/gitlab-com/alliances/liquibase/sandbox-projects/liquibasegitlabcicd/-/blob/master/README.md) \n\n\nGet a [speedy, secure database developer\nflow](https://www.liquibase.com/blog/secure-database-developer-flow-using-gitlab-pipelines)\nusing GitLab pipelines & Liquibase\n\n\n_Author Tsvi Zandany is a Senior Solutions Architect at Liquibase_\n",[9,785,2168],"CD",{"slug":2170,"featured":6,"template":696},"how-to-bring-devops-to-the-database-with-gitlab-and-liquibase","content:en-us:blog:how-to-bring-devops-to-the-database-with-gitlab-and-liquibase.yml","How To Bring Devops To The Database With Gitlab And Liquibase","en-us/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase.yml","en-us/blog/how-to-bring-devops-to-the-database-with-gitlab-and-liquibase",{"_path":2176,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2177,"content":2182,"config":2189,"_id":2191,"_type":13,"title":2192,"_source":15,"_file":2193,"_stem":2194,"_extension":18},"/en-us/blog/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io",{"title":2178,"description":2179,"ogTitle":2178,"ogDescription":2179,"noIndex":6,"ogImage":819,"ogUrl":2180,"ogSiteName":683,"ogType":684,"canonicalUrls":2180,"schema":2181},"Review Apps for Android with GitLab, fastlane & Appetize.io","See how GitLab and Appetize.io can bring Review Apps to your Android project","https://about.gitlab.com/blog/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to create Review Apps for Android with GitLab, fastlane, and Appetize.io\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Andrew Fontaine\"}],\n        \"datePublished\": \"2020-05-06\",\n      }",{"title":2183,"description":2179,"authors":2184,"heroImage":819,"date":2186,"body":2187,"category":714,"tags":2188},"How to create Review Apps for Android with GitLab, fastlane, and Appetize.io",[2185],"Andrew Fontaine","2020-05-06","{::options parse_block_html=\"true\" /}\n\n\n\n\nIn a [previous look at GitLab and _fastlane_], we discussed how _fastlane_\nnow\n\nautomatically publishes the Gitter Android app to the Google Play Store, but\nat\n\nGitLab, we live on [review apps], and review apps for Android applications\ndidn't\n\nreally exist... until [Appetize.io] came to our attention.\n\n\nJust a simple extension of our existing `.gitlab-ci.yml`, we can utilize\n\nAppetize.io to spin up review apps of our Android application.\n\n\nIf you'd rather just skip to the end, you can see\n\n[my MR to the Gitter Android project].\n\n\n## Setting up Fastlane\n\n\nFortunately for us, _fastlane_ has integrated support for Appetize.io, so\nall\n\nthat's needed to hit Appetize is the addition of a new `lane`:\n\n\n```diff\n\ndiff --git a/fastlane/Fastfile b/fastlane/Fastfile\n\nindex eb47819..f013a86 100644\n\n--- a/fastlane/Fastfile\n\n+++ b/fastlane/Fastfile\n\n@@ -32,6 +32,13 @@ platform :android do\n     gradle(task: \"test\")\n   end\n\n+  desc 'Pushes the app to Appetize and updates a review app'\n\n+  lane :review do\n\n+    appetize(api_token: ENV['APPETIZE_TOKEN'],\n\n+             path: 'app/build/outputs/apk/debug/app-debug.apk',\n\n+             platform: 'android')\n\n+  end\n\n+\n   desc \"Submit a new Internal Build to Play Store\"\n   lane :internal do\n     upload_to_play_store(track: 'internal', apk: 'app/build/outputs/apk/release/app-release.apk')\n```\n\n\n`APPETIZE_TOKEN` is an Appetize.io API token that can be generated on the\n\n[Appetize API docs] after signing up for an account. Once we add a new job\nand\n\nstage to our `.gitlab-ci.yml`, we will be able to deploy our APK to Appetize\nand\n\nrun them in the browser!\n\n\n```diff\n\ndiff --git a/.gitlab-ci.yml b/.gitlab-ci.yml\n\nindex d9863d7..e4d0ce3 100644\n\n--- a/.gitlab-ci.yml\n\n+++ b/.gitlab-ci.yml\n\n@@ -5,6 +5,7 @@ stages:\n   - environment\n   - build\n   - test\n+  - review\n   - internal\n   - alpha\n   - beta\n@@ -81,6 +82,16 @@ buildRelease:\n   environment:\n     name: production\n\n+deployReview:\n\n+  stage: review\n\n+  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n\n+  script:\n\n+    - bundle exec fastlane review\n\n+  only:\n\n+    - branches\n\n+  except:\n\n+    - master\n\n+\n testDebug:\n   image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n   stage: test\n```\n\n\nGreat! Review apps will be deployed when branches other than `master` build.\n\nUnfortunately, there is no `environment` block, so there's nothing linking\nthese\n\ndeployed review apps to GitLab. Let's fix that next.\n\n\n## Dynamic Environment URLs\n\n\nPreviously, GitLab only liked environment URLs that used pre-existing CI\n\nvariables (like `$CI_COMMT_REF_NAME`) in their definition. Since 12.9,\nhowever,\n\na [new way of defining environment urls with alternative variables exists].\n\n\nBy creating a `dotenv` file and submitting it as an `artifact` in our build,\nwe\n\ncan define custom variables to use in our environment's URL. As all\nAppetize.io\n\napp URLs take the pattern of `https://appetize.io.app/$PUBLIC_KEY`, where\n\n`$PUBLIC_KEY` is randomly generated when the app is created, we need to get\nthe\n\npublic key from the Appetize response in our `Fastfile`, and put it in a\n\n`dotenv` file.\n\n\n```diff\n\ndiff --git a/fastlane/Fastfile b/fastlane/Fastfile\n\nindex 7b5f9d1..ae3867c 100644\n\n--- a/fastlane/Fastfile\n\n+++ b/fastlane/Fastfile\n\n@@ -13,6 +13,13 @@\n # Uncomment the line if you want fastlane to automatically update itself\n # update_fastlane\n\n+\n\n+def update_deployment_url(pub_key)\n\n+  File.open('../deploy.env', 'w') do |f|\n\n+    f.write(\"APPETIZE_PUBLIC_KEY=#{pub_key}\")\n\n+  end\n\n+end\n\n+\n default_platform(:android)\n\n platform :android do\n@@ -37,6 +44,7 @@ platform :android do\n     appetize(api_token: ENV['APPETIZE_TOKEN'],\n              path: 'app/build/outputs/apk/debug/app-debug.apk',\n              platform: 'android')\n+    update_deployment_url(lane_context[SharedValues::APPETIZE_PUBLIC_KEY])\n   end\n\n   desc \"Submit a new Internal Build to Play Store\"\n```\n\n\nWe also need to add an `environment` block to our `.gitlab-ci.yml` to\ncapture an\n\nenvironment name and URL.\n\n\n```diff\n\ndiff --git a/.gitlab-ci.yml b/.gitlab-ci.yml\n\nindex f5a8648..c834077 100644\n\n--- a/.gitlab-ci.yml\n\n+++ b/.gitlab-ci.yml\n\n@@ -85,12 +85,18 @@ buildCreateReleaseNotes:\n deployReview:\n   stage: review\n   image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n+  environment:\n\n+    name: review/$CI_COMMIT_REF_NAME\n\n+    url: https://appetize.io/app/$APPETIZE_PUBLIC_KEY\n   script:\n     - bundle exec fastlane review\n   only:\n     - branches\n   except:\n     - master\n+  artifacts:\n\n+    reports:\n\n+      dotenv: deploy.env\n\n testDebug:\n   image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n```\n\n\nOnce committed, pushed, and a pipeline runs, we should see our environment\n\ndeployed!\n\n\n![Our first review environment][first-review-app]\n\n\n## Optimizing Updates\n\n\nAfter running with this for a bit, we realized that we were accidentally\n\ncreating a new app on Appetize.io with every new build! Their docs\n\n[specify how to update existing apps], so we went about seeing if we could\n\nsmartly update existing environments.\n\n\nSpoiler alert: We could.\n\n\nFirst, we need to save the public key granted to us by Appetize.io\nsomewhere. We\n\ndecided to put it in a JSON file and save that as an artifact of the build.\n\nFortunately, the `Fastfile` is just ruby, which allows us to quickly write\nit\n\nout to a file with a few lines of code, as well as attempt to fetch the\nartifact\n\nfor the last build of the current branch.\n\n\n```diff\n\ndiff --git a/fastlane/Fastfile b/fastlane/Fastfile\n\nindex ae3867c..61e9226 100644\n\n--- a/fastlane/Fastfile\n\n+++ b/fastlane/Fastfile\n\n@@ -13,8 +13,32 @@\n # Uncomment the line if you want fastlane to automatically update itself\n # update_fastlane\n\n+require 'net/http'\n\n+require 'json'\n\n+\n\n+GITLAB_TOKEN = ENV['PRIVATE_TOKEN']\n\n+PROJECT_ID = ENV['CI_PROJECT_ID']\n\n+REF = ENV['CI_COMMIT_REF_NAME']\n\n+JOB = ENV['CI_JOB_NAME']\n\n+API_ROOT = ENV['CI_API_V4_URL']\n\n+\n\n+def public_key\n\n+  uri =\nURI(\"#{API_ROOT}/projects/#{PROJECT_ID}/jobs/artifacts/#{REF}/raw/appetize-information.json?job=#{JOB}\")\n\n+  http = Net::HTTP.new(uri.host, uri.port)\n\n+  http.use_ssl = true\n\n+  req = Net::HTTP::Get.new(uri)\n\n+  req['PRIVATE-TOKEN'] = GITLAB_TOKEN\n\n+  response = http.request(req)\n\n+  return '' if response.code.equal?('404')\n\n+\n\n+  appetize_info = JSON.parse(response.body)\n\n+  appetize_info['publicKey']\n\n+end\n\n def update_deployment_url(pub_key)\n+  File.open('../appetize-information.json', 'w') do |f|\n\n+    f.write(JSON.generate(publicKey: pub_key))\n\n+  end\n   File.open('../deploy.env', 'w') do |f|\n     f.write(\"APPETIZE_PUBLIC_KEY=#{pub_key}\")\n   end\n@@ -42,6 +66,7 @@ platform :android do\n   desc 'Pushes the app to Appetize and updates a review app'\n   lane :review do\n     appetize(api_token: ENV['APPETIZE_TOKEN'],\n+             public_key: public_key,\n              path: 'app/build/outputs/apk/debug/app-debug.apk',\n              platform: 'android')\n     update_deployment_url(lane_context[SharedValues::APPETIZE_PUBLIC_KEY])\n```\n\n\nWhen we go to deploy our app to Appetize, we hit the [Jobs API] to see if we\n\nhave a public key for this branch. If the API returns a `404`, we know we\nare\n\nbuilding a fresh branch and return an empty string, else we parse the JSON\nand\n\nreturn our public key. The [Fastlane docs] state the `appetize` action can\ntake\n\na `public_key` to update an existing app. Here, `''` is considered the same\nas\n\n_not_ providing a public key, so a new application is still deployed as we\nexpect.\n\n\n**NOTE:** If you've read the `diff` closely, you'll notice the usage of an\n\nenvironment variable called `PRIVATE_TOKEN`. This is a GitLab private token\n\ncreated with the `read_api` scope and injected into our build as an\nenvironment\n\nvariable. This is required to authenticate with the GitLab API and fetch\n\nartifacts.\n\n\nOnce we update `.gitlab-ci.yml` to save the new `appetize-information.json`\nfile\n\nas an artifact, later builds on the same branch will be smart and update the\n\nexisting Appetize app!\n\n\n```diff\n\ndiff --git a/.gitlab-ci.yml b/.gitlab-ci.yml\n\nindex c834077..54cf3f6 100644\n\n--- a/.gitlab-ci.yml\n\n+++ b/.gitlab-ci.yml\n\n@@ -95,6 +95,8 @@ deployReview:\n   except:\n     - master\n   artifacts:\n+    paths:\n\n+      - appetize-information.json\n     reports:\n       dotenv: deploy.env\n```\n\n\n## Cleaning up\n\n\nAll that's left is to delete old apps from Appetize once we don't need them\n\nanymore. We can do that by leveraging `on_stop` and creating a `stop` job\nthat\n\nwill delete our app from Appetize.io\n\n\n```diff\n\ndiff --git a/.gitlab-ci.yml b/.gitlab-ci.yml\n\nindex 54cf3f6..f6ecf7e 100644\n\n--- a/.gitlab-ci.yml\n\n+++ b/.gitlab-ci.yml\n\n@@ -10,6 +10,7 @@ stages:\n   - alpha\n   - beta\n   - production\n+  - stop\n\n\n .updateContainerJob:\n@@ -88,6 +89,7 @@ deployReview:\n   environment:\n     name: review/$CI_COMMIT_REF_NAME\n     url: https://appetize.io/app/$APPETIZE_PUBLIC_KEY\n+    on_stop: stopReview\n   script:\n     - bundle exec fastlane review\n   only:\n@@ -100,6 +102,22 @@ deployReview:\n     reports:\n       dotenv: deploy.env\n\n+stopReview:\n\n+  stage: stop\n\n+  environment:\n\n+    name: review/$CI_COMMIT_REF_NAME\n\n+    action: stop\n\n+  variables:\n\n+    GIT_STRATEGY: none\n\n+  when: manual\n\n+  only:\n\n+    - branches\n\n+  except:\n\n+    - master\n\n+  script:\n\n+    - apt-get -y update && apt-get -y upgrade && apt-get -y install jq curl\n\n+    - curl --request DELETE\nhttps://$APPETIZE_TOKEN@api.appetize.io/v1/apps/`jq -r '.publicKey' \u003C\nappetize-information.json`\n\n+\n testDebug:\n   image: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG\n   stage: test\n```\n\n\nOnce your MR is merged and your branch is deleted, the `stopReview` job\nruns,\n\ncalling the [`DELETE` endpoint of the Appetize.io API] with the public key\nthat\n\nis contained in `appetize-information.json`. We don't need to fetch\n\n`appetize-information.json` because the artifact is already present in our\nbuild\n\ncontext. This is because the `stop` stage happens _after_ the `review`\nstage.\n\n\n![A merge request with a deployed review app][merge-request-with-review-app]\n\n\n## Conclusion\n\n\nThanks to some integration with _fastlane_ and the addition of a couple\n\nenvironment variables, having the ability to create review apps for an\nAndroid\n\nproject was surpsingly simple. GitLab's review apps are not _just_ for\nweb-based\n\nprojects, even though it may take a little tinkering to get working.\nAppetize.io\n\nalso supports iOS applications, so all mobile native applications can be\nturned\n\ninto review apps. I would love to see this strategy be applied to a React\nNative\n\nproject as well!\n\n\n[previous look at gitlab and _fastlane_]:\n/blog/android-publishing-with-gitlab-and-fastlane/\n\n[my mr to the gitter android project]:\nhttps://gitlab.com/gitlab-org/gitter/gitter-android-app/-/merge_requests/167\n\n[review apps]: https://docs.gitlab.com/ee/ci/review_apps/#review-apps\n\n[appetize.io]: https://appetize.io\n\n[appetize api docs]: https://appetize.io/docs#request-api-token\n\n[new way of defining environment urls with alternative variables exists]:\nhttps://docs.gitlab.com/ee/ci/environments/index.html#set-dynamic-environment-urls-after-a-job-finishes\n\n[first-review-app]:\n/images/blogimages/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io/first-review-app.png\n\n[specify how to update existing apps]:\nhttps://appetize.io/docs#updating-apps\n\n[jobs api]:\nhttps://docs.gitlab.com/ee/api/jobs.html#download-a-single-artifact-file-from-specific-tag-or-branch\n\n[fastlane docs]: https://docs.fastlane.tools/actions/appetize/\n\n[`delete` endpoint of the appetize.io api]:\nhttps://appetize.io/docs#deleting-apps\n\n[merge-request-with-review-app]:\n/images/blogimages/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io/merge-request-with-review-app.png\n",[108,9,742,807],{"slug":2190,"featured":6,"template":696},"how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io","content:en-us:blog:how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io.yml","How To Create Review Apps For Android With Gitlab Fastlane And Appetize Dot Io","en-us/blog/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io.yml","en-us/blog/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io",{"_path":2196,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2197,"content":2203,"config":2209,"_id":2211,"_type":13,"title":2212,"_source":15,"_file":2213,"_stem":2214,"_extension":18},"/en-us/blog/how-to-deploy-a-php-app-using-gitlabs-cloud-run-integration",{"title":2198,"description":2199,"ogTitle":2198,"ogDescription":2199,"noIndex":6,"ogImage":2200,"ogUrl":2201,"ogSiteName":683,"ogType":684,"canonicalUrls":2201,"schema":2202},"How to deploy a PHP app using GitLab's Cloud Run integration","Are you using PHP and want an easy way to deploy your application to Google Cloud? Follow this guide to deploy your app with Google Cloud Run in under 10 minutes.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098264/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_519147119_2RafH61mqosMZv8HGAlsUj_1750098264407.jpg","https://about.gitlab.com/blog/how-to-deploy-a-php-app-using-gitlabs-cloud-run-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to deploy a PHP app using GitLab's Cloud Run integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Christian Nnachi\"},{\"@type\":\"Person\",\"name\":\"Noah Ing\"}],\n        \"datePublished\": \"2024-12-10\",\n      }",{"title":2198,"description":2199,"authors":2204,"heroImage":2200,"date":2206,"body":2207,"category":739,"tags":2208},[2205,994],"Christian Nnachi","2024-12-10","Writing PHP application code and ensuring the application is running\nsmoothly in production are often two different skills sets owned by two\ndifferent engineers. GitLab aims to bridge the gap by enabling the engineer\nwho has written the PHP application code to also deploy it into Google Cloud\nPlatform with little effort. \n\n\nWhether you own event-driven, long-running services or deploy containerized\njobs to process data, Google Cloud Run automatically scales your containers\nup and down from zero — this means you only pay when your code is running.\n\n\nIf you are a PHP developer who would like to deploy your application with\nminimal effort to Google Cloud Platform, this guide will show you how using\nthe GitLab Google Cloud Run integration. \n\n\n# Overview\n\n\n- Create a new project in GitLab\n\n- Set up your PHP application\n\n- Utilizing the Google Cloud integration, create a Service account\n\n- Utilizing the Google Cloud integration, configure Cloud Run via merge\nrequest\n\n- Try adding another endpoint\n\n- Clean up\n\n\n## Prerequisites\n\n- Owner access on a Google Cloud Platform project\n\n- Working knowledge of\n[PHP](https://www.php.net/manual/en/introduction.php), an open-source,\ngeneral-purpose scripting language\n\n- Working knowledge of [GitLab\nCI](https://about.gitlab.com/topics/ci-cd/#what-is-continuous-integration-ci)\n\n- 10 minutes\n\n\n## 1. Create a new project in GitLab.\n\n\nWe decided to call our project `PHP cloud-run` for simplicity.\n\n\n![PHP cloud- run\nproject](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098287/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750098287615.png)\n\n\nThen, create an index.php\napp[https://gitlab.com/demos/templates/php-cloud-run/-/blob/main/index.php](https://gitlab.com/demos/templates/php-cloud-run/-/blob/main/index.php).\n\n\n```php\n\n\u003C?php\n\n\n$name = getenv('NAME', true) ?: 'World';\n\necho sprintf('Hello %s!', $name);\n\n```\n\n\n## 2. Utilizing the Google Cloud integration, create a Service account.\n\n\nNavigate to **Operate > Google Cloud > Create Service account**. \n\n\n![Create Service account\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image10_aHR0cHM6_1750098287616.png)\n\n\nThen configure the region you would like the Cloud Run instance deployed to.\n\n\n![Configure region\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750098287618.png)\n\n\n## 3. Utilizing the Google Cloud integration, configure **Cloud Run via\nmerge request**.\n\n\n![Deployment configuration\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image6_aHR0cHM6_1750098287620.png)\n\n\nThis will open a merge request. Immediately merge this merge request.\n\n\n![Enable Deployments to Cloud run\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750098287622.png)\n\n\n**Note:** `GCP_PROJECT_ID`, `GCP_REGION`,  `GCP_SERVICE_ACCOUNT`, and\n`GCP_SERVICE_ACCOUNT_KEY` will all be automatically populated from the\nprevious steps.\n\n\n![Variables\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750098287624.png)\n\n\nCheck your pipeline and you will see you have successfully deployed to\nGoogle Cloud Run utilizing GitLab CI.\n\n\n![merge branch\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image7_aHR0cHM6_1750098287625.png)\n\n\n\u003Cbr>\u003C/br>\n\n\n![Google Cloud Run deployed with GitLab\nCI](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750098287627.png)\n\n\n## 4. Click the **Service URL** to view your newly deployed Flask server.\n\n\nIn addition, you can navigate to **Operate > Environments** to see a list of\ndeployments for your environments.\n\n\n![Environments\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image9_aHR0cHM6_1750098287628.png)\n\n\nBy clicking on the environment called **main**, you’ll be able to view a\ncomplete list of deployments specific to that environment.\n\n\n![Main\nenvironment](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098288/Blog/Content%20Images/Blog/Content%20Images/image8_aHR0cHM6_1750098287631.png)\n\n\n## 5. Add another endpoint\n\n\nTo get started with developing your PHP application, try adding another\nendpoint. For example, in your main file, you can add a `/bye` endpoint like\nthis:\n\n\n```\n\n\n\u003C?php\n\n\n$name = getenv('NAME', true) ?: 'World';\n\n\nif ($_SERVER['REQUEST_URI'] == '/bye') {\n    echo sprintf('Goodbye %s!', $name);\n} else {\n    echo sprintf('Hello %s!', $name);\n}\n\n\n```\n\n\nPush the changes to the repo, and watch the `deploy-to-cloud-run` job deploy\nthe updates. Once the job is complete, go back to the Service URL and\nnavigate to the `/bye` endpoint to see the new functionality in action.\n\n\n### Clean up\n\n\nTo prevent incurring charges on your Google Cloud account for the resources\nused in this tutorial, you can either delete the specific resources or\ndelete the entire Google Cloud project. For detailed instructions, refer to\nthe [cleanup guide\nhere](https://docs.gitlab.com/ee/tutorials/create_and_deploy_web_service_with_google_cloud_run_component/#clean-up).\n\n\n> Check out more [easy-to-follow tutorials from our Solutions Architecture\nteam](https://about.gitlab.com/blog/tags/solutions-architecture/).\n",[998,807,741,9],{"slug":2210,"featured":6,"template":696},"how-to-deploy-a-php-app-using-gitlabs-cloud-run-integration","content:en-us:blog:how-to-deploy-a-php-app-using-gitlabs-cloud-run-integration.yml","How To Deploy A Php App Using Gitlabs Cloud Run Integration","en-us/blog/how-to-deploy-a-php-app-using-gitlabs-cloud-run-integration.yml","en-us/blog/how-to-deploy-a-php-app-using-gitlabs-cloud-run-integration",{"_path":2216,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2217,"content":2223,"config":2230,"_id":2232,"_type":13,"title":2233,"_source":15,"_file":2234,"_stem":2235,"_extension":18},"/en-us/blog/how-to-easily-launch-gitlab-through-cloud-marketplaces",{"title":2218,"description":2219,"ogTitle":2218,"ogDescription":2219,"noIndex":6,"ogImage":2220,"ogUrl":2221,"ogSiteName":683,"ogType":684,"canonicalUrls":2221,"schema":2222},"How to easily launch GitLab through cloud marketplaces","Bitnami makes publishing GitLab into Azure Marketplace simple.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670001/Blog/Hero%20Images/bitnami-gitlab-cloud.png","https://about.gitlab.com/blog/how-to-easily-launch-gitlab-through-cloud-marketplaces","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to easily launch GitLab through cloud marketplaces\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Miranda Carter\"},{\"@type\":\"Person\",\"name\":\"Vick Kelkar\"}],\n        \"datePublished\": \"2020-09-30\",\n      }",{"title":2218,"description":2219,"authors":2224,"heroImage":2220,"date":2227,"body":2228,"category":763,"tags":2229},[2225,2226],"Miranda Carter","Vick Kelkar","2020-09-30","\n\nToday almost every enterprise in the world moved at least some of its mission-critical workloads into public cloud environments, making it increasingly important that customers can easily deploy and manage their software in any cloud. All of the major cloud vendors have introduced marketplaces where customers can quickly deploy applications into their cloud computing infrastructure.\n\n[Bitnami](https://bitnami.com/), now part of VMware, has long partnered with the leading cloud vendors to provide a library of open source software in their marketplaces that is always up-to-date, packaged using best practices, and completely free to end users. Bitnami and GitLab worked together for years on publishing [GitLab Community Edition (CE)](/install/?version=ce) as part of this library.\n\n### The Bitnami and GitLab partnership advantage\n\nGitLab CE provides value to millions of organizations and community contributors, and this has only been enhanced by our partnership with Bitnami. By taking the GitLab CE open [source code](/solutions/source-code-management/) and packaging it in a way that is always up-to-date and easy to use out-of-the-box on almost any cloud platform, Bitnami has helped make GitLab CE accessible to hundreds of thousands of users.\n\nThe GitLab team is working with Bitnami to eliminate the complexity of packaging our enterprise application for multiple cloud marketplaces, in the same way they do for GitLab CE. This partnership enables the various marketplaces to receive timely updates of the GitLab Enterprise Edition (EE) software packages whenever there is a security issue or dependency update.\n\n### GitLab Enterprise Edition packaged by Bitnami is available on Microsoft Azure marketplace\n\nToday, we are pleased to announce that our partnership with Bitnami has helped make [GitLab EE](/install/) available in the [Microsoft Azure marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/gitlabinc1586447921813.gitlabee?tab=Overview). GitLab EE customers will be able to seamlessly deploy and use the application in these environments thanks to Bitnami’s expertise in packaging and publishing software for the public cloud.\n\nExisting customers can bring their licenses and apply them to GitLab EE in any of these environments. GitLab EE is also published by Bitnami in the VMware Cloud marketplace.\n\n### Software support for marketplace packages\n\nCustomers who deploy GitLab EE packaged by Bitnami will enjoy the same enterprise-level support that GitLab customers receive in any other supported environment. Customers who have deployed GitLab software into the cloud infrastructure already through the cloud marketplace must follow the normal GitLab software upgrade process to address any critical issues and vulnerabilities.\n\n### About the authors\n\n_[Vick Kelkar](/company/team/#vkelkar) is on Alliances team at GitLab. He has experience developing and running products for container orchestrators like Cloud Foundry and Kubernetes._\n\n_Miranda Carter has been part of the Bitnami team for over six years, and came to VMware as part of the VMware acquisition last year. Miranda is now a Program Manager at VMware and focuses on supporting Tanzu Application Catalog and supporting ISVs whenever possible._\n",[1988,108,851,9],{"slug":2231,"featured":6,"template":696},"how-to-easily-launch-gitlab-through-cloud-marketplaces","content:en-us:blog:how-to-easily-launch-gitlab-through-cloud-marketplaces.yml","How To Easily Launch Gitlab Through Cloud Marketplaces","en-us/blog/how-to-easily-launch-gitlab-through-cloud-marketplaces.yml","en-us/blog/how-to-easily-launch-gitlab-through-cloud-marketplaces",{"_path":2237,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2238,"content":2244,"config":2250,"_id":2252,"_type":13,"title":2253,"_source":15,"_file":2254,"_stem":2255,"_extension":18},"/en-us/blog/how-to-get-gitops-right-with-iac-security",{"title":2239,"description":2240,"ogTitle":2239,"ogDescription":2240,"noIndex":6,"ogImage":2241,"ogUrl":2242,"ogSiteName":683,"ogType":684,"canonicalUrls":2242,"schema":2243},"How to get GitOps right with infrastructure as code security","Learn how the GitLab and Indeni integration makes security a core component of your GitOps workflow.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663403/Blog/Hero%20Images/gitops-partner-cover-image.jpg","https://about.gitlab.com/blog/how-to-get-gitops-right-with-iac-security","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to get GitOps right with infrastructure as code security\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Ulrica de Fort-Menares\"}],\n        \"datePublished\": \"2021-06-10\",\n      }",{"title":2239,"description":2240,"authors":2245,"heroImage":2241,"date":2247,"body":2248,"category":739,"tags":2249},[2246],"Ulrica de Fort-Menares","2021-06-10","\nIn today's competitive digital era, it is imperative for organizations to undergo a digital transformation to effectively compete. For many, achieving a digital transformation means transitioning toward a DevOps model.\n\nDevOps has been around for many years, and the development side of the house has benefitted from the core practices of DevOps. However, the infrastructure side of the house has been lagging behind, particularly when it comes to speed. With [infrastructure as code (IaC)](/topics/gitops/infrastructure-as-code/) and [GitOps](/topics/gitops/), infrastructure teams have been able to apply the same disciplines and quality gates that are used to manage application code to the infrastructure - to deliver products faster, with more predictability and at scale.\n\n## Security slowing down delivery\n\nWhile the GitOps concept promises faster and more frequent deployment, the last thing you want is to be slowed down by your legacy security programs. How often has your release stopped near the end of process because it failed the security gate? All too often security testing is tacked on at the end of delivery. Developers inevitably spend significant time and energy investigating these security issues, which delays the release. Uncovering issues late in the cycle is expensive and painful to fix, not to mention creating unnecessary stress.\n\nThe software development process has been shifting left to deliver better-quality software faster. By using IaC, you can adopt the same DevOps principle for the infrastructure. Learning from the development world, you should integrate security controls into the development lifecycle early and everywhere.\n\n## How to shift your IaC security checks left\n\nThe core of the partnership between Indeni and GitLab is about making security a key part of the GitOps practice. The [Indeni Cloudrail](https://indeni.com/cloudrail/) and GitLab CI/CD integration brings IaC security into the tools that developers are familiar with and want to use.\n\n![GitOps workflow](https://about.gitlab.com/images/blogimages/secure-gitops-workflow.png){: .shadow}\nHow GitLab CI/CD fits into the Indeni Cloudrail DevOps workflow.\n{: .note.text-center}\n\nThe joint solution modernizes security programs with the shift-left approach and automates infrastructure compliance. Developers no longer need to get in line for security reviews. Instead, IaC will be automatically evaluated for security impacts. Security controls are integrated into the development lifecycle before deployment.\n\n![GitOps workflow](https://about.gitlab.com/images/blogimages/secure-gitops1.jpg){: .shadow}\nCatching IaC security violations in GitLab CI/CD.\n{: .note.text-center}\n\nAs shown in the example above, Indeni Cloudrail provides feedback in GitLab CI. This way, security risks relating to the infrastructure can be instantly remediated when they are made so developers can move fast. You can think of the shift security left approach as testing IaC continuously and preventing insecure infrastructure from being deployed.\n\n## Don't let those noisy security tools impede your GitOps practice\n\nSecurity tools are notorious for being noisy with their many false positives. According to the Advanced Technology Academic Research Center [(ATARC) Federal DevSecOps Landscape survey](https://atarc.org/project/devsecops-survey/), too many false positives is the number one frustration with security testing. A noisy security tool can be counterproductive by inadvertently stopping the pipeline frustrating your developers.\n\nWhat makes Indeni Cloudrail unique is its context-based analysis, which refers to its ability to understand the relationships among cloud resources, making in-depth security analyses possible. Cloudrail also factors in already existing resources in the cloud environment to gain a holistic view as part of its analysis. The end result is three times less noise than any comparable IaC security tools in the market. In essence, Cloudrail will only bother developers with problems that truly matter to the organization. Learn more about [what makes Cloudrail unique in this blog post](https://indeni.com/blog/comparing-cloudrail-checkov-tfsec-and-kics-with-testing/).\n\n## Why GitLab and Indeni are better together\n\nBy delivering a developer-centric security tool for IaC, security has a better chance of gaining acceptance in the developer community. Together, Indeni and GitLab equip developers with the right tools to support a GitOps model and help organizations with their digital transformation.\n\n## Watch the demo\n\nWatch the Cloudrail demo to see the GitOps workflow for IaC security.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/9WSd0D87Vxc\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n### About Indeni\n\n_[Indeni](https://indeni.com/) automates best practices for network security and cloud security. Its security infrastructure platform automates health and compliance checks for leading firewalls to maximize uptime and efficiency. Its Infrastructure-as-Code security analysis tool, Cloudrail, automates infrastructure compliance to prevent insecure cloud environments from being deployed._\n\nCover image by [Dimitry Anikin](https://unsplash.com/@anikinearthwalker) on [Unsplash](https://unsplash.com/photos/DsmjpJzm2i0)\n",[547,716,851,9],{"slug":2251,"featured":6,"template":696},"how-to-get-gitops-right-with-iac-security","content:en-us:blog:how-to-get-gitops-right-with-iac-security.yml","How To Get Gitops Right With Iac Security","en-us/blog/how-to-get-gitops-right-with-iac-security.yml","en-us/blog/how-to-get-gitops-right-with-iac-security",{"_path":2257,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2258,"content":2263,"config":2268,"_id":2270,"_type":13,"title":2271,"_source":15,"_file":2272,"_stem":2273,"_extension":18},"/en-us/blog/how-to-status-checks",{"title":2259,"description":2260,"ogTitle":2259,"ogDescription":2260,"noIndex":6,"ogImage":754,"ogUrl":2261,"ogSiteName":683,"ogType":684,"canonicalUrls":2261,"schema":2262},"How to use external status checks for merge requests","Want to integrate third-party systems and apps with GitLab merge requests? Here's everything you need to know.","https://about.gitlab.com/blog/how-to-status-checks","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to use external status checks for merge requests\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Cesar Saavedra\"}],\n        \"datePublished\": \"2021-10-04\",\n      }",{"title":2259,"description":2260,"authors":2264,"heroImage":754,"date":2265,"body":2266,"category":739,"tags":2267},[1565],"2021-10-04","\n\nThe [external status checks for merge requests capability](/releases/2021/07/22/gitlab-14-1-released/#external-status-checks-for-merge-requests) was recently introduced in GitLab and it allows the integration of third-party systems and applications with GitLab merge requests.\n\n## What are \"external status checks for merge requests\"?\n\nExternal status checks are API calls to systems or applications that sit outside GitLab. These API calls are invoked during merge requests, which display a widget with the status of each external check. With external status checks, you can integrate GitLab with third-party systems, e.g. Salesforce, PeopleSoft, Microsoft Dynamics, etc., that require manual approval for merge requests. This makes it easy to see that merge requests have met external requirements before being merged, adding an extra method to ensure compliance and audit requirements are met.\n\n## Steps to enable and use external status checks for merge requests\n\nIn this example, I have a sample project called **my-proj**, for which I'd like to add and exercise a single external status check, which will hypothetically do some kind of validation for the merge request.\n\n### Adding an external status check to your project\n\nExternal status checks are added to merge requests by heading to your project’s **Settings > General** and then expanding the **Merge requests** section. Towards the bottom of the **Merge requests** section, you will see an **Add status check** button, which you will need to click to to display the **Add status check** pop-up dialog:\n\n\u003C!--\n![Add status check dialog](https://about.gitlab.com/images/blogimages/how-to-status-checks/1-add-status-check-dialog.png){: .shadow.small.center.wrap-text}\nAdd status check dialog with filled values\n{: .note.text-center}\n-->\n\n\u003Cimg src=\"/images/blogimages/how-to-status-checks/1-add-status-check-dialog.png\" width=\"50%\" height=\"50%\">\nAdd status check dialog with filled values\n{: .note.text-center}\n\nIn the dialog above, the external service name is being given the name *compliance-check*. The external API that will be called is:\n\n> https://tech-marketing-sandbox-cd-compvalidator.compliance.gitlabworkshops.io/validate\n\n> **NOTE:** the *validate* service above was [a simple Java service that I set up](https://gitlab.com/tech-marketing/sandbox/cd/compvalidator) ahead of time to mimic a third-party external service. It returned an HTTP 200 success message when invoked. In a real life scenario, this external API call would be a SaaS service or an on-premises ERP system, for example.\n\nThe API above is a call - invoked from any merge requests created under this project - to an external system that will run a compliance check and validate modifications to this application.\n\nAs the target branch, the default *Any branch* has been selected. Another option could have been the *main* branch.\n\nWhen you click the **Add status check** button, an entry will be created in the **Status checks** table, as shown below:\n\n![status check table](https://about.gitlab.com/images/blogimages/how-to-status-checks/2-status-checks-table.png){: .shadow.small.center.wrap-text}\nStatus checks table\n{: .note.text-center}\n\n### External status check in action\n\nTo exercise the external status check for merge requests, we need to create a merge request. But before that, let's create an issue.\n\n1. Create an issue by clicking on **Issues > List** from the left vertical navigation menu to get to the Issues screen.\n\n2. Then click on the **New Issue** button\n\n3. On the **New Issue** window:\n\n3.1. In the Title field, enter \"External status check demo\"\n\n3.2. In the Description field, enter \"Issue to demonstrate an external status check\"\n\n3.3. Click on **Assign to me** next to the **Assignees** field\n\n3.4. Click on the **Create issue** button at the bottom of the window\n\n\u003C!--\n![issue create window](https://about.gitlab.com/images/blogimages/how-to-status-checks/3-issue-create-window.png){: .shadow.small.center.wrap-text}\nCreating an issue\n{: .note.text-center}\n-->\n\n\u003Cimg src=\"/images/blogimages/how-to-status-checks/3-issue-create-window.png\" width=\"75%\" height=\"75%\">\nCreating an issue\n{: .note.text-center}\n\nOnce the issue is created, you will be in the detail issue window.\n\n4. Click on the **Create merge request** button on the right hand side of the detailed issue window.\n\n![create a merge request](https://about.gitlab.com/images/blogimages/how-to-status-checks/4-create-merge-req.png){: .shadow.small.center.wrap-text}\nCreating a merge request\n{: .note.text-center}\n\nOnce the merge request is created, you will be in the detail merge request window.\n\n5. Click on the **Open in Web IDE** button on the right hand side of the detailed merge request window:\n\n![open webIDE](https://about.gitlab.com/images/blogimages/how-to-status-checks/5-open-webide.png){: .shadow.small.center.wrap-text}\nOpening the Web IDE\n{: .note.text-center}\n\n6. Make a minor update to the application. In the sample project **my-proj**, I modified two files: DemoApplication.java and DemoApplicationTests.java.\n\n6.1. In the DemoApplication.java class, I added the word \"today\" to the string returned by a call to this class:\n\n![update DemoApp](https://about.gitlab.com/images/blogimages/how-to-status-checks/6-update-demoapp.png){: .shadow.small.center.wrap-text}\nMaking a simple update to DemoApplication.java\n{: .note.text-center}\n\n6.2. In the DemoApplicationTests.java class, which is a unit test for DemoApplication.java, I also added the word \"today\" to the string in the *assertThat()* invocation to match the value returned by a call to the DemoApplication.java class:\n\n![update DemoAppTests](https://about.gitlab.com/images/blogimages/how-to-status-checks/7-update-demoapptests.png){: .shadow.small.center.wrap-text}\nMaking a simple update to DemoApplicationTests.java\n{: .note.text-center}\n\n7. Click on the **Commit…** button at the bottom of the Web IDE window. And then ensure to select the feature branch for the merge request before clicking on the **Commit** button again:\n\n\u003C!--\n![committing to feature branch](https://about.gitlab.com/images/blogimages/how-to-status-checks/8-click-commit.png){: .shadow.small.center.wrap-text}\nCommitting to the feature branch\n{: .note.text-center}\n-->\n\n\u003Cimg src=\"/images/blogimages/how-to-status-checks/8-click-commit.png\" width=\"30%\" height=\"30%\">\nCommitting to the feature branch\n{: .note.text-center}\n\n8. Go back to the merge request detail window by clicking on the merge request number on the bottom margin of the window:\n\n\u003C!--\n![click on merge request link](https://about.gitlab.com/images/blogimages/how-to-status-checks/9-click-mr-at-bottom.png){: .shadow.small.center.wrap-text}\nClicking on merge request link at bottom of window\n{: .note.text-center}\n-->\n\n\u003Cimg src=\"/images/blogimages/how-to-status-checks/9-click-mr-at-bottom.png\" width=\"75%\" height=\"75%\">\nClicking on merge request link at bottom of window\n{: .note.text-center}\n\n9. On the detail merge request window, scroll down until you see a section titled **Status checks 1 pending**. This is the merge request widget that lists all external status checks associated with merge requests. Click on the **Expand** button on the right hand side of this section:\n\n![expanding status checks widget](https://about.gitlab.com/images/blogimages/how-to-status-checks/10-click-on-expand.png){: .shadow.small.center.wrap-text}\nExpanding the status checks widget in the merge request\n{: .note.text-center}\n\n10. In the expanded section, you will see an entry for the external status check you defined above, whose name is *compliance-check*. Notice that to the left of its name, there is a pause symbol indicating to the merge request stakeholders that the check is still in progress and has not communicated its approval to the merge request yet:\n\n![list of status checks](https://about.gitlab.com/images/blogimages/how-to-status-checks/11-status-checks-widget-expanded.png){: .shadow.small.center.wrap-text}\nList of external status checks\n{: .note.text-center}\n\n11. In a real life scenario, the pause symbol would change to a green checkmark when the external status check communicates to GitLab that the compliance validation is finished, i.e. the merge request has been approved by the external service:\n\n![status checks passed](https://about.gitlab.com/images/blogimages/how-to-status-checks/12-status-check-passed.png){: .shadow.small.center.wrap-text}\nStatus checks that have passed\n{: .note.text-center}\n\n### How does an external status check inform GitLab that it has approved the merge request\n\nUsing an external status check integrates GitLab merge requests to a home-grown or SaaS application, for example, by invoking an API of this external system. Once this external system does its compliance validation or check, then it needs to inform GitLab that it has approved the merge request. To do this, the external system API must make use of the [GitLab external status checks API](https://docs.gitlab.com/ee/api/status_checks.html) to communicate to GitLab that the MR is approved. This is a 2-step process:\n\n1. The first step is to get the ID of the external status check you need to approve. Here is an example of how to invoke the GitLab API to do this:\n\n> curl --request GET --header \"PRIVATE-TOKEN: \u003Creplace with your GitLab API token>\" \"https://gitlab.com/api/v4/projects/28933616/merge_requests/1/status_checks\"\n\nAn example of what the command above will return follows:\n\n> [{\"id\":86,\"name\":\"compliance-check\",\"external_url\":\"https://tech-marketing-sandbox-cd-compvalidator.compliance.gitlabworkshops.io/validate\",\"status\":\"pending\"}]\n\nThe example return value above shows that the ID of the external status check that we’d like to approve is 86.\n\n> **NOTE:** Although I'm showing an example of how to invoke the GitLab API above using the *curl* command, the idea is that your external system API call would carry out any checks and validation and then it would assemble this message in a REST HTTP call back to GitLab to communicate its approval of the merge request.\n\n2. Once you have the ID of the external status check, you can then approve it by using the GitLab API. Here’s an example:\n\n> curl --request POST --header \"PRIVATE-TOKEN:\u003Creplace with your GitLab API token>\" \"https://gitlab.com/api/v4/projects/28933616/merge_requests/1/status_check_responses?sha=\u003Creplace with SHA at HEAD of the source branch>&external_status_check_id=86\"\n\nExecuting the REST API call above will approve the external status check on the GitLab merge request.\n\n```\nNOTE: to obtain the \u003CSHA at HEAD of the source branch>, here’s an example of the command you’d need to execute:\n\n$ git ls-remote https://gitlab.com/tech-marketing/sandbox/cd/my-proj.git\n\nThe URL in the preceding line is the URL to the git project for your merge request. And here’s an example of the output of the preceding command:\n\nad1eeee497c99466797a1155f514d3c0c2f0cc45\tHEAD\n9e209c8d409a0867c1df4e0965aa675277176137\trefs/heads/1-external-status-check-demo\nad1eeee497c99466797a1155f514d3c0c2f0cc45\trefs/heads/master\n9e209c8d409a0867c1df4e0965aa675277176137\trefs/merge-requests/1/head\n```\n\nIn the output above, the SHA for the feature branch associated with the merge request is *9e209c8d409a0867c1df4e0965aa675277176137*\n\n## What we've learned\n\nGitLab recently introduced \"external status checks for merge requests,\" which are effectively API calls to systems/application that sit outside GitLab. As you could see, with external status checks for merge requests, we were able to integrate GitLab with a third-party system that required manual approval for a merge request, ensuring that your application updates meet compliance and audit requirements.\n\nFor a demo of this feature in action, watch the video below:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/v4iY8qMvFLo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n",[9,872,851],{"slug":2269,"featured":6,"template":696},"how-to-status-checks","content:en-us:blog:how-to-status-checks.yml","How To Status Checks","en-us/blog/how-to-status-checks.yml","en-us/blog/how-to-status-checks",{"_path":2275,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2276,"content":2282,"config":2289,"_id":2291,"_type":13,"title":2292,"_source":15,"_file":2293,"_stem":2294,"_extension":18},"/en-us/blog/incident-management-with-aws-cloudwatch",{"title":2277,"description":2278,"ogTitle":2277,"ogDescription":2278,"noIndex":6,"ogImage":2279,"ogUrl":2280,"ogSiteName":683,"ogType":684,"canonicalUrls":2280,"schema":2281},"How to use GitLab's Incident Management with AWS CloudWatch","It's a straightforward process to set up GitLab Incident Management to work with AWS CloudWatch alarms. Here's what you need to know to get started.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664070/Blog/Hero%20Images/cloudwatch-gitlab-incident-management-bg.jpg","https://about.gitlab.com/blog/incident-management-with-aws-cloudwatch","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to use GitLab's Incident Management with AWS CloudWatch\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sean Arnold\"}],\n        \"datePublished\": \"2020-10-08\",\n      }",{"title":2277,"description":2278,"authors":2283,"heroImage":2279,"date":2285,"body":2286,"category":739,"tags":2287},[2284],"Sean Arnold","2020-10-08","\n\nAWS CloudWatch is a popular tool for users of Amazon Web Services to monitor and set alarms on their resources, including EC2 instances, RDS databases and many more.\n\nWhen alarms fire, it is important that your toolchain can quickly and effectively notify you and collate the relevant data. This enables your team to start determining the root cause and take action toward remediation.\n\nGitLab Incident Management now makes it easier than ever to do this. GitLab can take AWS CloudWatch alerts (aka [alarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)), or alerts from any other monitoring and alerting tool you have, and seamlessly integrate them into your [DevOps lifecycle](/topics/devops/).\n\n\n\n## Getting your alerts from AWS CloudWatch to GitLab\n\nNote: For this post, we will assume you are familiar with setting up CloudWatch metrics and alarms within AWS. For more information on AWS Cloudwatch consult the [AWS documentation](https://aws.amazon.com/cloudwatch/).\n\n### Enable the endpoint\n\nWith our generic alert endpoint, GitLab can ingest alerts via REST from any alerting service you have. An alert can be as simple as providing a title or as complex as you need. We provide some defined attributes that you can use to refine your GitLab Incident Management experience, such as the severity of the alert, the service that is alerting, and `gitlab_environment_name` so that you can get an [insight into your alerts for an associated environment and deployment](https://docs.gitlab.com/ee/ci/environments/#environment-incident-management) for users on our Gold and Ultimate plans.\n\nThe first step is to enable your project's alert endpoint. Follow the instructions in the [docs](https://docs.gitlab.com/ee/operations/incident_management/integrations.html#setting-up-generic-alerts) to do this.\n\nNext, we need to ensure the data sent to GitLab is in the expected payload format.\n\n### Transform the payload\n\nOne approach to send CloudWatch alarm data to GitLab is to use AWS Lambda to call the GitLab REST endpoint. We can set this up by publishing the CloudWatch alarm to an [SNS](https://aws.amazon.com/sns/) endpoint, which is then consumed by AWS Lambda to mutate and forward the alert payload to GitLab.\n\n![AWS CloudWatch to GitLab Incident Management](https://about.gitlab.com/images/blogimages/cloudwatch-incident-management-flow.png)\n\nIf you want to get this up and running quickly, I’ve [provided an AWS SAM (Serverless Application Model) application](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/cloudwatch-sns-to-gitlab-alerts) which can setup the Lambda application with the environment variables ready for you to enter your GitLab endpoint URL in.\n\nWe know that managing the integration between two tools can be painful. In the future, we want to make this step as easy as possible: the step of transforming your payload into GitLab Alert format will soon be replaced by [custom endpoints for alerts](https://gitlab.com/groups/gitlab-org/-/epics/4390).\n\nNext, you can [setup your SNS Notification Topic](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/US_SetupSNS.html), and subscribe to the [SNS Topic with your Lambda function](https://docs.aws.amazon.com/sns/latest/dg/sns-lambda-as-subscriber.html).\n\n### Receive your alerts\n\nWhen your CloudWatch alarm next triggers, Lambda should then fire the alert off to GitLab. You should then see your alert in the [Alert list](https://docs.gitlab.com/ee/operations/incident_management/alerts.html).\n\n![AWS CloudWatch to GitLab Incident Management alert list](https://about.gitlab.com/images/blogimages/cloudwatch-gitlab-incident-management-list.png)\n\nYou can click on an alert to [see more details](https://docs.gitlab.com/ee/operations/incident_management/alerts.html), assign an alert to a user and change the status of the alert. If the alert is significant enough to raise an incident, you can do that by clicking the “Create Incident.”\n\nCreating an incident will give you the power to assign team members to it and collaborate on it just like you would a regular GitLab issue. The incident will have the payload of the alert included in the [Alert Details tab](https://docs.gitlab.com/ee/operations/incident_management/incidents.html#alert-details).\n",[851,9,2288],"production",{"slug":2290,"featured":6,"template":696},"incident-management-with-aws-cloudwatch","content:en-us:blog:incident-management-with-aws-cloudwatch.yml","Incident Management With Aws Cloudwatch","en-us/blog/incident-management-with-aws-cloudwatch.yml","en-us/blog/incident-management-with-aws-cloudwatch",{"_path":2296,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2297,"content":2303,"config":2308,"_id":2310,"_type":13,"title":2311,"_source":15,"_file":2312,"_stem":2313,"_extension":18},"/en-us/blog/installing-gitlab-on-raspberry-pi-64-bit-os",{"title":2298,"description":2299,"ogTitle":2298,"ogDescription":2299,"noIndex":6,"ogImage":2300,"ogUrl":2301,"ogSiteName":683,"ogType":684,"canonicalUrls":2301,"schema":2302},"Installing GitLab on Raspberry Pi 64-bit OS","A Raspberry Pi enthusiast tries to run GitLab on the new 64-bit OS...and here's what happened.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679433/Blog/Hero%20Images/anto-meneghini-gqytxsrctvw-unsplash.jpg","https://about.gitlab.com/blog/installing-gitlab-on-raspberry-pi-64-bit-os","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Installing GitLab on Raspberry Pi 64-bit OS\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brendan O'Leary\"}],\n        \"datePublished\": \"2022-03-14\",\n      }",{"title":2298,"description":2299,"authors":2304,"heroImage":2300,"date":2305,"body":2306,"category":739,"tags":2307},[1424],"2022-03-14","\n\n_This blog post and linked pages contain information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes.\nAs with all projects, the items mentioned in this blog post and linked pages are subject to change or delay. The development and release, and timing of any products, features or functionality remain at the sole discretion of GitLab Inc._\n\nRecently the 64-bit version of [Raspberry Pi OS](https://www.raspberrypi.com/software/) came out of a long-awaited beta, and as a Raspberry Pi enthusiast, I was eager to get my hands on it. While the 64-bit version isn't compatible with all Pi hardware, it's exciting to see the expansion of the ecosystem to allow for better access to RAM and software compatibility as 32-bit support becomes less common.\n\nBut speaking of software support - what about running GitLab on the new 64-bit OS? Did you know that GitLab already has support for [Raspberry Pi OS](/install/#raspberry-pi-os)? We even have documentation on [optomizing GitLab on a Raspberry Pi](https://docs.gitlab.com/omnibus/settings/rpi.html) for folks who want to run their self-hosted DevOps platform on simple hardware like the Pi?\n\nNow, the distribution team would want me to point out that official support for ARM64 is still [in the works](https://gitlab.com/groups/gitlab-org/-/epics/2370), but that didn't stop me from at least wanting to try to install GitLab on this exciting new platform. Remember that your mileage may vary - and don't use this in production as it isn't yet officially supported.  \n\nBut that's never stopped me before, so I grabbed my Raspberry Pi 4, a new Micro SD card, and the updated [Raspberry Pi Imager](https://downloads.raspberrypi.org/imager/imager_latest.dmg) and got started.\n\n## Getting Started\n\nThe typical [install for GitLab on the Raspberry Pi](/install/#raspberry-pi-os) assumes you have the standard 32-bit version of `raspbian/buster` that has been standard for some time. So following those steps, I ran into an error with the install script.\n\nWhen running \n\n```bash \nsudo curl -sS https://packages.gitlab.com/install/repositories/gitlab/raspberry-pi2/script.deb.sh | sudo bash\n```\n\nIt appeared to work, but if I tried to install GitLab I'd get this error\n\n```bash\n$ sudo EXTERNAL_URL=\"https://gitpi.boleary.dev\" apt-get install gitlab-ce\n\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nPackage gitlab-ce is not available, but is referred to by another package.\nThis may mean that the package is missing, has been obsoleted, or\nis only available from another source\n \nE: Package 'gitlab-ce' has no installation candidate\n```\nThat's related to the fact that specifically this version of Raspberry Pi OS isn't supported yet - but since it is a fork of Debian Linux, I was able to work around that.\n\n## Manual Installation\n\nTo get started with a slightly modified installation path, I first got the package details and appropriate prerequisite libraries installed:\n\n```bash\ncurl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash\n\nsudo apt-get update\n\nsudo apt-get install debian-archive-keyring\n\nsudo apt-get install curl gnupg apt-transport-https\n\ncurl -L https://packages.gitlab.com/gitlab/gitlab-ce/gpgkey | sudo apt-key add -\n```\n\nThen I created a new sources list to point `apt` to for the installation with `sudo touch /etc/apt/sources.list.d/gitlab_gitlab-ce.list`\n\nNext, I manually added the Debian Buster repositories to that sources list I just created by modifying  `/etc/apt/sources.list.d/gitlab_gitlab-ce.list` to add:\n\n```\ndeb https://packages.gitlab.com/gitlab/gitlab-ce/debian/ buster main\ndeb-src https://packages.gitlab.com/gitlab/gitlab-ce/debian/ buster main\n```\n\n## Finishing Up\nFrom there, it was easy to install the 'standard' way, with apt-get handling the rest for me.\n\n```bash\nsudo apt-get update\n\nsudo EXTERNAL_URL=\"http://gitpi.boleary.dev\" apt-get install gitlab-ce\n```\n\n## Next Steps\n\nNow, those who love DNS will notice that I was pointing to a fully qualified domain name, but it points to a private address if you look up that address.\n\n```bash\ndig gitpi.boleary.dev\n; \u003C\u003C>> DiG 9.10.6 \u003C\u003C>> gitpi.boleary.dev\n;; OPT PSEUDOSECTION:\n; EDNS: version: 0, flags:; udp: 512\n;; QUESTION SECTION:\n;gitpi.boleary.dev.\t\tIN\tA\n\n;; ANSWER SECTION:\ngitpi.boleary.dev.\t300\tIN\tA\t100.64.205.40\n```\n\nIsn't that interesting?  What does it mean - can I access it from outside my house's network?  And how will I get it to work with HTTPs on that private address?\n\nFor those answers, you'll have to stay tuned to my next article about running GitLab on the Raspberry Pi: Hosting a private GitLab server with Tailscale and LetsEncrypt.\n\nPhoto by \u003Ca href=\"https://unsplash.com/@antomeneghini?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText\">Anto Meneghini\u003C/a> on \u003Ca href=\"https://unsplash.com/s/photos/raspberries?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText\">Unsplash\u003C/a>\n  \n",[1408,9,2128],{"slug":2309,"featured":6,"template":696},"installing-gitlab-on-raspberry-pi-64-bit-os","content:en-us:blog:installing-gitlab-on-raspberry-pi-64-bit-os.yml","Installing Gitlab On Raspberry Pi 64 Bit Os","en-us/blog/installing-gitlab-on-raspberry-pi-64-bit-os.yml","en-us/blog/installing-gitlab-on-raspberry-pi-64-bit-os",{"_path":2315,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2316,"content":2322,"config":2329,"_id":2331,"_type":13,"title":2332,"_source":15,"_file":2333,"_stem":2334,"_extension":18},"/en-us/blog/integration-management",{"title":2317,"description":2318,"ogTitle":2317,"ogDescription":2318,"noIndex":6,"ogImage":2319,"ogUrl":2320,"ogSiteName":683,"ogType":684,"canonicalUrls":2320,"schema":2321},"Integration management for git projects","Read here on how GitLab offers the tools for managing integrations for your projects!","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667194/Blog/Hero%20Images/2020-11-19-integration-management-header.jpg","https://about.gitlab.com/blog/integration-management","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Integration management for git projects\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Patrick Deuley\"},{\"@type\":\"Person\",\"name\":\"Taurie Davis\"}],\n        \"datePublished\": \"2020-11-19\",\n      }",{"title":2317,"description":2318,"authors":2323,"heroImage":2319,"date":2326,"body":2327,"category":763,"tags":2328},[2324,2325],"Patrick Deuley","Taurie Davis","2020-11-19","GitLab is a complete platform for the entire [DevOps lifecycle](/topics/devops/), but some users and organizations already have a specific tool they must use for certain parts of their workflow. **Over 4.5 million projects have configured integrations** and hundreds of thousands more are added each month. User utilize integration management to connect a wide array of applications such as Slack, Jira, Prometheus, and more – plugging critical parts of their chosen stack into GitLab.\n\nOne of the core design concepts of GitLab as a product is that a single application serves our users best. However, for users who have made specific choices about certain tools in their workflow, the inverse is also true: a disjointed toolchain where your tools are not connected at all is _the worst possible experience_. If you are going to have separate tools in your DevOps toolchain (which is fine!), they need to at least be sitting next to each other.\n\nBefore GitLab 13.3, project integrations were managed only at the project level. This meant that if you had 400 projects, you'd have to configure that integration 400 times!\n\n**In GitLab 13.3, we added the ability to add an integration across an entire GitLab instance, for all projects. In GitLab 13.6 (coming Nov. 22, 2020), we’re expanding this ability to work at the group level as well.**\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/6mz1y15JEHE\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n## Integration management for large organizations integrating third-party applications with their GitLab projects!\n\nA group _with any number of projects in it_ can integrate them all at once, from a single place. Group owners and instance administrators rejoice! This will save you hours and hours of work managing all of those connections and keeping them up to date.\n\nThere are also security benefits to this approach: instance administrators and group owners can roll out an integration without having to share the credentials with each project owner directly. This is a great security enhancement because many organizations had to restrict configuration to a small group of people, requiring them to do a ton of busywork just to maintain this posture.\n\nGroup-level Integration Management is available **today, for free**, on both [GitLab.com](https://gitlab.com) and in self-managed GitLab installations running 13.6 and up.\n\nFor more information, check out the documentation for [Project Integration Management](https://docs.gitlab.com/ee/administration/settings/project_integration_management.html).\n\n## So what’s next for Project Integration Management?\n\nWe’re also looking to expand this feature with more bells and whistles to make the lives of our instance administrators and group owners easier. Some things that we're considering for the future are:\n\n- [**Inheritance overviews**](https://gitlab.com/gitlab-org/gitlab/-/issues/14157), which will show what projects are overriding the inherited settings\n- **Per-field inheritance** that overrides only a single field while leaving the rest of the settings managed by the parent\n- **Field masking**, which allows the group or instance owner to obfuscate specific fields that are inheritable, while still allowing the integration to work\n- **Inheritance locking**, giving group or instance owners the ability to enforce those settings on every project under them\n- **Service Template migrations**, giving users of Service Templates an easy way to migrate to this new feature and roll the change out to every project where it’s applicable\n\nIf you have any feedback, ideas for future features, input, or requirements for items on the roadmap, or anything else – please leave comments [in the parent epic for this feature](https://gitlab.com/groups/gitlab-org/-/epics/2137).\n\n### Upcoming Service Template deprecation\n\nFormerly, [Service Templates](https://docs.gitlab.com/ee/user/admin_area/settings/project_integration_management.html) filled this particular need in GitLab, with many limitations. These templates were applied only to new projects, and if you updated a value on the template, it didn’t retroactively apply to each project that already used those settings.\n\nThis solves half the problem by allowing the _initial settings of an integration_ to be defined for many projects in one place, but failed to help with actually managing those integrations later. Because the ongoing management is just as important as the setup, we saw some organizations writing custom scripts to continuously validate that those settings hadn’t changed, and automations to roll out changes to many projects at once. These examples are glue code that they should never have needed to write in the first place, let alone make them maintain over time. Our hope is that this new feature suits those use cases perfectly, and that migrating from Service Templates to integrations managed at the group level dramatically reduces their maintenance overhead.\n\nWe are currently planning on [deprecating Service Templates](https://gitlab.com/gitlab-org/gitlab/-/issues/268032) during our normal deprecation cycle (only in major releases), in GitLab 14.0.\n\n#### More GitLab integrations\n\n- [Get the most out of the Checkmarx integration with GitLab](/blog/checkmarx-integration/)\n- [Is DevOps for designers?](/blog/is-devops-for-designers/)\n- [Demo: GitLab + Jira + Jenkins](/blog/gitlab-workflow-with-jira-jenkins/)\n\nCover image by [Ryan Quintal](https://unsplash.com/photos/US9Tc9pKNBU) on [Unsplash](https://unsplash.com)\n{: .note}\n",[742,9,763],{"slug":2330,"featured":6,"template":696},"integration-management","content:en-us:blog:integration-management.yml","Integration Management","en-us/blog/integration-management.yml","en-us/blog/integration-management",{"_path":2336,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2337,"content":2342,"config":2347,"_id":2349,"_type":13,"title":2350,"_source":15,"_file":2351,"_stem":2352,"_extension":18},"/en-us/blog/introducing-gitlab-serverless",{"title":2338,"description":2339,"ogTitle":2338,"ogDescription":2339,"noIndex":6,"ogImage":1764,"ogUrl":2340,"ogSiteName":683,"ogType":684,"canonicalUrls":2340,"schema":2341},"Announcing GitLab Serverless","The true value of serverless is best realized via a single-application DevOps experience – that's why we're launching GitLab Serverless.","https://about.gitlab.com/blog/introducing-gitlab-serverless","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Announcing GitLab Serverless\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Priyanka Sharma\"}],\n        \"datePublished\": \"2018-12-11\",\n      }",{"title":2338,"description":2339,"authors":2343,"heroImage":1764,"date":2344,"body":2345,"category":298,"tags":2346},[1057],"2018-12-11","\n\n[Serverless](/topics/serverless/) is the latest innovation in cloud computing that promises to alter the cost-benefit equation for enterprises. As our CEO, [Sid Sijbrandij](/company/team/#sytses) says, \"All roads lead to compute.\" There is a race among providers to acquire as many workloads from enterprises as possible, at the cheapest cost. The latter is where serverless comes in: serverless computing is an execution model in which the cloud provider acts as the server, dynamically managing the allocation of machine resources. Pricing is based on the actual resources consumed by an application, rather than on pre-purchased units of capacity.\n\nThis field began with the release of [AWS Lambda](https://en.wikipedia.org/wiki/AWS_Lambda) in November 2014. In the four short years since then, it has become a well-known workflow that enterprises are eager to adopt. Today, we are announcing [GitLab Serverless](/topics/serverless/) to enable our users to take advantage of the benefits of serverless.\n\n## GitLab Serverless is launching Dec. 22\n\nGitLab is the only single application for the entire [DevOps lifecycle](/topics/devops/). As part of that vision, we will release GitLab Serverless in GitLab 11.6, coming later this month, to allow enterprises to plan, build, and manage serverless workloads with the rest of their code from within the same GitLab UI. It leverages [Knative](https://cloud.google.com/knative/), which enables [autoscaling](https://en.wikipedia.org/wiki/Autoscaling) down to zero and back up to run serverless workloads on Kubernetes. This allows businesses to employ a multi-cloud strategy and leverage the value of serverless without being locked into a specific cloud provider.\n\nIn order to bring the best-in-class to our users, we partnered with [TriggerMesh](https://triggermesh.com/) founder [Sebastien Goasguen](https://twitter.com/sebgoa) and his team. Sebastien has been part of the serverless landscape since the beginning. He built a precursor to Knative, Kubeless. He is actively involved with the Knative community and understands the workflow from soup to nuts. Sebastien says, \"We are excited to help GitLab enable all their users to deploy functions directly on the Knative function-as-a-service clusters. We believe that these additions to GitLab will give those users the best possible experience for complete serverless computing from beginning to end.\"\n\n## \"Serverless first\"\n\nAs any attendees at [AWS re:Invent](/blog/aws-reinvent-recap/) would have noticed, the behemoth is putting all its energies behind serverless. We heard [stories from the likes of Trustpilot](https://www.computerworlduk.com/cloud-computing/how-trustpilot-takes-serverless-first-approach-engineering-with-aws-3688267/) about changing their engineering culture to \"serverless first.\" This is because serverless cloud providers save money by not having to keep idle machines provisioned and running, and are passing on the benefits to their customers. While this is amazing news, it is hard to truly embrace a workflow if it lives outside of developers' entrenched habits. GitLab has millions of users and is used by over 100,000 organizations, and with GitLab Serverless they can now enjoy the cost savings and elegant code design serverless brings, from the comfort of their established workflows.\n\nAs with all GitLab endeavors, making serverless multi-cloud and accessible to everyone is a big, hairy, audacious goal. Today, Knative can be installed to a Kubernetes cluster with a single click via the GitLab Kubernetes integration. It shipped in [GitLab 11.5](/releases/2018/11/22/gitlab-11-5-released/#easily-deploy-and-integrate-knative-with-gitlab).\n\n### How to activate GitLab Serverless\n\nStarting with the release of GitLab 11.6 on Dec. 22, the \"Serverless\" tab will be available for users as an alpha offering. Please do check it out and share your feedback with us.\n\n1. Go to your GitLab instance and pick your project of choice.\n2. Click on the `Operations` menu item in the sidebar.\n3. Pick `Serverless` to view the list of all the functions you have defined. You will also be able to see a brief description as well as the Knative cluster the function is deploying to.\n\n![Serverless list view](https://gitlab.com/gitlab-org/gitlab-ce/uploads/8b821d4aaa1bb75375dc54567a4313ad/CE-project__serverless-grouped.png \"Serverless list view\"){: .shadow.large.center}\n\nTo dig further, click into the function for more info.\n\n![function detail view](https://gitlab.com/gitlab-org/gitlab-ce/uploads/9e1e3893aa5369a2a165d1dd95c98dd8/CE-project__serverless--function-details.png \"function detail view\"){: .shadow.large.center}\n\nAll this goodness will be available Dec. 22. In the meantime, we would love to see you at [KubeCon Seattle](/events), where our product and engineering experts are attending to talk all things serverless with attendees. Hope to see you at booth S44!\n",[763,851,742,9,1040],{"slug":2348,"featured":6,"template":696},"introducing-gitlab-serverless","content:en-us:blog:introducing-gitlab-serverless.yml","Introducing Gitlab Serverless","en-us/blog/introducing-gitlab-serverless.yml","en-us/blog/introducing-gitlab-serverless",{"_path":2354,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2355,"content":2361,"config":2367,"_id":2369,"_type":13,"title":2370,"_source":15,"_file":2371,"_stem":2372,"_extension":18},"/en-us/blog/introducing-the-infrastructure-bill-of-materials",{"title":2356,"description":2357,"ogTitle":2356,"ogDescription":2357,"noIndex":6,"ogImage":2358,"ogUrl":2359,"ogSiteName":683,"ogType":684,"canonicalUrls":2359,"schema":2360},"Introducing the infrastructure bill of materials","Pair IBoMs and SBOMs for a more secure software supply chain.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671160/Blog/Hero%20Images/ibom.jpg","https://about.gitlab.com/blog/introducing-the-infrastructure-bill-of-materials","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Introducing the infrastructure bill of materials\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Cindy Blake\"}],\n        \"datePublished\": \"2022-09-22\",\n      }",{"title":2356,"description":2357,"authors":2362,"heroImage":2358,"date":2364,"body":2365,"category":716,"tags":2366},[2363],"Cindy Blake","2022-09-22","\nAll eyes are on software supply chain security and organizations are busily generating software bills of materials, or SBOMs. But many are leaving out an equally critical part of software supply chain security: their infrastructure. GitLab has partnered with Firefly to help DevOps teams create bills of materials across the entire cloud footprint. \n \nThe SBOM, which is an ingredient list that identifies third-party and open source code used within software (a.k.a. dependencies), came into the spotlight with the U.S. Executive Order on \"Improving the Nation's Cybersecurity\" and its resulting [NIST guidelines to secure the software supply chain](/blog/comply-with-nist-secure-supply-chain-framework-with-gitlab/).\n \nWhile SBOMs begin to peel back the layers on risky code using elements such as [composition analysis](/handbook/engineering/development/sec/secure/composition-analysis/) to scan for dependencies in containers, more attention must be paid to how cloud infrastructure, a critical part of the software development lifecycle, is managed and secured.\n \n## Assessing cloud infrastructure\n \nWhen people think about software integrity, they tend to think about applications. Yet with the rise of cloud computing, cloud native applications, and modern CI/CD pipelines, there is a considerable amount of code used to automate how infrastructure resources are provisioned, secured, and consumed. In fact, the cloud is defined using [infrastructure-as-code](/blog/fantastic-infrastructure-as-code-security-attacks-and-how-to-find-them/) (IaC), and most of the power attributed to applications relies on infrastructure capabilities, configurations, permissions, and relations. Understanding an application's relationship with the underlying infrastructure and how it is configured is just as important to supply chain security as understanding an application’s usage of third-party and open source code. \n \nThe challenge is that it’s not easy to do. This infrastructure software, often referred to as cloud assets, includes resources provided by cloud services, orchestrators like Kubernetes, and even policies. Google Cloud nicely [lists its assets](https://cloud.google.com/asset-inventory/docs/supported-asset-types) as an example. Increasingly, companies are [using more than one cloud service provider](https://www.cncf.io/wp-content/uploads/2022/02/CNCF-AR_FINAL-edits-15.2.21.pdf) for different workloads, and each service uses different constructs. Even with a single provider, many companies organize their applications into multiple AWS accounts or GCP projects. It can be difficult to see what assets an organization has across these silos.\n \n## Enter the IBoM\n \nDespite these challenges, just as an organization needs to list all the application code dependencies, it also needs to list all the infrastructure components across multiple clouds, multiple accounts, and Kubernetes. Together, they make up the infrastructure bill of materials, or IBoM. These assets must be tracked and managed closely as they can be changed and, if not properly governed, can wreak havoc on the stability and consistency of an application’s performance, creating troubleshooting problems.\n \nThe IBoM is the first key to understanding an organization’s complete cloud footprint and being able to better secure the software supply chain.\n \nThe second key, and equally important, is managing the integrity of that IBoM. The configuration of cloud assets such as S3 buckets, identity and access management roles, EC2, database instances, and Kubernetes clusters determines access to data and what resources are available to an application. The configuration also impacts the stability of the infrastructure upon which the applications depend.\n \nWith the surge of cloud native applications, the burden of managing this infrastructure has increased exponentially. To meet the challenge of governing this complex infrastructure, organizations have been codifying these cloud assets into IaC using tools like Terraform, Pulumi, and Helm. Once codified as IaC, they can utilize version control and be governed with the same rigor as application software – all within a DevOps platform like GitLab. This approach is typically called [GitOps](/topics/gitops/). It's important for the security of your supply chain because it provides visibility, traceability, and policy enforcement for your infrastructure software.\n \n## How Firefly and GitLab work together\n \n[Firefly’s Cloud Asset Management solution](https://www.gofirefly.io/) can help GitLab’s DevOps platform manage both application software and cloud infrastructure software - across an organization’s cloud footprint. Firefly essentially extends the GitLab [GitOps solution](/solutions/gitops/) to cover even more of your cloud and provides additional governance via drift detection and remediation.\n\nFirst, Firefly discovers all of an organization’s cloud infrastructure across AWS accounts, GCP projects, Kubernetes, and even SaaS application environments, providing an IBoM in one dashboard. Unmanaged and misconfigured environments are identified for DevOps. With a click, these unmanaged cloud assets are automatically coded into IaC such as Terraform or Helm, potentially saving engineering time and getting DevOps teams toward a more fully managed software supply chain.\n\nNow, as IaC, these cloud assets can be monitored for changes. Firefly continuously assesses drift between an organization’s desired IaC state and its actual cloud and Kubernetes configurations, helping ensure these configurations and policies remain enforced. When changes are made to either IaC or the underlying infrastructure, Firefly automatically creates a GitLab merge request to ensure changes to an organization’s infrastructure software are managed using DevOps automated CI/CD.\n \nFirefly and GitLab together enable DevOps teams to add to the security of their supply chains by generating IBoMs, applying version control, automation, and governance to the applications and infrastructure upon which they rely. Learn more about the [Firefly/GitLab integration](https://www.gofirefly.io/partners/gitlab) and give Firefly a try. \n\n\n_Blake is vice president of marketing at Firefly._\n\nCover image by [Edge2Edge Media](https://unsplash.com/photos/t1OalCBUYRc) on Unsplash\n{: .note}\n",[716,9,693],{"slug":2368,"featured":6,"template":696},"introducing-the-infrastructure-bill-of-materials","content:en-us:blog:introducing-the-infrastructure-bill-of-materials.yml","Introducing The Infrastructure Bill Of Materials","en-us/blog/introducing-the-infrastructure-bill-of-materials.yml","en-us/blog/introducing-the-infrastructure-bill-of-materials",{"_path":2374,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2375,"content":2381,"config":2386,"_id":2388,"_type":13,"title":2389,"_source":15,"_file":2390,"_stem":2391,"_extension":18},"/en-us/blog/ios-publishing-with-gitlab-and-fastlane",{"title":2376,"description":2377,"ogTitle":2376,"ogDescription":2377,"noIndex":6,"ogImage":2378,"ogUrl":2379,"ogSiteName":683,"ogType":684,"canonicalUrls":2379,"schema":2380},"How to publish iOS apps to the App Store with GitLab and fastlane","See how GitLab, together with fastlane, can build, sign, and publish apps for iOS to the App Store.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680470/Blog/Hero%20Images/ios-publishing-cover.jpg","https://about.gitlab.com/blog/ios-publishing-with-gitlab-and-fastlane","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to publish iOS apps to the App Store with GitLab and fastlane\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jason Yavorska\"}],\n        \"datePublished\": \"2019-03-06\",\n      }",{"title":2376,"description":2377,"authors":2382,"heroImage":2378,"date":2383,"body":2384,"category":739,"tags":2385},[736],"2019-03-06","_Note: You may also find the blog post [Tutorial: iOS CI/CD with\nGitLab](/blog/ios-cicd-with-gitlab/) from June 2023 helpful._\n\n\nRecently we published a [blog post\n\ndetailing how to get up and running quickly with your Android\napp](/blog/android-publishing-with-gitlab-and-fastlane/), GitLab, and\n\n[_fastlane_](https://fastlane.tools). In this edition, let's look at how to\nget\n\na build of an iOS app up and running, including publishing all the way to\n\nTestFlight. To see how cool this can be, check out this [video\n\nof me making a change on an iPad Pro using the GitLab Web\nIDE](https://www.youtube.com/watch?v=325FyJt7ZG8), getting that\n\nbuilt, and then receiving an update to the test version of my application on\nthe\n\nvery same iPad Pro I was using to develop.\n\n\nFor the purposes of this article, we'll be using a [simple Swift iOS\napp](https://gitlab.com/jyavorska/flappyokr)\n\nthat I recorded the video with.\n\n\n## First, a note on Apple Store configuration\n\n\nWhat we're going to need in order to set all of this up is a mobile\napplication set up\n\nin the App Store, distribution certificates, and a provisioning profile that\nties\n\nit all together.\n\n\nMost of the complexity here actually has to do with setting up your signing\n\nauthority for the App Store. Hopefully in most cases this is already good to\ngo\n\nfor you; if you're a new app developer, I'll try to get you started on the\nright\n\ntrack, but the intricacies of Apple certificate management is out of the\nscope of\n\nthis article, and tends to change somewhat frequently. But, this information\n\nshould get you going.\n\n\n### My apps\n\n\nYour application will need to be set up in App Store Connect so you have an\nID\n\nfor your application, which will be used in your `.xcodebuild`\nconfiguration.\n\nYour app profile and ID are what tie together the code builds with pricing\nand\n\navailability, as well as TestFlight configuration for distributing testing\n\napplications to your users. Note that you don't need to set up public\ntesting –\n\nyou can use personal testing with TestFlight just fine as long as your\ntesting\n\ngroup is small, and the setup is simpler and requires no additional\napprovals\n\nfrom Apple.\n\n\n### Provisioning profile\n\n\nIn addition to the app setup, you need iOS distribution and development keys\n\ncreated in the Certificates, Identifiers, and Profiles section of the Apple\n\nDeveloper console. Once these certificates are created, you can create a\n\nprovisioning profile to unify everything.\n\n\nAlso note that the user you will authenticate with needs to be able to\ncreate\n\ncertificates, so please ensure that they have that ability or you will see\nan\n\nerror during the [_cert_ and\n_sigh_](https://docs.fastlane.tools/codesigning/getting-started/#using-cert-and-sigh)\n\nsteps.\n\n\n### Other options\n\n\nThere are several more ways to set up your certificates and profiles than\nthe\n\nsimple method I've described above, so if you're doing something different\nyou may\n\nneed to adapt. The most important thing is that you need your `.xcodebuild`\n\nconfiguration to point to the appropriate files, and your keychain needs to\nbe\n\navailable on the build machine for the user that the runner is running as.\nWe're\n\nusing _fastlane_ for signing, so if you run into trouble here or want to\nlearn\n\nmore about your options, take a look at their extensive [code signing\ndocumentation](https://docs.fastlane.tools/codesigning/getting-started/).\n\n\nFor this sample project, I'm using the [_cert_ and\n_sigh_](https://docs.fastlane.tools/codesigning/getting-started/#using-cert-and-sigh)\n\napproach, but the [match\n\napproach](https://docs.fastlane.tools/codesigning/getting-started/#using-match)\nmay be better for actual enterprise use.\n\n\n## How to set up GitLab and _fastlane_\n\n\n### How to set up your CI/CD runner\n\n\nWith the above information gathered or set up, we can start with configuring\nthe\n\nGitLab runner on a macOS device. Unfortunately, building on macOS is the\nonly\n\nrealistic way to build iOS apps. This is potentially changing in the future;\n\nkeep an eye on projects like [xcbuild](https://github.com/facebook/xcbuild)\nand\n\n[isign](https://github.com/saucelabs/isign), as well as our own internal\nissue\n\n[gitlab-ce#57576](https://gitlab.com/gitlab-org/gitlab-ce/issues/57576) for\n\ndevelopments in this area.\n\n\nIn the meantime, setting up the runner is fairly straightforward. You can\nfollow\n\nour most current [instructions for setting up GitLab Runner on\nmacOS](https://docs.gitlab.com/runner/install/osx.html)\n\nto get that up and running.\n\n\nNote: Be sure to set your GitLab runner to use the `shell` executor. For\nbuilding iOS on\n\nmacOS, it's a requirement to operate directly as the user on the machine\nrather\n\nthan using containers. Note that when you're using the shell executor, the\n\nbuild and tests run as the identity of the runner logged in user, directly\non\n\nthe build host. This is less secure than using container executors, so\nplease\n\ntake a look at our [security implications\ndocumentation](https://docs.gitlab.com/runner/security/#usage-of-shell-executor)\n\nfor additional detail on what to keep in mind in this scenario.\n\n\n```\n\nsudo curl --output /usr/local/bin/gitlab-runner\nhttps://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64\n\nsudo chmod +x /usr/local/bin/gitlab-runner\n\ncd ~\n\ngitlab-runner install\n\ngitlab-runner start\n\n```\n\n\nWhat you need to be careful about here is ensuring your Apple keychain is\nset up\n\non this host and has access to the keys that Xcode needs in order\n\nto build. The easiest way to test this is to log in as the user that will be\n\nrunning the build and try to build manually. You may receive system prompts\nfor\n\nkeychain access which you need to \"always allow\" for CI/CD to work. You will\nprobably\n\nalso want to log in and watch your first pipeline or two to make sure that\n\nno prompts come up for additional keychain access. Unfortunately Apple does\nnot\n\nmake this super easy to use in unattended mode, but once you have it working\nit\n\ntends to stay that way.\n\n\n### _fastlane_ init\n\n\nIn order to start using _fastane_ with your project, you'll need to run\n\n`fastlane init`. Simply follow the [instructions\n\nto install and run\n_fastlane_](https://docs.fastlane.tools/getting-started/ios/setup/), being\nsure to use the instructions in the\n\n[Use a\nGemfile](https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile)\n\nsection, since we do want this to run quickly and predictably via unattended\nCI.\n\n\nFrom your project directory, you can run the following commands:\n\n\n```\n\nxcode-select --install\n\nsudo gem install fastlane -NV\n\n# Alternatively using Homebrew\n\n# brew cask install fastlane\n\nfastlane init\n\n```\n\n\n_fastlane_ will ask you for some basic configuration and then create a\nproject folder\n\ncalled `fastlane` in your project which will contain three files:\n\n\n#### 1. `fastlane/Appfile`\n\n\nThis file is straightforward, so you just want to check to make sure that\nthe Apple\n\nID and app ID that you set up earlier are correct.\n\n\n```\n\napp_identifier(\"com.vontrance.flappybird\") # The bundle identifier of your\napp\n\napple_id(\"your-email@your-domain.com\") # Your Apple email address\n\n```\n\n\n#### 2. `fastlane/Fastfile`\n\n\nThe `Fastfile` defines the build steps. Since we're using a lot of the\nbuilt-in\n\ncapability of _fastlane_ this is really straightforward. We create a single\n\nlane which gets certificates, builds, and uploads the new build to\nTestFlight.\n\nOf course, you may want to split these out into different jobs depending on\nyour\n\nuse case. Each of these steps, `get_certificates`,\n`get_provisioning_profile`,\n\n`gym`, and `upload_to_testflight` are pre-bundled actions already included\nwith\n\n_fastlane_.\n\n\n`get_certificates` and `get_provisioning_profile` are actions associated\nwith\n\nthe [_cert_ and\n_sigh_](https://docs.fastlane.tools/codesigning/getting-started/#using-cert-and-sigh)\n\napproach to code signing; if you're using _fastlane_\n[match](https://docs.fastlane.tools/codesigning/getting-started/#using-match)\n\nor some other approach you may need to update these.\n\n\n```yaml\n\ndefault_platform(:ios)\n\n\nplatform :ios do\n  desc \"Build the application\"\n  lane :flappybuild do\n    get_certificates\n    get_provisioning_profile\n    gym\n    upload_to_testflight\n  end\nend\n\n```\n\n\n#### 3. `fastlane/Gymfile`\n\n\nThis `gym` file is optional, but I created it manually in order to override\nthe default\n\noutput directory and place the output in the current folder. This makes\nthings a\n\nbit easier for CI. You can read more about `gym` and its options in the\n\n[gym documentation](https://docs.fastlane.tools/actions/gym/).\n\n\n```yaml\n\noutput_directory(\"./\")\n\n```\n\n\n### Our `.gitlab-ci.yml` configuration file\n\n\nNow, we have a CI/CD runner associated with our project so we're ready to\ntry a\n\npipeline. Let's see what's in our `.gitlab-ci.yml` file:\n\n\n```yaml\n\nstages:\n  - build\n\nvariables:\n  LC_ALL: \"en_US.UTF-8\"\n  LANG: \"en_US.UTF-8\"\n  GIT_STRATEGY: clone\n\nbuild:\n  stage: build\n  script:\n    - bundle install\n    - bundle exec fastlane flappybuild\n  artifacts:\n    paths:\n    - ./FlappyBird.ipa\n```\n\n\nYes, that's really it! [We set UTF-8 locale for _fastlane_ per their\n\nrequirements](https://docs.fastlane.tools/getting-started/ios/setup/#set-up-environment-variables),\n\nuse a `clone` strategy with the `shell` executor to ensure we have a clean\n\nworkspace each build, and then simply call our `flappybuild` _fastlane_\ntarget,\n\nwhich we discussed above. This will build, sign, and deploy the latest build\nto\n\nTestFlight.\n\n\nWe also gather the artifact and save it with the build – note that the\n`.ipa`\n\nformat output is a signed ARM executable, so not something you can run in\nthe\n\nsimulator. If you wanted a simulator output to be saved with the build, you\n\nwould simply add a build target that produces it and then add it to the\nartifact\n\npath.\n\n\n### Other environment variables\n\n\nThere are some special environment variables behind the scenes here that are\n\nmaking this work.\n\n\n#### `FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD` and `FASTLANE_SESSION`\n\n\nIn order to authenticate against the App Store for the TestFlight upload,\n\n_fastlane_ must be able to authenticate. In order to do this, you need to\n\ncreate an app-specific password to be used by CI. You can read more about\nthis\n\nprocess in [this\ndocumentation](https://docs.fastlane.tools/best-practices/continuous-integration/#use-of-application-specific-passwords-and-spaceauth).\n\n\nIf you're using two-factor authentication, you'll also need to generate the\n\n`FASTLANE_SESSION` variable – instructions are in the same place.\n\n\n#### `FASTLANE_USER` and `FASTLANE_PASSWORD`\n\n\nIn order for [_cert_ and\n_sigh_](https://docs.fastlane.tools/codesigning/getting-started/#using-cert-and-sigh)\n\nto be able to fetch the provisioning profile and certificates on demand, the\n\n`FASTLANE_USER` and `FASTLANE_PASSWORD` variables must be set. You can read\nmore\n\nabout this\n[here](https://docs.fastlane.tools/best-practices/continuous-integration/#environment-variables-to-set).\n\nYou may not need these if you are using some other approach to signing.\n\n\n## In closing...\n\n\nRemember, you can see a working project with all of this set up by heading\nover\n\nto my [simple demo app](https://gitlab.com/jyavorska/flappyokr).\n\n\nHopefully this has been helpful and has inspired you to get iOS builds and\n\npublishing working within your GitLab project. There is some good additional\n\n[CI/CD\nbest-practice](https://docs.fastlane.tools/best-practices/continuous-integration/)\n\ndocumentation for _fastlane_ if you get stuck anywhere,\n\nand you could also consider using the `CI_BUILD_ID` (which increments each\nbuild)\n\nto [automatically increment a\nversion](https://docs.fastlane.tools/best-practices/continuous-integration/gitlab/#auto-incremented-build-number).\n\n\nAnother great capability of _fastlane_ to try is the ability to\n\n[automatically generate\nscreenshots](https://docs.fastlane.tools/getting-started/ios/screenshots/)\n\nfor the App Store – it's just as easy to set up as the rest of this has\nbeen.\n\n\nWe'd love to hear in the comments how this is working for you, as well as\nyour\n\nideas for how we can make GitLab a better place to do iOS development in\ngeneral.\n\n\nPhoto by eleven_x on [Unsplash](https://unsplash.com/photos/lwaw_DL09S4)\n\n{: .note}\n",[108,9,742],{"slug":2387,"featured":6,"template":696},"ios-publishing-with-gitlab-and-fastlane","content:en-us:blog:ios-publishing-with-gitlab-and-fastlane.yml","Ios Publishing With Gitlab And Fastlane","en-us/blog/ios-publishing-with-gitlab-and-fastlane.yml","en-us/blog/ios-publishing-with-gitlab-and-fastlane",{"_path":2393,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2394,"content":2400,"config":2406,"_id":2408,"_type":13,"title":2409,"_source":15,"_file":2410,"_stem":2411,"_extension":18},"/en-us/blog/jenkins-gitlab-ultimate-guide-to-modernizing-cicd-environment",{"title":2395,"description":2396,"ogTitle":2395,"ogDescription":2396,"noIndex":6,"ogImage":2397,"ogUrl":2398,"ogSiteName":683,"ogType":684,"canonicalUrls":2398,"schema":2399},"Jenkins to GitLab: The ultimate guide to modernizing your CI/CD environment","Learn how to migrate from Jenkins to the integrated CI/CD of the GitLab DevSecOps Platform to deliver high-quality software rapidly.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663000/Blog/Hero%20Images/tanukilifecycle.png","https://about.gitlab.com/blog/jenkins-gitlab-ultimate-guide-to-modernizing-cicd-environment","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Jenkins to GitLab: The ultimate guide to modernizing your CI/CD environment\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Itzik Gan Baruch\"}],\n        \"datePublished\": \"2023-11-01\",\n      }",{"title":2395,"description":2396,"authors":2401,"heroImage":2397,"date":2403,"body":2404,"category":1244,"tags":2405},[2402],"Itzik Gan Baruch","2023-11-01","\nIn today's dynamic landscape of software development, certain requirements have become paramount for delivering high-quality software rapidly. These requirements include the need for cloud compatibility, faster development cycles, improved collaboration, containerization, enhanced development experiences, and the integration of AI-driven capabilities for better efficiency and speed. Jenkins, a longstanding and respected continuous integration (CI) tool, has admirably played a role in many teams' software development for years. However, as more teams adopt DevOps/DevSecOps strategies for their software delivery, leveraging the integrated CI that is available in a DevSecOps platform like GitLab can provide benefits that Jenkins does not. \n\nSome organizations find themselves hesitating to migrate, not because they doubt the benefits of a top-tier [CI/CD](https://about.gitlab.com/topics/ci-cd/) solution such as GitLab, but due to the complexities of their existing Jenkins implementations. It's understandable that such a transition can seem daunting. \n\nIn this blog, you'll find several migration strategies to help transition from Jenkins to GitLab and make the process smoother and more manageable.\n\n## Migrating to GitLab\nIt's become evident that for organizations seeking a CI/CD solution that can seamlessly support their evolving demands, GitLab emerges as a powerful game-changer. Let's explore why transitioning to this advanced platform is transformative for Jenkins users.\n\n### Why migrate to GitLab \nBefore we delve into the migration approaches, let's take a moment to understand GitLab CI and what makes it a compelling choice for modern CI/CD needs.\n\n> Try GitLab CI/CD today with [a free trial of Ultimate](https://gitlab.com/-/trials/new).\n\n### GitLab CI overview\nGitLab CI is an integral part of the GitLab [AI-powered](https://about.gitlab.com/gitlab-duo/) DevSecOps Platform, which offers a comprehensive and unified solution for DevSecOps and CI/CD. GitLab's design revolves around streamlining development workflows, fostering collaboration, enhancing security, and ensuring scalability.\n\n### Key features of GitLab CI\nThese are the key features of GitLab CI:\n- **Unified platform:** GitLab CI is more than just a CI/CD tool; it's part of a broader ecosystem that includes source code management, project management, security features, analytics and more. This unified platform streamlines workflows and enhances collaboration among development teams.\n- **Containerization and orchestration:** GitLab CI/CD is designed with containerization in mind, offering native support for Docker and Kubernetes. This enables seamless integration of container technologies into your CI/CD pipelines.\n- **Security by design:** Security is a top priority, and GitLab CI incorporates features such as static code analysis and vulnerability scanning to help teams identify and address security issues early in the development process.\n- **GitOps principles:** GitLab CI aligns with [GitOps principles](https://about.gitlab.com/blog/the-ultimate-guide-to-gitops-with-gitlab/), emphasizing version-controlled, declarative configurations for infrastructure and application deployments. This approach enhances the reliability and repeatability of deployments.\n\nGet familiar with GitLab CI with this tutorial:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/WKR-7clknsA?si=T21Fe10Oa0rQ0SGB\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nWith that understanding of GitLab CI's capabilities, let's explore the migration steps and strategies for Jenkins users looking to leverage the benefits of GitLab CI.\n\n## A recommended step-by-step Jenkins-to-GitLab CI migration\nWhen considering a migration from Jenkins to GitLab CI, we strongly recommend following a well-structured, step-by-step approach to ensure a seamless transition. Here's our recommended process:\n1. **Pipeline assessment:** Start by conducting a comprehensive inventory of all your existing pipelines in Jenkins. This initial step will help you gain a clear understanding of the scope and complexity of the migration.\n2. **Parallel migration:** Begin the migration process by selecting individual pipelines and moving them to GitLab CI one at a time. Continue to maintain the use of Jenkins for your ongoing work during this transition to minimize disruptions.\n3. **Code verification:** We advise beginning with verification checks in CI. Run both the Jenkins and GitLab CI pipelines in parallel. This dual approach allows you to directly compare the two workflows and identify any issues in the new GitLab workflows. During this phase, keep the GitLab workflow as an optional choice while Jenkins remains required.\n4. **Continuous validation:** After running both pipelines in parallel for a full iteration, thoroughly evaluate the outcomes from each pipeline. This evaluation should consider various factors, including status codes, logs, and performance. \n5. **GitLab CI transition:** As you gain confidence in the reliability and effectiveness of GitLab CI through the parallel runs, make the transition to the GitLab CI workflow as the required standard while Jenkins continues to operate in the background.\n6. **Jenkins phaseout:** After a second iteration, when you are confident in the performance and stability of GitLab CI, you can begin to remove the Jenkins job from your code verification pipeline. This successful transition will enable you to retire Jenkins from this particular aspect of your CI/CD process.\n\nThis recommended approach ensures that your migration is a gradual evolution, allowing you to identify and address any issues or discrepancies before fully committing to GitLab CI. Running Jenkins and GitLab CI pipelines in parallel provides valuable insights and ensures the effective streamlining of your CI/CD processes.\n\n## Preparing for migration: Training and communication\nTo ensure a smooth and successful migration from Jenkins to GitLab CI, follow these essential steps:\n- **Stakeholder communication:** Start by announcing your migration plans and timelines to all relevant stakeholders. This includes DevOps teams, developers, and QA engineers. Transparency in communication is crucial to ensure that everyone understands the objectives and expectations of the migration.\n- **Knowledge-level training:** Conduct knowledge-level training sessions for your teams to promote GitLab CI adoption.\nCover topics such as using GitLab CI, understanding the YAML syntax, and how to create a basic pipeline.\nProvide team members with the knowledge and skills necessary to navigate the new GitLab CI environment effectively.\n- **Hands-on learning:** Encourage hands-on learning by pairing up developers.\nCreate opportunities for them to learn from each other's experiences throughout the migration process.\n\nBy following these instructions for training and communication, you'll build a strong foundation for a successful migration, empowering your teams to adapt and thrive in the new environment.\n\n## 3 Jenkins-to-GitLab CI migration strategies\nThere are different strategies to consider. These three strategies offer flexibility, allowing organizations to choose the path that best aligns with their specific needs and resources. Let's explore these strategies in detail to help you make an informed decision about which one suits your organization best.\n\n### Migration Strategy 1: Using GitLab CI for new projects\nThe first migration strategy involves a gradual transition. While you maintain your existing Jenkins infrastructure for ongoing projects, you introduce GitLab CI for new projects. This approach allows you to harness the modern features of GitLab CI without disrupting your current work.\n\n#### Benefits of Migration Strategy 1\nThe benefits of this approach include the following:\n- New projects can leverage GitLab CI's advanced features right from the start. \n- This strategy minimizes the risk of disrupting existing workflows, as your existing Jenkins setup remains intact.\n- Your team can gradually adapt to GitLab CI, building confidence and expertise without the pressure of an immediate full-scale migration.\n\n#### Challenges of Migration Strategy 1\nThe challenges of this approach include the following:\n- Operating two CI/CD platforms simultaneously can introduce complexity, especially in terms of integration and team collaboration.\n- Managing projects on different platforms may require careful coordination to ensure consistency in processes and security practices.\n\nThis strategy offers a smooth and manageable transition by allowing you to harness GitLab CI's strengths for new projects, while your existing Jenkins infrastructure continues to support ongoing work.\n\n### Migration Strategy 2: Migrating only strategic projects\nIn this strategy, you identify specific projects within your organization that stand to benefit the most from the capabilities of GitLab CI. Instead of preparing for a wholesale migration, you start by focusing your efforts on migrating these strategically selected projects first.\n\n#### Benefits of Migration Strategy 2\nThe benefits of this approach include the following:\n- By concentrating on key projects, you can realize significant improvements in those areas where GitLab CI aligns with specific needs.\n- This approach reduces the complexity of migrating everything at once, minimizing the potential for disruptions.\n- You can gradually build confidence with GitLab CI and its benefits before considering further migrations.\n\n#### Challenges of Migration Strategy 2\nThe challenges of this approach include the following:\n- Even though you're not migrating all projects, the chosen projects' migration can still be intricate and require careful planning.\n- Ensuring seamless collaboration between projects on different platforms may require additional attention.\n\nThis strategy allows you to maximize the impact of GitLab CI by focusing on strategic areas, minimizing risk, and gradually gaining experience with the new tool.\n\n### Migration Strategy 3: Migrating everything\nThe third strategy is a comprehensive migration where you commit to moving all your CI/CD processes, projects, and workflows to GitLab CI. This approach aims for uniformity and simplification of CI/CD across all projects. This strategy can benefit from taking an iterative approach. Consider starting with new projects, followed by migrating strategic projects, and then leverage your growing knowledge and experience with GitLab CI to complete the migration of remaining projects. \n\n#### Benefits of Migration Strategy 3\nThe benefits of this approach include the following:\n- Uniform CI/CD processes across all projects can streamline administration and maintenance, reducing complexity.\n- You can take full advantage of GitLab CI's modern capabilities, from Infrastructure as Code to enhanced security features.\n- As your projects grow, GitLab CI is designed to handle increased demands, ensuring long-term scalability.\n\n#### Challenges of Migration Strategy 3\nThe challenges of this approach include the following:\n- A full-scale migration can be intricate, requiring meticulous planning and implementation.\n- The transition may disrupt ongoing projects and require a significant time investment.\n- Investment in training and potential tool migration expenses should be considered.\n\nOpt for this approach if uniformity and consolidation of CI/CD processes are a high priority, and you have the resources to execute a full migration.\n\nThe migration strategy you select should align with your organization's specific needs and circumstances. In all cases, the ultimate goal is to enhance your development process with modern CI/CD tools like GitLab CI, which offers scalability, infrastructure automation, security, and collaboration features that align with today's development needs.\n\n## Technical insights: How the migration works\nMoving your CI/CD workflows from Jenkins to GitLab CI is a transformative journey, and understanding how it works is vital for a successful transition.\n\n### Understanding the configurations: Jenkinsfile vs. .gitlab-ci.yml\nThe heart of your CI/CD pipeline lies in the configurations defined in your Jenkinsfile (for Jenkins) and .gitlab-ci.yml (for GitLab CI). While there are some similarities between these configuration files, there are notable differences as well.\n\n#### Similarities\n- Both files define the stages, jobs, and steps of your CI/CD process.\n- You specify the desired build, test, and deployment steps in both files.\n- Environment variables and settings can be configured in either file.\n\n#### Differences\n- Jenkinsfile uses Groovy for scripting, while .gitlab-ci.yml uses YAML. This change in language affects the way you write and structure your configurations.\n- The process of defining pipelines is more intuitive in .gitlab-ci.yml, with a cleaner, more human-readable syntax.\n- GitLab CI provides a wide range of built-in templates and predefined jobs, simplifying configuration and reducing the need for custom scripting.\n\n### Manually converting the pipeline configuration\nCurrently, migrating your existing Jenkins pipelines to GitLab CI is typically done manually. This means analyzing your Jenkinsfile and re-creating the equivalent configurations in .gitlab-ci.yml. While there are similarities in the concepts and structure, the differences in syntax and the specific capabilities of each platform require careful consideration during the migration.\n\n## Strategic planning for a smooth transition\nMigrating from Jenkins to GitLab CI requires meticulous planning to ensure a seamless transition. It's crucial to assess the disparities between the two systems and evaluate their impact on your workflow, considering aspects like security, cost, time, and capacity.\n\nOnce you've identified these differences and devised your migration strategy, break down the migration into key steps. These include setting up GitLab CI pipelines, securely transferring data from Jenkins to GitLab CI, and integrating GitLab CI into your existing tools and processes. \n\n## Case study: A seamless transition for Lockheed Martin\nLet's look at a real-world case study to illustrate the effectiveness of the \"Migrate Everything\" strategy. [Lockheed Martin](https://about.gitlab.com/customers/lockheed-martin/), the world’s largest defense contractor, had been using Jenkins for several years. As their project portfolio expanded, they realized that their Jenkins implementation with a wide variety of DevOps tools was becoming increasingly complex to manage. They were also eager to adopt modern CI/CD capabilities that Jenkins struggled to provide.\n\nIn collaboration with GitLab, Lockheed Martin decided to undertake a comprehensive migration to GitLab CI. Their goals included achieving consistency in their CI/CD processes, simplifying administration and maintenance, and taking full advantage of The GitLab Platform’s robust features.\n\nThe comprehensive migration strategy proved to be a resounding success for Lockheed Martin. With GitLab CI, they not only streamlined their CI/CD processes but achieved remarkable results. **They managed to run CI pipeline builds a staggering 80 times faster, retired thousands of Jenkins servers, and reduced the time spent on system maintenance by a staggering 90%. This monumental shift resulted in a significant increase in efficiency and productivity for Lockheed Martin.**\n\nThis case study showcases how a comprehensive migration strategy can be effective for organizations looking to leverage GitLab capabilities across all their projects.\n\nFor more in-depth insights into Lockheed Martin's successful transition to GitLab and how it streamlined their software development processes, check out [the detailed case study](https://about.gitlab.com/customers/lockheed-martin/).\n\n## GitLab documentation and support\nFor those embarking on this migration journey, GitLab offers documentation to guide you through the process. You can find valuable resources in GitLab's [official documentation](https://docs.gitlab.com/ee/ci/migration/jenkins.html).\n\nIn addition to documentation, GitLab's Professional Services team is available to assist organizations in their migrations. They bring expertise and experience to ensure a smooth transition. Whether it's understanding the nuances of Jenkinsfile to .gitlab-ci.yml conversion or optimizing your CI/CD workflows, their support can be invaluable.\n\n> Try GitLab CI/CD today with [a free trial of Ultimate](https://gitlab.com/-/trials/new).\n",[807,276,934,9,976,851],{"slug":2407,"featured":6,"template":696},"jenkins-gitlab-ultimate-guide-to-modernizing-cicd-environment","content:en-us:blog:jenkins-gitlab-ultimate-guide-to-modernizing-cicd-environment.yml","Jenkins Gitlab Ultimate Guide To Modernizing Cicd Environment","en-us/blog/jenkins-gitlab-ultimate-guide-to-modernizing-cicd-environment.yml","en-us/blog/jenkins-gitlab-ultimate-guide-to-modernizing-cicd-environment",{"_path":2413,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2414,"content":2420,"config":2426,"_id":2428,"_type":13,"title":2429,"_source":15,"_file":2430,"_stem":2431,"_extension":18},"/en-us/blog/keyless-signing-with-cosign",{"title":2415,"description":2416,"ogTitle":2415,"ogDescription":2416,"noIndex":6,"ogImage":2417,"ogUrl":2418,"ogSiteName":683,"ogType":684,"canonicalUrls":2418,"schema":2419},"Streamline security with keyless signing and verification in GitLab","Our partnership with Sigstore means that with just a few lines in a yml file, GitLab customers can make their development environment more secure.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664923/Blog/Hero%20Images/security-checklist.png","https://about.gitlab.com/blog/keyless-signing-with-cosign","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Streamline security with keyless signing and verification in GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sam White\"}],\n        \"datePublished\": \"2023-09-13\",\n      }",{"title":2415,"description":2416,"authors":2421,"heroImage":2417,"date":2423,"body":2424,"category":716,"tags":2425},[2422],"Sam White","2023-09-13","\nTraditional cryptographic keys have created security issues and management overhead for software development teams for years. To address these security issues and ease the administrative burden, GitLab is partnering with Sigstore to use their command-line utility Cosign for [keyless signing and verification](https://docs.gitlab.com/ee/ci/yaml/signing_examples.html), which can be done by adding just a few lines in a yml file.\n\nBefore digging too far into the integration, though, let's take a closer look at some of the issues of traditional key management and some of the benefits of keyless signing.\n\n## Traditional key management\nCryptographic keys have been a mainstay of securing software and network elements for years. Traditional key management involves the generation, storage, distribution, and protection of cryptographic keys that are essential for processes like encryption, decryption, and digital signing. While these methods have worked well over the years, they pose challenges that can impact security and operational efficiency.\n\n* Complexity and risk of exposure: Generating, storing, and distributing cryptographic keys manually can be error-prone and time-consuming. This complexity increases the risk of key exposure due to mismanagement or vulnerabilities in the key storage systems.\n\n* Security risk: Risk that the key management system (KMS) might be compromised and the private key leaked. There is no way for users to verify that the public key has not been tampered with or modified.\n\n* Key rotation complexity: Regular key rotation is a security best practice, but it can be complex to manage, especially when dealing with large numbers of keys. Key rotation will often disrupt applications.\n\n* Key revocation: Revoking access to keys that are no longer needed or that have been compromised can be challenging, especially if those keys are widely used across different parts of your application.\n\n* Integration complexity: Integrating your application with a KMS can introduce complexity. If your application is distributed or consists of microservices the complexity increases.\n\n* Key distribution: There is no standard way of distributing public keys. A system for distribution must be selected and secure, and if that system is compromised the public key must be changed.\n\n![A diagram of how traditional key management works](https://about.gitlab.com/images/blogimages/traditionalkeymanagement.png){: .shadow}\n\nHow traditional key management works\n{: .note.text-center}\n\n## The move to keyless signing\nRecently, the industry has been making a push towards keyless signing. With keyless signing, a message is signed using an ephemeral key that is generated and used for signing. The key is only valid for a few minutes, greatly reducing the complexity and security issues associated with traditional key management.\n\nKeyless signing has several advantages. \n* Enhanced security: Keyless signing removes the need to store private keys on user devices, reducing the risk of exposure to malware or unauthorized access. \n\n* Simplified key management: With keyless signing, the complexities of key generation, distribution, and rotation are abstracted, leading to simplified key management processes. This streamlines operational workflows and reduces the potential for human error.\n\n* Audit trail: Keyless signing systems provide comprehensive audit trails and logging. Artifact verification is possible since public keys cannot be tampered with.\n\n* Remote signing and access: Keyless signing allows remote signing operations, enabling users to sign documents and transactions securely from anywhere. This capability enhances accessibility and collaboration without sacrificing security.\n\n* Regulatory compliance: The audit trails and accountability provided by keyless signing solutions facilitate regulatory compliance. With keyless signing, organizations can more confidently meet industry standards and demonstrate their commitment to secure practices.\n\n\n![A diagram of how keyless signing works](https://about.gitlab.com/images/blogimages/keylesssigningdiagram.png){: .shadow}\n\nHow keyless signing works\n{: .note.text-center}\n\n## Keyless signing within GitLab\nGitLab has partnered with one of the leaders in the keyless signing space, Sigstore, to help customers move away from traditional keys and easily make the transition to keyless signing.  \n\nThe Sigstore project provides a command-line utility called Cosign, which can be used for keyless signing of container images built with the GitLab CI/CD. By adding a few lines of code to the GitLab yml file, GitLab users can use Cosign to leverage the benefits of keyless signing. Sigstore’s Cosign enables software developers to sign release files, binaries, and other software artifacts.  \n\nOnce enabled within GitLab, when a user runs a pipeline, Cosign requests a short-lived key pair to use for signing, records it on a certificate transparency log (Rektor), and then discards it. The key is generated through a token obtained from the GitLab server using the [OIDC](https://docs.gitlab.com/ee/administration/auth/oidc.html) identity of the user who ran the pipeline. This token includes unique claims that certify the token was generated by a CI/CD pipeline. The private key only lasts for a short time so there is no need to store it or rotate it. With Cosign, verification data, including the public key, signature, and signing timestamp, is written to the immutable Rektor log (an append-only transparency ledger) so that signing events can be publicly audited. Users can then verify the binary and signature against the public key.\n\nThe whole process is quick and easy and greatly increases system-wide security. With this integration, there is no longer a need to set up a key management system, no longer a need to rotate keys, and no longer a need to distribute public keys. Life is simpler and more secure!\n\n## Next steps\nThis feature is now available on all tiers of GitLab SaaS.\n\nWatch a setup demo here:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/Ws2D77n4nAg?si=jhDRWXH7oJEwvyLS\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nFor more details, check out [Sigstore’s keyless signature documentation](https://docs.sigstore.dev/#how-sigstore-works) and then start your [free trial of GitLab Ultimate](https://gitlab.com/-/trials/new?glm_content=default-saas-trial&glm_source=about.gitlab.com).\n\n\n\n\n\n",[716,763,281,9],{"slug":2427,"featured":6,"template":696},"keyless-signing-with-cosign","content:en-us:blog:keyless-signing-with-cosign.yml","Keyless Signing With Cosign","en-us/blog/keyless-signing-with-cosign.yml","en-us/blog/keyless-signing-with-cosign",{"_path":2433,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2434,"content":2440,"config":2447,"_id":2449,"_type":13,"title":2450,"_source":15,"_file":2451,"_stem":2452,"_extension":18},"/en-us/blog/kontra-and-gitlab-integrate-vulnerability-education-into-the-devops-workflow",{"title":2435,"description":2436,"ogTitle":2435,"ogDescription":2436,"noIndex":6,"ogImage":2437,"ogUrl":2438,"ogSiteName":683,"ogType":684,"canonicalUrls":2438,"schema":2439},"Integrating vulnerability education into DevOps workflows","Interactive training labs are now available within the GitLab platform from Kontra Application Security, a ThriveDX company.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668199/Blog/Hero%20Images/KontraCover.png","https://about.gitlab.com/blog/kontra-and-gitlab-integrate-vulnerability-education-into-the-devops-workflow","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Kontra and GitLab integrate vulnerability education into the DevOps workflow\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Gyan Chawdhary\"}],\n        \"datePublished\": \"2022-03-31\",\n      }",{"title":2441,"description":2436,"authors":2442,"heroImage":2437,"date":2444,"body":2445,"category":1244,"tags":2446},"Kontra and GitLab integrate vulnerability education into the DevOps workflow",[2443],"Gyan Chawdhary","2022-03-31","\n\nInteractive training labs are now available within the GitLab DevOps platform from Kontra Application Security, a ThriveDX company. This integration allows GitLab users to access Kontra’s interactive security training modules from the familiar Merge Request (MR) and pipeline experiences to quickly learn about and fix vulnerabilities reported through automated security scans.\n\nKontra’s content is also available in GitLab’s vulnerability management features, providing the same easy access to training on vulnerabilities identified from these same security scans, as well as other sources such as penetration tests or bug bounty programs. By putting interactivity into our learning simulations, we put the developer first, helping them to understand the risk and impact of a vulnerability from an attacker's perspective.\n\n## So, what is Kontra?\n\nKontra is a scalable Application Security Training platform powered by ThriveDX. This training application was built for modern development teams and it aims to give developers the most advanced security simulations for the best quality training. Kontra works by creating short educational sessions of real-life security incidents to give developers the necessary skills to build and maintain secure application code. \n\nBy going through a simulated security scenario, developers gain better insight into how to get ahead of would-be cyber attackers. \n\n## The benefits of interactive developer security education\n\nAs enterprise developers become increasingly responsible for the security and integrity of their applications, they require relevant, actionable, and engaging security education that enables them to:\n\n- quickly understand and resolve security vulnerabilities\n- design controls to proactively prevent security issues\n- confidently communicate and assign security issues within engineering teams\n\nUnfortunately, these skills are almost never taught in academic courses or coding bootcamps. To address this gap, enterprise software developers often undergo annual developer security training, which typically involves consuming a PowerPoint presentation or watching a recorded presentation on software vulnerabilities and issues. The problem with this style of training is that it lacks actionable explanations, is too passive, or contains generic content that doesn't resonate with developers and engineers.\n\nKontra’s short training sessions are designed to be played in less than five minutes, ensuring that the correct explanations are provided to the developer to fully understand the security impact of a reported vulnerability and how to address it. The short sessions also make it easier to apply the security fix to the code.\n\n## The elements of interactive training\n\nThe most important aspect of training and education is how you convey and communicate ideas visually. This requires strong visual design, empathy, aesthetics, and communication with the learner. Kontra’s interactive training tutorials are offered in multiple programming languages and frameworks, ensuring each lesson is relevant to the developer.\n\nKontra’s learning environment consists of many different interactive UI elements which, depending on a specific vulnerability, are dynamically shown to the learner, ensuring that both the context and the impact of a vulnerability are demonstrated. \n\n![Kontra learning console](https://about.gitlab.com/images/blogimages/Kontra1.png){: .shadow}\n\n## How developers experience the vulnerability education integration\n\nTo have the highest impact, training is placed prominently, yet unobtrusively, where developers spend time: in MRs and pipelines. Developers can view vulnerabilities found by automated security scans in a dedicated MR security widget as well as a pipeline security tab. Clicking on a vulnerability shows its details such as a description and any identifiers such as a [Common Vulnerabilities and Exposures (CVE)](https://cve.mitre.org/) or [Common Weakness Enumeration (CWE)](https://cwe.mitre.org/). Once enabled, GitLab can now place a link to a relevant training from Kontra right in this details view. The identifier is used to dynamically locate the relevant content. And for security professionals, the same training content is available when viewing vulnerability details pages from GitLab’s Vulnerability Reports. \n\n## How to install and configure Kontra training\n\nKontra’s training is available to all [GitLab Ultimate](/pricing/ultimate/) customers. Simply [enable it](https://docs.gitlab.com/ee/user/application_security/vulnerabilities/#enable-security-training-for-vulnerabilities) for any desired projects.\n\n\n![Kontra security configuration](https://about.gitlab.com/images/blogimages/Kontra3.png){: .shadow}\n\nThen, look at the results from a [GitLab security scan](https://docs.gitlab.com/ee/user/application_security/#security-scanning-tools) (or one of GitLab’s [integration partners](/partners/technology-partners/#security)) in an MR, pipeline security tab, or a vulnerability details page. When you open a vulnerability record, you will see a direct link to training. GitLab will pull a training from Kontra that most closely matches the particular security issue and the specific language or framework in which it was detected.\n\n![Kontra predictable pseudorandom number generator](https://about.gitlab.com/images/blogimages/Kontra2.png){: .shadow}\n\n_Chawdhary is head of application security at ThriveDX SaaS._\n",[9,716,851],{"slug":2448,"featured":6,"template":696},"kontra-and-gitlab-integrate-vulnerability-education-into-the-devops-workflow","content:en-us:blog:kontra-and-gitlab-integrate-vulnerability-education-into-the-devops-workflow.yml","Kontra And Gitlab Integrate Vulnerability Education Into The Devops Workflow","en-us/blog/kontra-and-gitlab-integrate-vulnerability-education-into-the-devops-workflow.yml","en-us/blog/kontra-and-gitlab-integrate-vulnerability-education-into-the-devops-workflow",{"_path":2454,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2455,"content":2460,"config":2466,"_id":2468,"_type":13,"title":2469,"_source":15,"_file":2470,"_stem":2471,"_extension":18},"/en-us/blog/kubecon-na-2019-are-you-about-to-break-prod",{"title":2456,"description":2457,"ogTitle":2456,"ogDescription":2457,"noIndex":6,"ogImage":863,"ogUrl":2458,"ogSiteName":683,"ogType":684,"canonicalUrls":2458,"schema":2459},"KubeCon NA: Are you about to break Prod?","Use Pulumi and GitLab to build a pipeline that validates your application, infrastructure, and deployment process.","https://about.gitlab.com/blog/kubecon-na-2019-are-you-about-to-break-prod","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"KubeCon NA: Are you about to break Prod?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Erin Krengel, Pulumi\"}],\n        \"datePublished\": \"2020-01-27\",\n      }",{"title":2456,"description":2457,"authors":2461,"heroImage":863,"date":2463,"body":2464,"category":691,"tags":2465},[2462],"Erin Krengel, Pulumi","2020-01-27","\n\nA couple of months ago, my [Pulumi](https://www.pulumi.com/) colleague Sean Holung, staff sofware engineer, and I had the opportunity to present [\"Are you about to break prod? Acceptance Testing with Ephemeral Environments\"](https://www.youtube.com/watch?v=jAQhDZiRzBQ) at KubeCon NA 2019. In this talk, we covered what is an ephemeral environment, how to create one, and then we walked the audience through a concrete example. Given our limited time, we had to move quickly through a ton of information. This post will recap our presentation and add a few more details we weren't able to cover.\n\nAs software engineers, our job is to deliver business value. To do this, we need to be delivering software both quickly and reliably.\n\nSo the question we ask you is: are you about to break prod? Everyone will break production at some point because there are things we miss. As independent software lead Alexandra Johnson sums up so well in a tweet: \"Failures are part of the cost of building and shipping large systems.\" Building a robust pipeline allows us to move quickly in the case of failure and gain confidence around making changes to our infrastructure and applications.\n\n{::options parse_block_html=\"false\" /}\n\n\u003Cdiv class=\"center\">\n\n\u003Cblockquote class=\"twitter-tweet\">\u003Cp lang=\"en\" dir=\"ltr\">Big takeaway from \u003Ca href=\"https://twitter.com/hashtag/KubeCon?src=hash&amp;ref_src=twsrc%5Etfw\">#KubeCon\u003C/a>: none of us want to break prod, but failures are part of the cost of building and shipping large systems. Using tools like \u003Ca href=\"https://twitter.com/hashtag/AcceptanceTesting?src=hash&amp;ref_src=twsrc%5Etfw\">#AcceptanceTesting\u003C/a> (\u003Ca href=\"https://twitter.com/eckrengel?ref_src=twsrc%5Etfw\">@eckrengel\u003C/a>) and \u003Ca href=\"https://twitter.com/hashtag/ChaosEngineering?src=hash&amp;ref_src=twsrc%5Etfw\">#ChaosEngineering\u003C/a> (\u003Ca href=\"https://twitter.com/Ana_M_Medina?ref_src=twsrc%5Etfw\">@Ana_M_Medina\u003C/a>) can increase your confidence in your infrastructure changes!\u003C/p>&mdash; Alexandra Johnson (@alexandraj777) \u003Ca href=\"https://twitter.com/alexandraj777/status/1198373475049623552?ref_src=twsrc%5Etfw\">November 23, 2019\u003C/a>\u003C/blockquote> \u003Cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\">\u003C/script>\n\n\u003C/div>\n\nWith this in mind, we use Pulumi and GitLab to build a pipeline that validates both our application, infrastructure, and deployment process. \n\n## Ephemeral environments\n\nWhat is an ephemeral environment? It is a short-lived environment that mimics a production environment. To maintain agility, boundaries are defined in the environment to only encompass the first-level dependencies of the particular microservice that is being deployed. It means you don't have to spin up every single microservice or piece of infrastructure that's running in production. Yet you may need to spin up extra pieces of infrastructure to properly test the microservice. For example, you may need to create a subscription to pull from a PubSub topic your microservice writes to. This subscription would allow your acceptance tests to pull from a topic in order to validate an outbound message is published.\n\n## Why this is important\n\nInfrastructure is a key part of an application's behavior. The architecture and requirements are continually evolving. How can you incorporate these into a testing suite to give us a high degree of confidence?\n\nEphemeral environments allow you to integrate infrastructure and deployment processes into a testing suite. They ensure your testing environment is always in-sync with production and therefore allow you to iterate quickly to meet new requirements.\n\nEphemeral environments also encourage you to lean on automated tests over manual tests. If you use ephemeral environments as a replacement for a testing environment, there is not enough time to go in and run a manual check. Shifting your mindset to automated tests can be challenging, yet it's imperative that we do so. Automated tests guarantee your application behaves as expected today as well as months from now when you're out on vacation.\n\n## Our demo application\n\nTo demonstrate the effectiveness of integrating acceptance testing with ephemeral environments into your deployment process, we created a simple demo application. The service is written in Go and accepts a message on the `/message` endpoint, then places it in a storage bucket and sends a notification about the new object on a PubSub topic. The code for this application lives in our [main.go](https://gitlab.com/rocore/demo-app/blob/master/main.go) file. While you can walk through this code yourself, the most important thing to call out is that our application is *configurable*. This means we take configuration in at the very beginning of our main function and shut down the application if the values are not present.\n\n```go\nfunc main() {\n    ...\n\t// Get configuration from environment variables. These are\n\t// required configuration values, so we use an helper\n\t// function get the values and exit if the value is not set.\n\tproject := getConfigurationValue(\"PROJECT\")\n\ttopicName := getConfigurationValue(\"TOPIC\")\n\tbucketName := getConfigurationValue(\"BUCKET\")\n    ...\n}\n\nfunc getConfigurationValue(envVar string) string {\n\tvalue := os.Getenv(envVar)\n\tif value == \"\" {\n\t\tlog.Fatalf(\"%s not set\", envVar)\n\t}\n\tlog.Printf(\"%s: %s\", envVar, value)\n\treturn value\n}\n```\n\n### Infrastructure\n\nThere are many pieces of infrastructure to spin up and we can use Pulumi to easily wire it all together. Our architecture looks like this:\n\n![Pulumi Architecture](https://about.gitlab.com/images/blogimages/pulumidemoarch.jpg){: .medium.center}\n\nYou can check out the Pulumi code that we use to reproduce both our ephemeral environments as well as production in the [infrastructure/index.ts](https://gitlab.com/rocore/demo-app/blob/master/infrastructure/index.ts) file. The neat thing about using Pulumi is that we can create the Google Cloud Platform (GCP) resources we need and then directly reference them in our Kubernetes deployment. Using Pulumi ensures we're always configuring our application with the correct GCP resources for that environment.\n\nFor example, in our Kubernetes deployment, we set the environment variables by using the topic and bucket variables created just above.\n\n```typescript\n// Create a K8s Deployment for our application.\nconst appLabels = { appClass: name };\nconst deployment = new k8s.apps.v1.Deployment(name, {\n    metadata: { labels: appLabels },\n    spec: {\n        selector: { matchLabels: appLabels },\n        template: {\n            metadata: { labels: appLabels },\n            spec: {\n                containers: [{\n                    ...\n                    env: [\n                        { name: \"TOPIC\", value: topic.name }, // referencing topic just created\n                        { name: \"BUCKET\", value: bucket.name }, // referencing bucket just created\n                        { name: \"PROJECT\", value: project },\n                        {\n                            name: \"GOOGLE_APPLICATION_CREDENTIALS\",\n                            value: \"/var/secrets/google/key.json\"\n                        },\n                    ],\n                    ...\n                }]\n            }\n        }\n    },\n});\n```\n\n### Acceptance tests\n\nThe acceptance tests validate that our service, when stood up, functions as expected. They are run against an ephemeral environment. The tests live in the `acceptance/acceptance_test.go` [file](https://gitlab.com/rocore/demo-app/blob/master/acceptance/acceptance_test.go). You'll notice we're once again using the helper function `getConfigurationValue`. Our acceptance test must also be configured to ensure they're validating against the correct resources for that particular ephemeral environment.\n\nSince the service is only accessible from within the Kubernetes cluster, we use a Kubernetes job to run our acceptance tests. Using a Kubernetes job is a good technique to use when your CI is running externally, such as from GitLab, and you do not want to expose your service publicly. Our ephemeral environment plus acceptance test looks like this:\n\n![Acceptance Tests](https://about.gitlab.com/images/blogimages/pulumiacceptancetestarch.jpg){: .medium.center}\n \nWe spin up a Kubernetes Job and additional resources by using an if statement at the bottom of our `infrastructure/index.ts` file. The conditional depends on the environment's name as follows:\n\n```typescript\n// If it's a test environment, set up acceptance tests.\nlet job: k8s.batch.v1.Job | undefined;\nif (ENV.startsWith(\"test\")) {\n    job = acceptance.setupAcceptanceTests({\n        ...\n    });\n}\n\n// Export the acceptance job name, so we can get the logs from our\n// acceptance tests.\nexport const acceptanceJobName = job ? job.metadata.name : \"unapplicable\";\n```\n\nThat covers all the major aspects of our application and infrastructure, and if you'd like to view the code in detail, it is available in our `demo-app` [GitLab repository](https://gitlab.com/rocore/demo-app).\n\n## Our pipeline\n\nWhen developing a new service, we must establish a solid deployment strategy upfront. We want to make sure we're building in quality from day one. As we develop the service, we can add acceptance tests for every feature we add while the context and requirements are still fresh in our minds. This ensures we have thorough coverage of our app's functionality.\n\nWe used GitLab to set up our pipeline. We chose GitLab because it's straightforward to set up and allows us to run our pipeline on our Docker image of choice. We use a [base-image](https://gitlab.com/rocore/global-infra/blob/master/base-image/Dockerfile) that has all our dependencies installed and then reference that Docker image and tag in our `demo-app` pipeline. The Docker image allows us to bundle and version the dependencies for building our application and infrastructure.\n\n![GitLab Pipelines](https://about.gitlab.com/images/blogimages/pulumibloggitlabci.png){: .shadow.medium.center}\n \n1. **Test and Build** - This runs our unit tests and builds both our application and acceptance test images. To build our images, we used [Kaniko](https://github.com/GoogleContainerTools/kaniko), a tool for building images within a container or Kubernetes cluster. GitLab has excellent documentation on [how to incorporate Kaniko](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html) into your pipeline. The application image is an immutable image that is used for both running our acceptance tests and deploying to production.\n1. **Acceptance Test** - This is what spins up our ephemeral environments and runs our acceptance tests. This acts as a quality gate catching issues before production.\n\n    Our ephemeral environment and Kubernetes job are all spun up in the `script` portion of the acceptance test job definition. We do a bit of setup for our new acceptance test stack and then run `pulumi up`. Here is the print out from our acceptance tests.\n\n    ```bash\n    ...\n    $ pulumi stack init rocore/$ENV-app\n    Logging in using access token from PULUMI_ACCESS_TOKEN\n    Created stack 'rocore/test-96425413-app'\n    $ pulumi config set DOCKER_TAG $DOCKER_TAG\n    $ pulumi config set ENV $ENV\n    $ pulumi config set gcp:project rocore-k8s\n    $ pulumi config set gcp:zone us-west1-a\n    $ pulumi up --skip-preview\n    Updating (rocore/test-96425413-app):\n    ...\n    Resources:\n        + 16 created\n\n    Duration: 4m10s\n\n    Permalink: https://app.pulumi.com/rocore/demo-app/test-96425413-app/updates/1\n    ```\n\n    The `after_script` destroys our stack as well as prints the logs of both our Kubernetes job and deployment, which help with debugging if our tests were to fail. We use the `after_script` to make sure that we always clean up and print logs even when our acceptance tests fail.\n    \n    ```bash\n    ...\n    $ pulumi stack select rocore/$ENV-app\n    $ kubectl logs -n rocore --selector=appClass=$ENV-demo-app-acc-test --tail=200\n    === RUN   TestSimpleHappyPath\n    === RUN   TestSimpleHappyPath/message_is_sent_to_PubSub_topic\n    === RUN   TestSimpleHappyPath/message_is_stored_in_bucket\n    ",[1989,1040,693,108,9,276],{"slug":2467,"featured":6,"template":696},"kubecon-na-2019-are-you-about-to-break-prod","content:en-us:blog:kubecon-na-2019-are-you-about-to-break-prod.yml","Kubecon Na 2019 Are You About To Break Prod","en-us/blog/kubecon-na-2019-are-you-about-to-break-prod.yml","en-us/blog/kubecon-na-2019-are-you-about-to-break-prod",{"_path":2473,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2474,"content":2480,"config":2486,"_id":2488,"_type":13,"title":2489,"_source":15,"_file":2490,"_stem":2491,"_extension":18},"/en-us/blog/learn-gitlab-devops-version-control",{"title":2475,"description":2476,"ogTitle":2475,"ogDescription":2476,"noIndex":6,"ogImage":2477,"ogUrl":2478,"ogSiteName":683,"ogType":684,"canonicalUrls":2478,"schema":2479},"GitLab tutorials for secure pipelines, Kubernetes, and more at Learn@GitLab","Learn@GitLab offers videos and self-driven demos so you can get the most out of GitLab at your own pace.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667236/Blog/Hero%20Images/Learn-at-GL.jpg","https://about.gitlab.com/blog/learn-gitlab-devops-version-control","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab tutorials for secure pipelines, Kubernetes, and more at Learn@GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Chrissie Buchanan\"}],\n        \"datePublished\": \"2021-01-12\",\n      }",{"title":2475,"description":2476,"authors":2481,"heroImage":2477,"date":2483,"body":2484,"category":739,"tags":2485},[2482],"Chrissie Buchanan","2021-01-12","\nAt GitLab, we often say that it's not what you know, it's knowing where to look. But sometimes, finding answers isn’t so easy.\n\nAn autonomous, [self-service](/company/culture/all-remote/self-service/#proactive-approach-to-answering-questions), self-learning, and self-searching mindset is when you operate with the idea that your question has already been answered – somewhere. But we realized that for people interested in GitLab, or even those using GitLab, learning **how** to use it wasn’t always easy to find.\n\nWhile we stress the importance of having a [single source of truth](https://handbook.gitlab.com/handbook/values/#single-source-of-truth), we realized that when it came to learning about GitLab, there were almost too many places to look. We have [GitLab University](https://docs.gitlab.com/ee/index.html), our official [GitLab](https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg) and [GitLab Unfiltered](https://www.youtube.com/channel/UCMtZ0sc1HHNtGGWZFDRTh5A) YouTube pages where we regularly upload educational content, and of course, the [docs](https://docs.gitlab.com/). We needed to find a way to consolidate self-education and make it more intuitive.\n\n## What is Learn@GitLab?\n\n[Learn@GitLab](/learn/) is a learning portal where anyone can go to find self-driven demos and videos about using GitLab. Rather than just making Learn@GitLab _one more resource_, we’re iterating on this idea and consolidating our educational content so that it’s self-driven and easy to find.\n\nThe goal for Learn@GitLab is to present high quality, and accessible technical content that is easy to find on our website to help prospects and users educate themselves about GitLab. This content will include educational technical videos, as well as simulation/click-through demos, and tutorials. The content is organized by common topics such as [DevOps Platform](/solutions/devops-platform/), [version control](/topics/version-control/) and collaboration, and continuous integration, to name a few.\n\nWe’ve picked three of our favorite videos/tutorials for you to get a quick introduction to Learn@GitLab.\n\n## The benefits of a single DevOps platform\n\nWhen we talk about the benefits of GitLab, we often talk about how it saves time and how the single application reduces toolchain complexity. But what does that mean in the context of an ordinary toolchain using tools like GitHub, Jenkins, Jira, etc.?\n\nIn this super short video, we break down a typical toolchain according to three criteria: Integrations needed, clicks, and screen switches. How many times do you need to context switch for a simple task? We break it down for you.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/MNxkyLrA5Aw\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n## Adding security to your GitLab CI/CD pipeline\n\nGitLab helps teams go from DevOps to DevSecOps. One of the ways we help is by allowing you to check your application for security vulnerabilities in your CI/CD pipelines that may lead to unauthorized access, data leaks, denial of services, or worse. GitLab reports these vulnerabilities in the merge request so you can fix them before they ever reach end users.\n\nThis quick video guides you through setting up and configuring GitLab security features, and setting up approval rules for merge requests.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/Fd5DhebtScg\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n## GitLab developer flow with Kubernetes\n\nIf you’re a developer, or even just managing a team of developers, you might want to see what a typical workflow would be like using GitLab. If you’re using [Kubernetes](/solutions/kubernetes/), seeing how GitLab works within a deployment environment is especially important.\n\nIn this technical demo, we use Amazon EKS as the deployment environment. We go over creating GitLab issues, merge requests, how to use Auto DevOps pipeline templates, review apps, advanced deployment techniques, and staging and production rollout – all in **just 15 minutes.**\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/TMQziI2VDbQ\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nWhile we’ll continue to have educational content in other places on our site (and will continue to update them), Learn@GitLab will act as a front door for self education that is no more than two clicks from our homepage. With this new learning portal, we hope to teach people what problems GitLab can solve, but more importantly, show step-by-step _how_ GitLab solves them.\n\nFeel free to explore the different learning paths and comment below if you have any suggestions. Everyone can contribute.\n\n\u003Ci class=\"fab fa-gitlab\" style=\"color:rgb(107,79,187); font-size:.85em\" aria-hidden=\"true\">\u003C/i>&nbsp;&nbsp;\n[Go to Learn@GitLab](/learn/)!\n&nbsp;&nbsp;\u003Ci class=\"fab fa-gitlab\" style=\"color:rgb(107,79,187); font-size:.85em\" aria-hidden=\"true\">\u003C/i>\n\nCover image by [Benjamin Davies](https://unsplash.com/@bendavisual?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/learn?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",[1161,9,807],{"slug":2487,"featured":6,"template":696},"learn-gitlab-devops-version-control","content:en-us:blog:learn-gitlab-devops-version-control.yml","Learn Gitlab Devops Version Control","en-us/blog/learn-gitlab-devops-version-control.yml","en-us/blog/learn-gitlab-devops-version-control",{"_path":2493,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2494,"content":2500,"config":2506,"_id":2508,"_type":13,"title":2509,"_source":15,"_file":2510,"_stem":2511,"_extension":18},"/en-us/blog/lessons-weet-learned-lokalise",{"title":2495,"description":2496,"ogTitle":2495,"ogDescription":2496,"noIndex":6,"ogImage":2497,"ogUrl":2498,"ogSiteName":683,"ogType":684,"canonicalUrls":2498,"schema":2499},"How Weet integrates localization into the GitLab pipeline with Lokalise","Localization is an increasingly important option for users. Here's how to integrate localization in your GitLab pipeline.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668543/Blog/Hero%20Images/lokalise_cover.png","https://about.gitlab.com/blog/lessons-weet-learned-lokalise","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How Weet integrates localization into the GitLab pipeline with Lokalise\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Alexander Pereverzevs\"}],\n        \"datePublished\": \"2021-09-13\",\n      }",{"title":2495,"description":2496,"authors":2501,"heroImage":2497,"date":2503,"body":2504,"category":1244,"tags":2505},[2502],"Alexander Pereverzevs","2021-09-13","\n\nAs a GitLab customer, Weet has fully invested in the premise of \"Iterate faster, innovate together.\" Weet has a low tolerance for processes that don't keep pace with the way they develop and launch. One important process that was slowing the business down – localizing their app.\n\nLocalization is a key way to drive growth and accelerate product adoption. When done poorly, localization or l10n, as it's commonly known, can slow down your development process, introduce bugs, and make it cumbersome to launch updates. When done right, teams can smooth out the process and [continuously localize](https://lokalise.com/features/localization-process-automation) their app. We unpack how Weet conquered its localization problems using GitLab and Lokalise.\n\n## What is Weet?\n\n[Weet](https://beeweet.com) is an asynchronous video communication tool designed to reduce the need for meetings. By combining video, audio, and screen sharing, it provides the nuance that written communication simply does not. For example, Weet's 10-person team, which is spread between France and the US, uses the product to speed through code reviews. The product has also been used for demos, design feedback, bug reports, QA reviews, and client presentations. At Lokalise, we use the tool to communicate with team members across time zones with ease and clarity.\n\nWeet started using GitLab five years ago and is using the latest version (13.11 as of this writing). For the runner they use 13.11 too, with an auto-scalable configuration (best feature ever!). The instance is self-managed on Google Cloud.\n\nWeet uses roughly 50 pipelines to manage processes such as: building the entire stack of the Weet application, checking the unit tests, deploying to a QA environment, deploying in production, launching the end-to-end tests, and more. The company currently has 17 projects set up, which are combined with GitLab CI/CD to deploy the Weet application.\n\nThey are, in summary... GitLab fans.\n\n## The first l10n solution\n\nWhen Weet first started localizing their app the engineering team considered two options:\n\n1. Download CSV files of strings, email them to the translators, and then reintegrate the data after the translation work was complete\n2. Translate directly in the IDE\n\nBoth options had their drawbacks. Downloading and uploading files takes developers out of the flow, but worse than that, the process can introduce l10n bugs that make the app look unreliable or amateurish. Also, these problems take time to resolve. It's not uncommon for version control to be an issue with this type of system.\n\nWeet chose the Web IDE option because it was easier to get started, but the process wasn't working at the pace they wanted.\n\n>> \"Before we used the Lokalise integration, we had to validate the new wording before each code push. The process was time-consuming as approvers were spread across different time zones,\" - Geraud Bonou-Selegbe, Full-stack engineer at Weet.\n\nHunting through the code to change all the instances of a word that needs to be replaced is not high on anyone's list of fun things to do.\n\nIt wasn't long before Jeremy Rouet, the CTO and co-founder of Weet, started looking for new options. If they wanted to fulfill the CI/CD promise of GitLab, they needed a tool that would integrate cleanly into the pipeline. Jeremy began testing translation management systems (TMS) and settled on integrating [Lokalise with GitLab](https://docs.lokalise.com/en/articles/1789855-gitlab).\n\n## How to continuously localize your product\n\nLokalise integrates into GitLab and allows a user (like Weet) to pull files into Lokalise, where translation tasks can be assigned and completed and then easily merged back.\n\n![Schema of how Lokalise works in GitLab](https://about.gitlab.com/images/blogimages/lokalize1.png){: .shadow.medium.center}\nA schema of how Lokalise works in GitLab.\n{: .note.text-center}\n\nDevelopers code as normal aiming to complete their work prior to each weekly release. Each push on master sends text strings automatically into Lokalise. Lokalise detects any changes to the text, so the developers don't have to remember what exactly they changed. Jeremy then uses the task features in Lokalise to assign the translation tasks to the Weet marketing team, who then go in and check all the new words.\n\nOnce the translation team is done, they create a merge request, and the product is ready to launch.\n\n>> \"Lokalise enabled us to bridge this gap by letting developers do what they do the best: coding. If my phrasing is not perfect, language experts can review it on Lokalise and then send a merge request with their updates. Now we've got the right expert in the right place for each milestone of our development process,\" says Geraud.\n\n![Lokalise Merge Request in GitLab](https://about.gitlab.com/images/blogimages/lokalize2.png){: .shadow.medium.center}\nWhat a merge request looks like using Lokalise and GitLab.\n{: .note.text-center}\n\nGone are the days of manually updating translations in the IDE in order to fix phrasing. Now app localization is a seamless and reliable part of the development workflow of the CI/CD process that is built around GitLab.\n\n## Steps to set up the integration\n\nFull instructions are available here. With over 500 keys in the app, the Weet team created several internal processes to keep their work tidy.\nOne move they made was to split their localization data into 5 projects/files. Each localization is a .json file. The separate files are:\n\n- emails\n- frontend\n- integration\n- server-side rendering\n- mobile – iOS/Android (WIP)\n\nThen to simplify key maintenance they used a naming pattern so that each component has its own keys. When they delete a component, they simply remove the main key from the localization file, which removes each label for this component. See below:\n\n![Deleting a component and removing main key from the localization file](https://about.gitlab.com/images/blogimages/lokalize3.png){: .shadow.medium.center}\nHow to delete a component and remove the main key from the localization file.\n{: .note.text-center}\n\nFinally, they tackled conflicts. The developers are able to edit the localization files both in Lokalise and in their environment. Changes in multiple systems could clash. To solve this problem, they decided that developers can only use Lokalise to update labels and they can only add or remove keys in their local environment.\n\n## What localization delivers\n\nIt took the Weet team some time and trial and error to smooth out the process.\n\nNow that the process is totally seamless, they can localize a new release in less than an hour with just a short quality check. That’s a big improvement from the days when they had to synchronize the dev, PO, and QA teams over a few days, to check and correct the new localization.\n\nWith their ability to continuously localize their app, they can focus on developing and delivering the best product possible. And it seems to be working as they were recently voted the #2 (closed) product of the week on Product Hunt. Coming up on the roadmap – mobile apps and more languages.\n",[717,9,693],{"slug":2507,"featured":6,"template":696},"lessons-weet-learned-lokalise","content:en-us:blog:lessons-weet-learned-lokalise.yml","Lessons Weet Learned Lokalise","en-us/blog/lessons-weet-learned-lokalise.yml","en-us/blog/lessons-weet-learned-lokalise",{"_path":2513,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2514,"content":2520,"config":2525,"_id":2527,"_type":13,"title":2528,"_source":15,"_file":2529,"_stem":2530,"_extension":18},"/en-us/blog/low-code-no-code",{"title":2515,"description":2516,"ogTitle":2515,"ogDescription":2516,"noIndex":6,"ogImage":2517,"ogUrl":2518,"ogSiteName":683,"ogType":684,"canonicalUrls":2518,"schema":2519},"The role low code app development tools may play at GitLab","Citizen developers are creating code without being coders. CEO Sid Sijbrandij and senior PMM Parker Ennis explain the impact of low code app development tools on GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681170/Blog/Hero%20Images/lowcodenocode.jpg","https://about.gitlab.com/blog/low-code-no-code","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"The role low code app development tools may play at GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Valerie Silverthorne\"}],\n        \"datePublished\": \"2020-03-26\",\n      }",{"title":2515,"description":2516,"authors":2521,"heroImage":2517,"date":2522,"body":2523,"category":848,"tags":2524},[1097],"2020-03-26","\n\nIf software is eating the world and there is a [worldwide shortage of software developers](https://www.icims.com/hiring-insights/for-employers/how-to-win-tech-talent), how can companies stay in the game?\n\nOne answer: The [citizen developer](https://www.forbes.com/sites/johneverhard/2019/01/22/the-pros-and-cons-of-citizen-development/#2376328184fd). Empowered by technology, the so-called citizen developer is able to create code without a formal developer background. Two types of tools allow this: Low code app development tools let a citizen developer build apps using only the most rudimentary of coding skills, while no-code solutions are generally WYSIWYG choices that allow someone to create an app, or part of an app, using pre-assembled pieces of code.\n\nLow code and no code tools have been available for a long time – 4GL, computer-assisted software engineering (CASE) and rapid application development (RAD) tools were all precursors – and according to [IDC](http://www.idc.com), today their use is on the rise. In fact out of 23.4 million developers worldwide in 2019, IDC said 1.76 million of them are low coders, representing 7.5% of the total. There were also 810,000 no-code developers worldwide last year, according to IDC’s Market Perspective: Low-Code and No-Code Developer Census, 2019: Growth Begins in Earnest report.\n\nGiven the growing popularity, it’s not surprising the GitLab development team is taking a hard look at [how to leverage and/or integrate low code functionality](https://gitlab.com/groups/gitlab-org/-/epics/2353#note_263252013) into our tool. Recently CEO [Sid Sijbrandij](/company/team/#sytses) sat down with senior product marketing manager [Parker Ennis](/company/team/#parker_ennis) to talk about the role low code solutions can and should play at Gitlab.\n\n“So what I like about low code is the potential to have more people programming,” Sid tells Parker. And Parker is definitely enthusiastic as well. “What interests me in low code is providing the ease of getting into something like coding,” he explains. “There’s a high barrier of entry when it comes to programming. I found that first hand when I was an undergrad trying to learn Ruby on Rails. It was an intimidating, tough experience but for other people it’s something innate inside them. One of the really cool benefits of low code is you can have people starting to learn how to code without the intimidating factor.”\n\nAlso there’s no question there are simply not enough people with coding skills to fill the demand for software, Parker says, pointing to data from industry analyst and blogger [James Governor](https://redmonk.com/jgovernor/author/jgovernor) who says the world will need around 100 million developers in 10 years. Remember, we’re at just one quarter of that today.\n\nParker is particularly excited about the potential of low code tools to get kids interested in programming at an early age. “How can we educate the next generation in how to solve the problems we are creating today?” he asks. “Low code is a viable option.”\n\nMeanwhile today at GitLab we’re looking at ways we can make it easier to integrate low code tools into our workflow, Parker says. We might go further than that if a viable open source low-code tool arrives on the market.\n\n**Learn more about app develompent tools:**\n\n[Unify your logs and metrics](/blog/unifylogsmetrics/)\n\n[Get the most out of performance testing](/blog/how-were-building-up-performance-testing-of-gitlab/)\n\n[Up your merge train game](/blog/all-aboard-merge-trains/)\n\nCover image by [Anas Alshanti](https://unsplash.com/@otenteko) on [Unsplash](https://www.unsplash.com)\n{: .note}\n",[9,1161,872],{"slug":2526,"featured":6,"template":696},"low-code-no-code","content:en-us:blog:low-code-no-code.yml","Low Code No Code","en-us/blog/low-code-no-code.yml","en-us/blog/low-code-no-code",{"_path":2532,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2533,"content":2539,"config":2545,"_id":2547,"_type":13,"title":2548,"_source":15,"_file":2549,"_stem":2550,"_extension":18},"/en-us/blog/machine-learning-and-devsecops",{"title":2534,"description":2535,"ogTitle":2534,"ogDescription":2535,"noIndex":6,"ogImage":2536,"ogUrl":2537,"ogSiteName":683,"ogType":684,"canonicalUrls":2537,"schema":2538},"Machine learning and DevSecOps: Inside the OctoML/GitLab integration","MLOps and DevSecOps teams can unify their workflows and gain automation and cost efficiencies.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666915/Blog/Hero%20Images/autodevops.jpg","https://about.gitlab.com/blog/machine-learning-and-devsecops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Machine learning and DevSecOps: Inside the OctoML/GitLab integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sameer Farooqui, OctoML\"}],\n        \"datePublished\": \"2023-02-23\",\n      }",{"title":2534,"description":2535,"authors":2540,"heroImage":2536,"date":2542,"body":2543,"category":1244,"tags":2544},[2541],"Sameer Farooqui, OctoML","2023-02-23","\n\nMachine learning can be a powerful tool in software development, but not if it has to live apart from existing engineering workflows. DevSecOps teams, including MLOps, can now integrate [OctoML CLI](https://gitlab.com/octoml/octoml-public/octoml-cli-tutorials) into [GitLab’s CI/CD Pipelines](https://docs.gitlab.com/ee/ci/pipelines/) to unify workflows and leverage existing deployment and monitoring infrastructure. This integration makes it easier to catch bugs and model performance degradations early in the ML development cycle. \n\nThe OctoML Platform is a machine learning model optimization and deployment service powered by octoml.ai. [Machine learning has grown in popularity](/blog/top-10-ways-machine-learning-may-help-devops/) in DevSecOps, along with AI, because of its ability to learn and model how to perform complex tasks as a human would and then automate those tasks.\n\n## How does CI/CD apply to machine learning?\n\nOnce a machine learning model has been successfully deployed, it can get stale over time and its accuracy could degrade, a situation called “data drift”. Data drift causes newer inferencing data to drift away from the data used to train the model. In the retail industry, this can happen because of seasonality, as an example.\n\nProduction models must be regularly refreshed by retraining their weights with the latest data. Applying CI/CD concepts borrowed from software engineering, the OctoML CI integration makes the deployment process for trained/re-trained models automated and repeatable.\n\n## How OctoML CLI and GitLab work together\n\nNew commits to your inference code repository can run [OctoML CLI](https://github.com/octoml/octoml-cli-tutorials#readme) in your GitLab pipeline to automatically optimize machine learning models for lowest cost per inference and lowest latency, and then deploy the optimized model to your cloud registry. For customers looking for more granular packaging formats that integrate with existing containerization systems, OctoML offers [Python wheel packaging](https://app.octoml.ai/docs/deploy.html#python-wheel-deployment) and will soon offer YAML configuration files. To reduce model latency and serving costs, OctoML searches through multiple acceleration engines such as Apache TVM, ONNX Runtime, and TensorRT and then suggests the ideal CPU or GPU hardware type on AWS, Azure, or GCP.\n\n## Choice in cloud deployment targets\n\nUsing OctoML CLI, developers can send any trained model to OctoML’s SaaS platform for cost efficiency and cloud hardware benchmarking. By adapting and optimizing the trained model to leverage hardware intrinsics in CPU and GPUs, OctoML makes inferences run faster in production, thus saving users on cost per inference and improving the user experience of ML applications.\n\n![Cloud workflow](https://about.gitlab.com/images/blogimages/octomlintegration/image1.png){: .shadow}\n\nThe cloud workflow is designed for enterprise and production deployments. Here’s how it works:\n\n* The initial push from a developer to the GitLab repository launches a local, shared, or remote runner.\n* The runner will send the updated, trained model first to OctoML’s platform for acceleration and hardware adaptation.\n* Then, the pipeline pushes the accelerated model container to the GitLab Container Registry.\n* Finally, it deploys the container to a managed Kubernetes service in any of the major cloud providers.\n\nModels deployed via the accelerated cloud workflow not only provide end users the lowest latency user experience but also save the organization compute costs at inference time, which can amount to \\[90% of a production machine learning application’s compute costs](https://aws.amazon.com/blogs/machine-learning/reduce-ml-inference-costs-on-amazon-sagemaker-with-hardware-and-software-acceleration/).\n\n## Four required stages for every pipeline\n\nEach pipeline has four stages: setup, package, deploy, and test. Here’s the logical flow:\n\n![Logical flow](https://about.gitlab.com/images/blogimages/octomlintegration/image2.png){: .shadow}\n\n1. common:setup - produces OctoML CLI binary artifact and passes it on to local:package\n2. cloud:package - packages the incoming model into a Docker tarball using the OctoML CLI binary and passes the tarball to the next stage\n3. cloud:deploy - builds a Docker image from the Tarball and deploys the docker container to a remote registry (in our example, we deploy it to AWS via GitLab Container Registry using Flux, but there can be other mechanisms)\n4. cloud:test - run the user-provided test script\n\nWhen a cloud pipeline is executed, the GitLab Pipeline UI will display a corresponding workflow:\n\n![GitLab Pipeline UI](https://about.gitlab.com/images/blogimages/octomlintegration/image3.png){: .shadow}\n\nSimilar to any other GitLab CI/CD job, our [example repository](https://gitlab.com/octoml/octoml-public/octoml-cli-tutorials) has YAML files that define how each stage will execute. You can easily clone the repository or code and adapt it to your custom model and inference code:\n\n![example repository](https://about.gitlab.com/images/blogimages/octomlintegration/image4.png){: .shadow}\n\nIn addition to the stage YAML files, OctoML CLI also has its own `octoml.yaml` configuration, which defines the path to your model, hardware type the model should be accelerated for, and the model’s input shapes:\n\n![octoml.yaml config](https://about.gitlab.com/images/blogimages/octomlintegration/image5.png){: .shadow}\n\n## Get started with OctoML CLI and GitLab CI/CD\n\nOctoML CLI and GitLab CI/CD unify your software engineering and machine learning pipelines by allowing ML models to be deployed using the same infrastructure and processes you’re currently using for software applications. Further, our integration makes it seamless to start with local model deployments to test end-to-end inference and move to accelerated cloud deployments with minimal changes to your workflow.\n\n**We’ve [published tutorials](https://gitlab.com/octoml/octoml-public/octoml-cli-tutorials) with an NLP (Bertsquad) and Vision (YOLOv5) model for end-to-end examples. So, to get started, download the [OctoML CLI](https://try.octoml.ai/cli/) and [request an acceleration consultation](https://try.octoml.ai/cli/#lp-pom-block-105) to receive a token to OctoML’s SaaS platform.**\n",[9,934,976],{"slug":2546,"featured":6,"template":696},"machine-learning-and-devsecops","content:en-us:blog:machine-learning-and-devsecops.yml","Machine Learning And Devsecops","en-us/blog/machine-learning-and-devsecops.yml","en-us/blog/machine-learning-and-devsecops",{"_path":2552,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2553,"content":2559,"config":2565,"_id":2567,"_type":13,"title":2568,"_source":15,"_file":2569,"_stem":2570,"_extension":18},"/en-us/blog/machine-learning-on-the-gitlab-devops-platform",{"title":2554,"description":2555,"ogTitle":2554,"ogDescription":2555,"noIndex":6,"ogImage":2556,"ogUrl":2557,"ogSiteName":683,"ogType":684,"canonicalUrls":2557,"schema":2558},"How Comet can streamline machine learning on The GitLab DevOps Platform","Here's a step-by-step look at how to bring ML into software development using Comet on GitLab's DevOps Platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669991/Blog/Hero%20Images/ways-to-encourage-collaboration.jpg","https://about.gitlab.com/blog/machine-learning-on-the-gitlab-devops-platform","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How Comet can streamline machine learning on The GitLab DevOps Platform\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"William Arias\"}],\n        \"datePublished\": \"2021-11-08\",\n      }",{"title":2554,"description":2555,"authors":2560,"heroImage":2556,"date":2562,"body":2563,"category":739,"tags":2564},[2561],"William Arias","2021-11-08","\n\nBuilding machine learning-powered applications comes with numerous challenges. When we talk about these challenges, there is a tendency to overly focus on problems related to the quality of a model’s predictions—things like data drift, changes in model architectures, or inference latency. \n\nWhile these are all problems worthy of deep consideration, an often overlooked challenge in [ML development](/topics/devops/the-role-of-ai-in-devops/) is the process of integrating a model into an existing software application.  \n\nIf you’re tasked with adding an ML feature to a product, you will almost certainly run into an existing codebase that must play nicely with your model. This is, to put it mildly, not an easy task. \n\nML is a highly iterative discipline. Teams often make many changes to their codebase and pipelines in the process of developing a model. Coupling an ML codebase to an application’s dependencies, unit tests, and CI/CD pipelines will significantly reduce the velocity with which ML teams can deliver on a solution, since each change would require running these downstream dependencies before a merge can be approved.  \n\nIn this post, we’re going to demonstrate how you can use [Comet](https://www.comet.ml/site/) with [GitLab’s DevOps platform](/solutions/devops-platform/) to streamline the workflow for your ML and software engineering teams, allowing them to collaborate without getting in each other's way.      \n\n## The challenge for ML teams working with application teams\n\nLet’s say your team is working on improving a feature engineering pipeline. You will likely have to test many combinations of features with some baseline model for the task to see which combinations make an impact on model performance.     \n \nIt is hard to know beforehand which features might be significant, so having to run multiple experiments is inevitable. If your ML code is a part of your application codebase, this would mean having to run your application’s CI/CD pipeline for every feature combination you might be trying. \n\nThis will certainly frustrate your Engineering and DevOps teams, since you would be unnecessarily tying up system resources, given that software engineering teams do not need to run their pipelines with the same frequency as ML teams do.  \n\nThe other issue is that despite having to run numerous experiments, only a single set of outputs from these experiments will make it to your production application. Therefore, the rest of the assets produced through these experiments are not relevant to your application code.     \n\nKeeping these two codebases separated will make life a lot easier for everyone – but it also introduces the problem of syncing the latest model between two codebases.     \n\n## Use The GitLab DevOps Platform and Comet for your model development process\n\nWith The GitLab DevOps platform and Comet, we can keep the workflows between ML and engineering teams separated, while enabling cross-team collaboration by preserving the visibility and auditability of the entire model development process across teams.     \n\nWe will use two separate projects to demonstrate this process. One project will contain our application code for a handwritten digit recognizer, while the other will contain all the code relevant to training and evaluating our model.  \n\nWe will adopt a process where discussions, code reviews, and model performance metrics get automatically published and tracked within The GitLab DevOps Platform, increasing the velocity and opportunity for collaboration between data scientists and software engineers for machine learning workflows.\n\n## Project setup\n\nOur project consists of two projects: [comet-model-trainer](https://gitlab.com/tech-marketing/devops-platform/comet-model-trainer) and [ml-ui](https://gitlab.com/tech-marketing/devops-platform/canara-review-apps-testing). \n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/cometmodeltrainer.png){: .shadow}\n\nThe **comet-model-trainer** repository contains scripts to train and evaluate a model on the MNIST dataset. We have set up The GitLab DevOps Platform in a way that runs the training and evaluation Pipeline whenever a new merge request is opened with the necessary changes.\n\nThe **ml-ui** repository contains the necessary code to build the frontend of our ML application.\n\nSince the code is integrated with Comet, your ML team can easily track the source code, hyperparameters, metrics, and other details related to the development of the model.  \n\nOnce the training and evaluation steps are completed, we can use Comet to fetch summary metrics from the project as well as metrics from the Candidate model and display them within the merge request; This will allow the ML team to easily review the changes to the model. \n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/buildmodelgraph.png){: .shadow}\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/summarymetrics.png){: .shadow}\n\nIn our case, the average accuracy of the models in the project is 97%. Our Candidate model achieved an accuracy of 99%, so it looks like it is a good fit to promote to production. The metrics displayed here are completely configurable and can be changed as necessary.        \n\nWhen the merge request is approved, the deployment pipeline is triggered and the model is pushed to Comet’s Model Registry. The Model Registry versions each model and links it back to the Comet Experiment that produced it.  \n![Alt text for your image](https://about.gitlab.com/images/blogimages/OpenComet_SparkVideo.gif){: .shadow}    \n\nOnce the model is pushed to the Model Registry, it is available to the application code. When the application team wishes to deploy this new version of the model to their app, they simply have to trigger their specific deployment pipeline.     \n\n## Running the pipeline\n\n### Pipeline outline\n\nWe will run the process outlined below every time a team member creates a merge request to change code in the `build-neural-network`script:\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/modelapprove.png){: .shadow}\n\nNow, let’s take a look at the yaml config used to define our CI/CD pipelines depicted in the previous diagram:\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/workflowsbranch.png){: .shadow}\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/script.png){: .shadow}\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/registermodel.png){: .shadow}\n\nLet's break down the CI/CD pipeline by describing the gitlab-ci.yml file so you can use it and customize it to your needs.\n\nWe start by instructing our GitLab runners to utilize Python:3.8 to run the jobs specified in the pipeline: \n\n`Image: python:3.8`\n\nThen, we define the job where we want to build and train the neural network:\n\n`Build-neural-network`\n\n### Build-neural-network \n\nIn this step, we start by creating a folder where we will store the artifacts generated by this job, install dependencies using the requirements.txt file, and finally  execute the corresponding Python script that will be in charge of training the neural network. The training runs in the GitLab runner using the Python image defined above, along with its dependencies.\n\nOnce the `build-neural-network` job has finalized successfully, we move to the next job: `write-report-mr`\n\nHere, we use another image created by DVC that will allow us to publish a report right in the merge request opened by the contributor who changed code in the neural network script. In this way, we’ve brought software development workflows to the development of ML applications. With the report provided by this job, code and model review can be executed within the merge request view, enabling teams to collaborate not only around the code but also the model performance.\n\nFrom the merge request page, we get access to loss curves and other relevant performance metrics from the model we are training, along with a link to the Comet Experiment UI, where richer details are provided to evaluate the model performance. These details include interactive charts for model metrics, the model hyperparameters, and Confusion Matrices of the test set performance, to name a few. \n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/manualDeploy_SparkVideo.gif){: .shadow}\n\nWhen the team is done with the code and model review,  the merge request gets approved, and the script that generated the model is merged into the main codebase, along with its respective commit and the CI pipeline associated to it. This takes us to the next job: \n\n### Register-model\n\nThis job uses an integration between GitLab and Comet to upload the reviewed and accepted version of the model to the Comet Model Registry. If you recall, the Model Registry is where models intended for production can be logged and versioned. In order to run the commands that will register the model, we need to set up these variables: \n\n- COMET_WORKSPACE\n- COMET_PROJECT_NAME \n \nIn order to do that, follow the steps described [here](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-an-instance).\n\nIt is worth noting that the `register-model` job only runs when the merge request gets reviewed and approved, and this behavior is obtained by setting `only: main` at the end of the job.\n\nFinally, we decide to let a team member have final control of the deployment so therefore we define a manual job:\n`Deploy-ml-ui`\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/deployuiml.png){: .shadow}\n\nWhen triggered, this job will import the model from Comet’s Model Registry and automatically create the necessary containers to build the user interface and deploy to a Kubernetes cluster. \n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/downstream.png){: .shadow}\n\nThis job triggers a downstream pipeline, which means that the UI for this MNIST application resides in a different project. This keeps the codebase for the UI and model training separated but integrated and connected at the moment of deploying the model to a production environment.\n\n![Alt text for your image](https://about.gitlab.com/images/blogimages/multipipeline_SparkVideo.gif){: .shadow}\n\n## Key takeaways\n\nIn this post, we addressed some of the challenges faced by ML and software teams when it comes to collaborating on delivering ML-powered applications. Some of these challenges include:\n\n* The discrepancy in the frequency with which each of these teams need to iterate on their codebases and CI/CD pipelines.\n\n* The fact that only a single set of experiment assets from an ML experimentation pipeline is relevant to the application.\n\n* The challenge of syncing a model or other experiment assets across independent codebases.   \n\nUsing The GitLab DevOps Platform and Comet, we can start bridging the gap between ML and software engineering teams over the course of a project. \n\nBy having model performance metrics adopted into software development workflows like the one we saw in the issue and merge request, we can keep track of the code changes, discussions, experiments, and models created in the process. All the operations executed by the team are recorded, can be audited, are end-to end-traceable, and (most importantly) reproducible. \n\nWatch a demo of this process:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/W_DsNl5aAVk\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n_About Comet:_\nComet is an MLOps Platform that is designed to help data scientists and teams build better models faster! Comet provides tooling to Track, Explain, Manage, and Monitor your models in a single place! \n\nLearn more about Comet [here](https://www.comet.ml/site/) and get started for free!\n\n\n\n",[851,1408,9,934],{"slug":2566,"featured":6,"template":696},"machine-learning-on-the-gitlab-devops-platform","content:en-us:blog:machine-learning-on-the-gitlab-devops-platform.yml","Machine Learning On The Gitlab Devops Platform","en-us/blog/machine-learning-on-the-gitlab-devops-platform.yml","en-us/blog/machine-learning-on-the-gitlab-devops-platform",{"_path":2572,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2573,"content":2579,"config":2585,"_id":2587,"_type":13,"title":2588,"_source":15,"_file":2589,"_stem":2590,"_extension":18},"/en-us/blog/managing-gitlab-resources-with-pulumi",{"title":2574,"description":2575,"ogTitle":2574,"ogDescription":2575,"noIndex":6,"ogImage":2576,"ogUrl":2577,"ogSiteName":683,"ogType":684,"canonicalUrls":2577,"schema":2578},"Managing GitLab resources with Pulumi","Learn how Pulumi's infrastructure-as-code tool helps streamline the automation of GitLab CI/CD workflows.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683430/Blog/Hero%20Images/AdobeStock_293854129__1_.jpg","https://about.gitlab.com/blog/managing-gitlab-resources-with-pulumi","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Managing GitLab resources with Pulumi\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Josh Kodroff, Pulumi\"}],\n        \"datePublished\": \"2024-01-10\",\n      }",{"title":2574,"description":2575,"authors":2580,"heroImage":2576,"date":2582,"body":2583,"category":1244,"tags":2584},[2581],"Josh Kodroff, Pulumi","2024-01-10","In the ever-evolving landscape of DevOps, platform engineers are\nincreasingly seeking efficient and flexible tools to manage their GitLab\nresources, particularly for orchestrating continuous integration/continuous\ndelivery (CI/CD) pipelines.\n[Pulumi](https://pulumi.com?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\noffers a unique approach to infrastructure as code (IaC) by allowing\nengineers to use familiar programming languages such as TypeScript, Python,\nGo, and others. This approach streamlines the automation of GitLab CI/CD\nworkflows. Pulumi's declarative syntax, combined with its ability to treat\ninfrastructure as software, facilitates version control, collaboration, and\nreproducibility, aligning seamlessly with the GitLab philosophy.\n\n\nLet's explore the power of using Pulumi and GitLab.\n\n\n## What is Pulumi?\n\n\nPulumi is an IaC tool that allows you to manage resources in more than 150\nsupported cloud or SaaS products (including AWS and GitLab, which we will be\ndemonstrating in this post). You can express your infrastructure with Pulumi\nusing popular general-purpose programming languages like TypeScript, Python,\nand Go.\n\n\nPulumi is declarative (just like other popular IaC tools you may be familiar\nwith), which means that you only need to describe the desired end state of\nyour resources and Pulumi will figure out the order of create, read, update,\nand delete (CRUD) operations to get from your current state to your desired\nstate.\n\n\nIt might seem strange at first to use a general-purpose programming language\nto express your infrastructure's desired state if you're used to tools like\nCloudFormation or Terraform, but there are considerable advantages to\nPulumi's approach, including the following:\n\n- **Familiar tooling.** You don't need any special tooling to use Pulumi.\nCode completion will work as expected in your favorite editor or IDE without\nany additional plugins. You can share Pulumi code using familiar packaging\ntools like npm, PyPI, etc.\n\n- **Familiar syntax.** Unlike with DSL-based IaC tools, you don't need to\nlearn special ways of indexing an array element, or creating loops or\nconditionals - you can just use the normal syntax of a language you already\nknow.\n\n\nThe Pulumi product has an open source component, which includes the Pulumi\ncommand line and its ecosystem of providers, which provide the integration\nbetween Pulumi and the cloud and SaaS providers it supports. Pulumi also\noffers a free (for individual use) and paid (for teams and organizations)\nSaaS service called Pulumi Cloud, which provides state file and secrets\nmanagement, among many other useful features. It’s a widely-supported\nopen-source IaC tool.\n\n\n## Initializing the project\n\n\nTo complete this example you'll need:\n\n\n1. [A Pulumi Cloud\naccount](https://app.pulumi.com?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources).\nPulumi Cloud is free for individual use forever and we'll never ask for your\ncredit card. Pulumi Cloud will manage your Pulumi state file and handle any\nsecrets encryption/decryption. Because it's free for individual use (no\ncredit card required), we strongly recommend that you use Pulumi Cloud as\nyour backend when learning how to use Pulumi.\n\n2. A GitLab account, group, and a GitLab token set to the `GITLAB_TOKEN`\nenvironment variable.\n\n3. An AWS account and credentials with permissions to deploy identity and\naccess management (IAM) resources. For details on how to configure AWS\ncredentials on your system for use with Pulumi, see [AWS Classic:\nInstallation and\nConfiguration](https://www.pulumi.com/registry/packages/aws/installation-configuration/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources).\n\n\nThis example will use two providers from the [Pulumi\nRegistry](https://www.pulumi.com/registry/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources):\n\n\n1. The [GitLab\nProvider](https://www.pulumi.com/registry/packages/gitlab/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\nwill be used to manage resources like Projects, ProjectFiles (to initialize\nour project repository), ProjectHooks (for the integration with Pulumi\nCloud), and ProjectVariables (to hold configuration for our CI/CD\npipelines).\n\n2. The [AWS Classic\nProvider](https://www.pulumi.com/registry/packages/aws/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\nwill be used to manage AWS resources to create OpenID Connect (OIDC)\nconnectivity between AWS and GitLab.\n\n\nYou can initialize your Pulumi project by changing into a new, empty\ndirectory, running the following command, and accepting all the default\nvalues for any subsequent prompts:\n\n\n```bash\n\npulumi new typescript\n\n```\n\n\nThis will bootstrap an empty Pulumi program. Now you can import the provider\nSDKs for the providers you'll need:\n\n\n```bash\n\nnpm i @pulumi/aws @pulumi/gitlab\n\n```\n\n\nYour `index.ts` file is the entry point into your Pulumi program (just as\nyou would expect in any other Node.js program) and will be the file to which\nyou will add your resources. Add the following imports to the top of\n`index.ts`:\n\n\n```typescript\n\nimport * as gitlab from \"@pulumi/gitlab\";\n\nimport * as aws from \"@pulumi/aws\";\n\n```\n\n\nNow you are ready to add some resources!\n\n\n## Adding your first resources\n\n\nFirst, let's define a variable that will hold the audience claim in our OIDC\nJWT token. Add the following code to `index.ts`:\n\n\n```typescript\n\nconst audience = \"gitlab.com\";\n\n```\n\n\nThe above code assume you're using the GitLab SaaS (\u003Chttps://gitlab.com>) If\nyou are using a private GitLab install, your value should be the domain of\nyour GitLab install, e.g. `gitlab.example.com`.\n\n\nThen, you'll use a [Pulumi\nfunction](https://www.pulumi.com/docs/concepts/resources/functions/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\nto grab an existing GitLab group by name and create a new public GitLab\nproject in your GitLab group:\n\n\n```typescript\n\nconst group = gitlab.getGroup({\n  fullPath: \"my-gitlab-group\", // Replace the value with the name of your GL group\n});\n\n\nconst project = new gitlab.Project(\"pulumi-gitlab-demo\", {\n  visibilityLevel: \"public\",\n  defaultBranch: \"main\",\n  namespaceId: group.then(g => parseInt(g.id)),\n  archiveOnDestroy: false // Be sure to set this to `true` for any non-demo repos you manage with Pulumi!\n});\n\n```\n\n\n## Creating OIDC resources\n\n\nTo allow GitLab CI/CD to request and be granted temporary AWS credentials,\nyou'll need to create an OIDC provider in AWS that contains the thumbprint\nof GitLab's certificate, and then create an AWS role that GitLab is allowed\nto assume.\n\n\nYou'll scope the assume role policy so that the role can be only be assumed\nby the GitLab project you declared earlier. The role that GitLab CI/CD\nassumed will have full administrator access so that Pulumi can create and\nmanage any resource within AWS. (Note that it is possible to grant less than\n`FullAdministrator` access to Pulumi, but `FullAdministrator` is often\npractically required, e.g. where IAM resources, like roles, need to be\ncreated. Role creation requires `FullAdministrator`. This consideration also\napplies to IaC tools like Terraform.)\n\n\nAdd the following code to `index.ts`:\n\n\n```typescript\n\nconst GITLAB_OIDC_PROVIDER_THUMBPRINT =\n\"b3dd7606d2b5a8b4a13771dbecc9ee1cecafa38a\";\n\n\nconst gitlabOidcProvider = new\naws.iam.OpenIdConnectProvider(\"gitlab-oidc-provider\", {\n  clientIdLists: [`https://${audience}`],\n  url: `https://${audience}`,\n  thumbprintLists: [GITLAB_OIDC_PROVIDER_THUMBPRINT],\n}, {\n  deleteBeforeReplace: true, // URLs are unique identifiers and cannot be auto-named, so we have to delete before replace.\n});\n\n\nconst gitlabAdminRole = new aws.iam.Role(\"gitlabAdminRole\", {\n  assumeRolePolicy: {\n    Version: \"2012-10-17\",\n    Statement: [\n      {\n        Effect: \"Allow\",\n        Principal: {\n          Federated: gitlabOidcProvider.arn,\n        },\n        Action: \"sts:AssumeRoleWithWebIdentity\",\n        Condition: {\n          StringLike: {\n            // Note: Square brackets around the key are what allow us to use a\n            // templated string. See:\n            // https://stackoverflow.com/questions/59791960/how-to-use-template-literal-as-key-inside-object-literal\n            [`${audience}:sub`]: pulumi.interpolate`project_path:${project.pathWithNamespace}:ref_type:branch:ref:*`\n          },\n        },\n      },\n    ],\n  },\n});\n\n\nnew aws.iam.RolePolicyAttachment(\"gitlabAdminRolePolicy\", {\n  policyArn: \"arn:aws:iam::aws:policy/AdministratorAccess\",\n  role: gitlabAdminRole.name,\n});\n\n```\n\n\nA few things to be aware of regarding the thumbprint:\n\n\n1. If you are self-hosting GitLab, you'll need to obtain the thumbprint from\nyour private GitLab installation.\n\n2. If you're using GitLab SaaS, it's possible GitLab's OIDC certificate may\nhave been rotated by the time you are reading this.\n\n\nIn either case, you can obtain the correct/latest thumbprint value by\nfollowing AWS' instructions contained in [Obtaining the thumbprint for an\nOpenID Connect Identity\nProvider](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html)\nin the AWS docs.\n\n\nYou'll also need to add the role's ARN as a project variable so that the\nCI/CD process can make a request to assume the role:\n\n\n```typescript\n\nnew gitlab.ProjectVariable(\"role-arn\", {\n  project: project.id,\n  key: \"ROLE_ARN\",\n  value: gitlabAdminRole.arn,\n});\n\n```\n\n\n## Project hook (optional)\n\n\nPulumi features an integration with GitLab via a webhook that will post the\noutput of the `pulumi preview` directly to a merge request as a comment. For\nthe webhook to work, you must have a Pulumi organization set up with GitLab\nas its SSO source. If you don't have a Pulumi organization and would like to\ntry the integration, you can [sign up for a free\ntrial](https://app.pulumi.com/signup?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\norganization. The trial lasts 14 days, will give you access to all of\nPulumi's paid features, and does not require a credit card. For full details\non the integration, see [Pulumi CI/CD & GitLab\nintegration](https://www.pulumi.com/docs/using-pulumi/continuous-delivery/gitlab-app/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources).\n\n\nTo set up the webhook, add the following to your `index.ts` file:\n\n\n```typescript\n\nnew gitlab.ProjectHook(\"project-hook\", {\n  project: project.id,\n  url: \"https://api.pulumi.com/workflow/gitlab\",\n  mergeRequestsEvents: true,\n  enableSslVerification: true,\n  token: process.env[\"PULUMI_ACCESS_TOKEN\"]!,\n  pushEvents: false,\n});\n\n```\n\n\nNote that the above resource assumes that your Pulumi access token is stored\nas an environment variable. You may want to instead store the token in your\nstack configuration file. To do this, run the following command:\n\n\n```bash\n\npulumi config set --secret pulumiAccessToken ${PULUMI_ACCESS_TOKEN}\n\n```\n\n\nThis will store the encrypted value in your Pulumi stack configuration file\n(`Pulumi.dev.yaml`). Because the value is encrypted, you can safely commit\nyour stack configuration file to git. You can access its value in your\nPulumi program like this:\n\n\n```typescript\n\nconst config = new pulumi.Config();\n\nconst pulumiAccessToken = config.requireSecret(\"pulumiAccessToken\");\n\n```\n\n\nFor more details on secrets handling in Pulumi, see\n[Secrets](https://www.pulumi.com/docs/concepts/secrets/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\nin the Pulumi docs.\n\n\n## Creating a repository and adding repository files\n\n\nYou'll need to create a git repository (a GitLab project) and add some files\nto it that will control the CI/CD process. First, create some files that\nyou'll include in your GitLab repo:\n\n\n```bash\n\nmkdir -p repository-files/scripts\n\ntouch repository-files/.gitlab-ci.yml\nrepository-files/scripts/{aws-auth.sh,pulumi-preview.sh,pulumi-up.sh}\n\nchmod +x\nrepository-files/scripts/{aws-auth.sh,pulumi-preview.sh,pulumi-up.sh}\n\n```\n\n\nNext, you'll need a GitLab CI/CD YAML file to describe the pipeline: which\ncontainer image it should be run in and what the steps of the pipeline are.\nPlace the following code into `repository-files/.gitlab-ci.yml`:\n\n\n```yaml\n\ndefault:\n  image:\n    name: \"pulumi/pulumi:3.91.1\"\n    entrypoint: [\"\"]\n\nstages:\n  - infrastructure-update\n\npulumi-up:\n  stage: infrastructure-update\n  id_tokens:\n    GITLAB_OIDC_TOKEN:\n      aud: https://gitlab.com\n  before_script:\n    - chmod +x ./scripts/*.sh\n    - ./scripts/aws-auth.sh\n  script:\n    - ./scripts/pulumi-up.sh\n  only:\n    - main # i.e., the name of the default branch\n\npulumi-preview:\n  stage: infrastructure-update\n  id_tokens:\n    GITLAB_OIDC_TOKEN:\n      aud: https://gitlab.com\n  before_script:\n    - chmod +x ./scripts/*.sh\n    - ./scripts/aws-auth.sh\n  script:\n    - ./scripts/pulumi-preview.sh\n  rules:\n    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'\n```\n\n\nThe CI/CD process is fairly simple but illustrates the basic functionality\nneeded for a production-ready pipeline (or these steps may be all your\norganization needs):\n\n\n1. Run the `pulumi preview` command when a merge request is opened or\nupdated. This will help the reviewer gain important context. Because IaC is\nnecessarily stateful (the state file is what enables Pulumi to be a\ndeclarative tool), when reviewing changes reviewers _must have both the code\nchanges and the infrastructure changes to fully understand the impact of\nchanges to the codebase_. This process constitutes continuous integration.\n\n2. Run the `pulumi up` command when code is merged to the default branch\n(called `main` by default). This process constitutes continuous delivery.\n\n\nNote that this example uses the\n[`pulumi/pulumi`](https://hub.docker.com/r/pulumi/pulumi) \"kitchen sink\"\nimage that contains all the runtimes for all the languages Pulumi supports,\nalong with some ancillary tools like the AWS CLI (which you'll need in order\nto use OIDC authentication). While the `pulumi/pulumi` image is convenient,\nit's also quite large (1.41 GB at the time of writing), which makes it\nrelatively slow to initialize. If you're creating production pipelines using\nPulumi, you may want to consider creating your own custom (slimmer) image\nthat has exactly the tools you need installed, perhaps starting with one of\nPulumi's language-specific images, e.g.\n[`pulumi/pulumi-nodejs`](https://hub.docker.com/r/pulumi/pulumi-nodejs).\n\n\nThen you'll need to write the script that authenticates GitLab with AWS via\nOIDC. Place the following code in `repository-files/scripts/aws-auth.sh`:\n\n\n```bash\n\n#!/bin/bash\n\n\nmkdir -p ~/.aws\n\necho \"${GITLAB_OIDC_TOKEN}\" > /tmp/web_identity_token\n\necho -e \"[profile\noidc]\\nrole_arn=${ROLE_ARN}\\nweb_identity_token_file=/tmp/web_identity_token\"\n> ~/.aws/config\n\n\necho \"length of GITLAB_OIDC_TOKEN=${#GITLAB_OIDC_TOKEN}\"\n\necho \"ROLE_ARN=${ROLE_ARN}\"\n\n\nexport AWS_PROFILE=\"oidc\"\n\naws sts get-caller-identity\n\n```\n\n\nFor continuous integration, you'll need a script that will execute the\n`pulumi preview` command when a merge request is opened. Place the following\ncode in `repository-files/scripts/pulumi-preview.sh`:\n\n\n```bash\n\n#!/bin/bash\n\nset -e -x\n\n\nexport PATH=$PATH:$HOME/.pulumi/bin\n\n\nyarn install\n\npulumi login\n\npulumi org set-default $PULUMI_ORG\n\npulumi stack select dev\n\nexport AWS_PROFILE=\"oidc\"\n\npulumi preview\n\n```\n\n\nFor continuous delivery, you'll need a similar script that will execute the\n`pulumi up` command when the Merge Request is merged to the default branch.\nPlace the following code in `repository-files/scripts/pulumi-up.sh`:\n\n\n```bash\n\n#!/bin/bash\n\nset -e -x\n\n\n# Add the pulumi CLI to the PATH\n\nexport PATH=$PATH:$HOME/.pulumi/bin\n\n\nyarn install\n\npulumi login\n\npulumi org set-default $PULUMI_ORG\n\npulumi stack select dev\n\nexport AWS_PROFILE=\"oidc\"\n\npulumi up -y\n\n```\n\n\nFinally, you'll need to add these files to your GitLab Project. Add the\nfollowing code block to your `index.ts` file:\n\n\n```typescript\n\n[\n  \"scripts/aws-auth.sh\",\n  \"scripts/pulumi-preview.sh\",\n  \"scripts/pulumi-up.sh\",\n  \".gitlab-ci.yml\",\n].forEach(file => {\n  const content = fs.readFileSync(`repository-files/${file}`, \"utf-8\");\n\n  new gitlab.RepositoryFile(file, {\n    project: project.id,\n    filePath: file,\n    branch: \"main\",\n    content: content,\n    commitMessage: `Add ${file},`,\n    encoding: \"text\",\n  });\n});\n\n```\n\n\nNote that we're able to take advantage of general-purpose programming\nlanguage features: We are able to create an array and use `forEach()` to\niterate through its members, and we are able to use the `fs.readFileSync()`\nmethod from the Node.js runtime to read the contents of our file. This is\npowerful stuff!\n\n\n## Project variables and stack outputs\n\n\nYou'll need a few more resources to complete the code. Your CI/CD process\nwill need a Pulumi access token in order to authenticate against the Pulumi\nCloud backend which holds your Pulumi state file and handles encryption and\ndecryption of secrets. You will also need to supply name of your Pulumi\norganization. (If you are using Pulumi Cloud as an individual, this is your\nPulumi username.) Add the following to `index.ts`:\n\n\n```typescript\n\nnew gitlab.ProjectVariable(\"pulumi-access-token\", {\n  project: project.id,\n  key: \"PULUMI_ACCESS_TOKEN\",\n  value: process.env[\"PULUMI_ACCESS_TOKEN\"]!,\n  masked: true,\n});\n\n\nnew gitlab.ProjectVariable(\"pulumi-org\", {\n  project: project.id,\n  key: \"PULUMI_ORG\",\n  value: pulumi.getOrganization(),\n});\n\n```\n\n\nFinally, you'll need to add a stack output so that we can run the `git\nclone` command to test out our pipeline. Stack outputs allow you to access\nvalues within your Pulumi program from the command line or from other Pulumi\nprograms. For more information, see [Understanding Stack\nOutputs](https://www.pulumi.com/learn/building-with-pulumi/stack-outputs/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources).\nAdd the following to `index.ts`:\n\n\n```typescript\n\nexport const gitCloneCommand = pulumi.interpolate`git clone\n${project.sshUrlToRepo}`;\n\n```\n\n\n## Deploying your infrastructure and testing the pipeline\n\n\nTo deploy your resources, run the following command:\n\n\n```bash\n\npulumi up\n\n```\n\n\nPulumi will output a list of the resources it intends to create. Select\n`yes` to continue.\n\n\nOnce the command has completed, you can run the following command to get the\ngit clone command for your GitLab repo:\n\n\n```bash\n\npulumi stack output gitCloneCommand\n\n```\n\n\nIn a new, empty directory, run the `git clone` command from your Pulumi\nstack output, e.g.:\n\n\n```bash\n\ngit clone git@gitlab.com:jkodroff/pulumi-gitlab-demo-9de2a3b.git\n\n```\n\n\nChange into the directory and create a new branch:\n\n\n```bash\n\ngit checkout -b my-first-branch\n\n```\n\n\nNow you are ready to create some sample infrastructure in our repository.\nYou can use the `aws-typescript` to quickly generate a simple Pulumi program\nwith AWS resources:\n\n\n```bash\n\npulumi new aws-typescript -y --force\n\n```\n\n\nThe template includes a very simple Pulumi program that you can use to prove\nout the pipeline:\n\n\n```bash\n\n$ cat index.ts\n\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport * as aws from \"@pulumi/aws\";\n\nimport * as awsx from \"@pulumi/awsx\";\n\n\n// Create an AWS resource (S3 Bucket)\n\nconst bucket = new aws.s3.Bucket(\"my-bucket\");\n\n\n// Export the name of the bucket\n\nexport const bucketName = bucket.id;\n\n```\n\n\nCommit your changes and push your branch:\n\n\n```bash\n\ngit add -A\n\ngit commit -m \"My first commit.\"\n\ngit push\n\n```\n\n\nIn the GitLab UI, create a merge request for your branch:\n\n\n![Screenshot demonstrating opening a GitLab Merge\nRequest](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/create-merge-request.jpg)\n\n\nYour merge request pipeline should start running:\n\n\n![Screenshot demonstrating opening a GitLab Merge\nRequest](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/merge-request-running.jpg)\n\n\nOnce the pipeline completes, you should see the output of the `pulumi\npreview` command in the pipeline's logs:\n\n\n![Screenshot of a GitLab pipeline log showing the output of the \"pulumi\npreview\"\ncommand](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/pulumi-preview.jpg)\n\n\nIf you installed the optional webhook, you should see the results of `pulumi\npreview` posted back to the merge request as a comment:\n\n\n![Screenshot of the GitLab Merge Request screen showing the output of the\n\"pulumi preview\" command as a\ncomment](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/merge-request-comment.jpg)\n\n\nOnce the pipeline has completed running, your merge request is ready to\nmerge:\n\n\n![Screenshot of the GitLab Merge Request screen showing a successfully\ncompleted\npipeline](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/merge.jpg)\n\n\nMerging the merge request will trigger the main branch pipeline. (Note that\nin this screen you will see a failed initial run of CI/CD on the main branch\ntoward the bottom of the screen. This is normal and is caused by the initial\nupload of `.gitlab-ci/yml` to the main branch without a Pulumi program being\npresent.)\n\n\n![Screenshot of the GitLab pipelines screen showing a running pipeline along\nwith a passed\npipelines](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/piplines.jpg)\n\n\nIf you click into the main branch pipeline's execution, you can see your\nbucket has been created:\n\n\n![Screenshot of a GitLab pipeline log showing the output of the \"pulumi up\"\ncommand](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683438/Blog/Content%20Images/pulumi-up.jpg)\n\nTo delete the bucket, run the following command in your local clone of the\nrepository:\n\n\n```bash\n\npulumi destroy\n\n```\n\n\nAlternatively, you could create a merge request that removes the bucket from\nyour Pulumi program and run the pipelines again. Because Pulumi is\ndeclarative, removing the bucket from your program will delete it from AWS.\n\n\nFinally, run the `pulumi destroy` command again in the Pulumi program with\nyour OIDC and GitLab resources to finish cleaning up.\n\n\n## Next steps\n\n\nUsing IaC to define pipelines and other GitLab resources can greatly improve\nyour platform team's ability to reliably and quickly manage the resources to\nkeep application teams delivering. With Pulumi, you also get the power and\nexpressiveness of using popular programming languages to express those\nresources!\n\n\nIf you liked what you read here, here are some ways you can enhance your\nCI/CD pipelines:\n\n\n- Add [Pulumi Policy\nPacks](https://www.pulumi.com/docs/using-pulumi/crossguard/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\nto your pipeline: Pulumi policy packs allow you to validate that your\nresources are in compliance with your organization's security and compliance\npolicies. Pulumi's open source [Compliance Ready\nPolicies](https://www.pulumi.com/docs/using-pulumi/crossguard/compliance-ready-policies/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\nare a great place to start on your journey. Compliance Ready Policies\ncontain policy rules for the major cloud providers for popular compliance\nframeworks like PCI-DSS and ISO27001, and policy packs are easy to integrate\ninto your pipelines.\n\n- Check out [Pulumi ESC (Environments, Secrets, and\nConfiguration)](https://www.pulumi.com/product/esc/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources):\nPulumi ESC makes it easy to share static secrets like GitLab tokens and can\neven [generate dynamic secrets like AWS OIDC\ncredentials](https://www.pulumi.com/blog/esc-env-run-aws/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources).\nESC becomes especially useful when using Pulumi at scale because it reduces\nthe duplication of configuration and secrets that are used by multiple\nPulumi programs. You don't even have to use Pulumi IaC to benefit from\nPulumi ESC - [Pulumi ESC's command\nline](https://www.pulumi.com/docs/esc-cli/commands/?utm_source=GitLab&utm_medium=Referral&utm_campaign=Managing-GitLab-Resources)\ncan be used with any CLI tool like the AWS CLI.\n",[108,976,281,9],{"slug":2586,"featured":6,"template":696},"managing-gitlab-resources-with-pulumi","content:en-us:blog:managing-gitlab-resources-with-pulumi.yml","Managing Gitlab Resources With Pulumi","en-us/blog/managing-gitlab-resources-with-pulumi.yml","en-us/blog/managing-gitlab-resources-with-pulumi",{"_path":2592,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2593,"content":2599,"config":2605,"_id":2607,"_type":13,"title":2608,"_source":15,"_file":2609,"_stem":2610,"_extension":18},"/en-us/blog/marker-io-gitlab-integration",{"title":2594,"description":2595,"ogTitle":2594,"ogDescription":2595,"noIndex":6,"ogImage":2596,"ogUrl":2597,"ogSiteName":683,"ogType":684,"canonicalUrls":2597,"schema":2598},"How to radically simplify bug reporting in GitLab","Marie Hargitt from Marker.io shares how product teams can empower colleagues to report actionable issues in GitLab, without driving developers crazy.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679899/Blog/Hero%20Images/gitlab-marker-io.png","https://about.gitlab.com/blog/marker-io-gitlab-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to radically simplify bug reporting in GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Marie Hargitt\"}],\n        \"datePublished\": \"2019-01-09\",\n      }",{"title":2594,"description":2595,"authors":2600,"heroImage":2596,"date":2602,"body":2603,"category":739,"tags":2604},[2601],"Marie Hargitt","2019-01-09","\n\nIf you’re like us, you’re constantly pushing out new features and improvements to your product, but with those updates and changes comes the inevitable risk of bugs. The best way to find and fix those bugs are your internal reporters and developers, but getting the whole team to report bugs into GitLab can be hard.\n\nWhether it’s your copywriters on the lookout for wonky content, your QA testers that find a broken form, designers that spot a font size five times too big, or your customer support team receiving word that a billing issue is blocking customers from paying – reporters can take forever to send actionable feedback to developers, who in turn don’t always get the information they need to smash those bugs.\n\n## What a bug-reporting workflow usually looks like ...\n\n### ... for reporters\n\nBecause reporters aren’t always super tech-savvy, it can be tricky for them to share reports that are helpful for your developers. The process is long, complicated, and tracking down the crucial technical information isn’t always easy.\n\nIn most teams, reporting bugs into GitLab looks like this:\n1. Find the bug.\n1. Open screenshot tool, capture bug.\n1. Open software to annotate screenshot, add comments.\n1. Open and log into GitLab.\n1. Select the correct project.\n1. Create new issue.\n1. Document the bug. (How exactly do I do this!?)\n1. Add technical information. (What is this even?)\n1. Attach screenshots.\n1. And then finally: submit report.\n\nThat’s a whopping 10 steps to report even the smallest bugs.\n\nAnd we didn’t even mention the super-fun scavenger hunt reporters have to go on to identify all of the environmental data developers need to even start thinking about fixing the bugs.\n\n### ... for developers\n\nDevelopers get feedback flying at them in all forms – emails, phone calls, sticky notes and screenshots.\n\nThey’re ready to gouge their eyes out because they can’t reproduce the reported bugs, because they’re not receiving actionable feedback from the get-go, and they don’t have time to investigate all the bug reports they receive.\n\n## So what can you do to make sure everyone can contribute?\n\n### Speed up workflow for reporters\n\nWe created Marker.io to speed up and simplify your team bug reporting. Now, those 10 steps are only three:\n\n1. Capture and annotate screenshot of bug.\n1. Send bug reports straight to your GitLab project.\n1. Keep hunting for more bugs!\n\nOne real-life example is an issue we ran into with our pricing page a while back. During our QA process, we noticed a weird bug: the price for our Team Plan was mysteriously missing. Instead of using the lengthy process mentioned earlier in this post, we used Marker.io to quickly send feedback to our dev team and get the bug fixed in no time.\n\nThis is what reporting the issue with Marker.io looked like:\n\n![Creating the bug report issue in GitLab](https://about.gitlab.com/images/blogimages/GitLab-creating-issue-Marker-io.gif){: .shadow.center.medium}\n\nNow, not only is the process much faster, but you never have to leave your website, there is nothing to configure, and all the technical data the developers need is automatically captured by Marker.io.\n\n### Create actionable reports for your developers\n\nOnce a visual feedback tool like Marker.io is introduced into the equation your developers can choose where they receive feedback, down to the specific bug-tracking GitLab project, and the important technical data they need is automatically grabbed and included in every bug report.\n\nThat means environment data, including:\n- Browser\n- Operating system (OS) and version\n- Screen size\n- Zoom level\n- Pixel ratio\n\nHere’s an example of what a Marker.io bug report looks like in GitLab:\n\n![The bug report issue inside GitLab](https://about.gitlab.com/images/blogimages/GitLab-issue-created-with-Marker-io.gif){: .shadow.center.medium}\n\nThis GitLab issue has all the information needed for your developers to act on it:\n\n- The issue is in the correct project.\n- Any pre-set epics, milestones or labels are included.\n- The issue is assigned to a team member.\n- The annotated screenshot is attached.\n- The expected and actual results are well documented.\n- The steps to reproduce are detailed.\n- The technical environment information is all there.\n- The issue has the URL where the screenshot was captured.\n- The issue has a due date.\n\nNo more wasted time following up with reporters to fill in the gaps. It’s all there, organized directly in your chosen GitLab project – complete with everything vital to fix your bugs.\n\nWant to try for yourself? Marker.io comes with a free 15-day trial. Give it go ➡️ [Marker.io/gitlab](https://marker.io/gitlab?utm_source=gitlab&utm_medium=post&utm_campaign=gitlab_bug_reporting)\n\n### About the guest author\n\nMarie Hargitt is the Marketing Manager of [Marker.io](https://marker.io/gitlab), a powerful tool that makes bug reporting and visual feedback easy for the whole team.\n",[717,9,872],{"slug":2606,"featured":6,"template":696},"marker-io-gitlab-integration","content:en-us:blog:marker-io-gitlab-integration.yml","Marker Io Gitlab Integration","en-us/blog/marker-io-gitlab-integration.yml","en-us/blog/marker-io-gitlab-integration",{"_path":2612,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2613,"content":2619,"config":2625,"_id":2627,"_type":13,"title":2628,"_source":15,"_file":2629,"_stem":2630,"_extension":18},"/en-us/blog/microcks-and-gitlab-part-one",{"title":2614,"description":2615,"ogTitle":2614,"ogDescription":2615,"noIndex":6,"ogImage":2616,"ogUrl":2617,"ogSiteName":683,"ogType":684,"canonicalUrls":2617,"schema":2618},"Speed up API and microservices delivery with Microcks and GitLab - Part 1","Learn how to configure Microcks for GitLab and what the use cases are for this open source Kubernetes-native tool.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749683021/Blog/Hero%20Images/lightsticks.png","https://about.gitlab.com/blog/microcks-and-gitlab-part-one","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Speed up API and microservices delivery with Microcks and GitLab - Part 1\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Madou Coulibaly\"}],\n        \"datePublished\": \"2023-09-27\",\n      }",{"title":2614,"description":2615,"authors":2620,"heroImage":2616,"date":2622,"body":2623,"category":739,"tags":2624},[2621],"Madou Coulibaly","2023-09-27","\n\nAPI development is all the rage these days for customer and partner integration, frontend-to-backend communication, microservices orchestration, and more. Yet APIs have their challenges, including how to create a fast feedback loop on design, how different teams can work with autonomy without having to wait for each other's API implementation, and how to cope with backward compatibility tests when shipping newer versions of the API. \n\n[Microcks](https://microcks.io), an open source, Kubernetes-native tool for API mocking and testing, addresses these challenges. With Microcks, which is accepted as a Sandbox project in the [Cloud Native Computing Foundation](https://cncf.io), developers can leverage their [OpenAPI](https://www.openapis.org/), [GraphQL](https://graphql.org/), [gRPC](https://grpc.io/), [AsyncAPI](https://www.asyncapi.com/), and [Postman Collection](https://www.postman.com/collection/) assets to quickly mock and simulate APIs before writing them. Couple Microcks with GitLab and you have a powerful combination to foster collaboration, encourage rapid changes, and provide a robust delivery platform for API-based applications.\n\nIn this ongoing blog series, we will introduce you to Microcks use cases and how they fit with the GitLab platform. We'll also discuss technical integration points that will help ease the developer burden, including identity management, Git repositories, and pipeline integrations.\n\n## What is Microcks?\nMicrocks addresses two major use cases: \n- **Simulating (or mocking) an API or a microservice** from a set of descriptive assets. This can be done as soon as you start the design phase to set up a feedback loop very quickly, or later on to ease the pain of provisioning environments with a lot of dependencies.\n- **Validating the conformance of your application regarding your API specification** by running contract-test. This validation can be integrated into your CI/CD pipeline so that conformance can be checked on each and every iteration. This is of great help to enforce backward compatibility of your API of microservices interfaces.\n\nMicrocks offers a uniform and consistent approach for the various kinds of request/response APIs (REST, GraphQL, gRPC, Soap) and event-driven APIs (currently supporting eight different protocols), thereby bringing consistency for users and for automations all along your API lifecycle.\n\n## How Microcks fits into the software development lifecycle\nMicrocks is a solution based on containers and can be deployed in several configurations. It can be deployed on the developer laptop through [Docker](https://microcks.io/documentation/installing/docker-compose/), [Podman](https://microcks.io/documentation/installing/podman-compose/) or [Docker Desktop Extension](https://microcks.io/documentation/installing/docker-desktop-extension/) to assist with mocking complex environments. When it comes to team collaboration, Microcks can be deployed as a centralized instance that connects to the Git repositories of the organization, discovers the API artifacts, and then provides shared up-to-date API simulations.\n\n![diagram of how Microcks fits into development lifecycle](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/microcks.png){: .shadow.small.center}\n\nTo ease the burden on developers (and administrators), Microcks can be configured to use your GitLab platform as an identity provider. With that configuration, integrating Microcks is seamless, and API simulations are automatically shared among development teams. Microcks fosters collaboration by providing everyone with the same “source of truth” and avoiding drift risks. The tool can also be used to lower the pain and the cost of deploying and maintaining complex QA environments because simulations are inexpensive to deploy or redeploy on-demand. Microcks deployment follows a GitOps approach.\n\nBeyond this sharing of simulations, Microcks also integrates well with CI/CD pipelines. As you release API-based applications, there is always concern about conformance of the contractualized expectations you defined using specifications like OpenAPI, GraphQL, and the like. Usually, the hardest part isn't delivering the `1.0` of this API; problems come later when you're trying to deliver the `1.3`. This latest version must still be backward compatible with the 1.0 contract if you don't want to make your consumers angry and frustrated.\n\nThis conformance validation is very well assured by Microcks using contract-testing principles. So we encourage you to plug Microcks into some `test` related jobs in your GitLab pipeline and delegate this conformance validation to your Microcks instance.\n\n![microcks-in-gitlab-workflow](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/microcks-in-gitlab-workflow.png){: .shadow.medium.center}\n\n\nEmbedding Microcks conformance testing in your pipeline is actually easy thanks to our lightweight CLI that you'll integrate in pipeline jobs. You can choose to reuse an existing Microcks instance to record results and keep history of your success or pop up a new ephemeral instance as it's lightweight and fast to bootstrap.\n\n## How to set up GitLab as an identity provider in Microcks\n\nTo start off this series, we will detail how to configure Microcks to use your GitLab platform as an identity provider. This is in fact very easy as authentication in Microcks is based on [Keycloak](https://keycloak.org) (another CNCF project) and GitLab can be set as an identity provider in Keycloak (see [official documentation](https://www.keycloak.org/docs/latest/server_admin/index.html#gitlab)).\n\n**Note:** This configuration is optional as Microcks can use any other identity provider Keycloak integrates with.\n\nKeycloak is a very common solution that may be deployed already at your organization. If not, Microcks comes with a Keycloak distribution that is pre-configured for its usage with a realm called `microcks`. We have used this realm to validate this configuration.\n\n### Create a GitLab Group Application\nThe first thing is to create a new [Group Application](https://docs.gitlab.com/ee/integration/oauth_provider.html#create-a-group-owned-application) on your GitLab instance as follows:\n- `Name`: `microcks-via-keycloak`\n- `Redirect URI`: `https://keycloak.acme.org/realms/microcks/broker/gitlab/endpoint`\n- `Scopes`: `read_user`, `openid`, `profile` and `email`\n\n![gitlab-application-form](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/gitlab-application-form.png){: .shadow.medium.center}\n\n\nThis application uses your Keycloak instance with `https://keycloak.acme.org/realms/microcks/broker/gitlab/endpoint` as the redirect URI. As a result, we obtain an `Application ID` and an associated `Secret` we have to keep aside for the next step.\n\n![gitlab-application](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/gitlab-application.jpeg){: .shadow.medium.center}\n\n\n### Add GitLab as identity provider in Keycloak\nThe next step takes place in the Keycloak admin console. Once the correct `microcks` realm is selected, you'll just have to go to the **Identity providers** section and add a GitLab provider. Simply paste here the `Application ID` you got earlier as `Client ID` and the `Secret` as `Client Secret`. You can also choose a `Display order` if you plan to have multiple identity providers.\n\n![keycloak-identity-provider](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/keycloak-identity-provider.jpg){: .shadow.medium.center}\n\n\nThen, from the **Authentication** section in the admin console, choose the browser flow and configure the `Identity Provider Redirector` as follows:\n\n- `Alias`: `GitLab`\n- `Default Identify Provider`: `gitlab`\n\n![keycloak-redirector](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/keycloak-redirector.jpg){: .shadow.medium.center}\n\n### Test your Microcks configuration\nNow open the Microcks URL into your browser and you'll be directly redirected to the GitLab login page. Enter your GitLab credentials and you will be authenticated and redirected to Microcks. \n\n![microcks-homepage](https://about.gitlab.com/images/blogimages/2023-09-27-microcks-and-gitlab-part-1-speed-up-api-and-microservices-delivery/microcks-homepage.jpeg){: .shadow.medium.center}\n\n## What's next?\nIn upcoming blogs, we'll detail how GitLab can be used in the two major use cases for Microcks. We'll see how Microcks integrates with GitLab Git repositories to discover API specifications and produce simulations, and how to integrate Microcks conformance tests into your GitLab CI/CD pipelines.\n\n_[Laurent Broudoux](https://www.linkedin.com/in/laurentbroudoux/) is a cloud-native architecture expert and enterprise integration problem lover. He has helped organizations in adopting distributed and cloud paradigms while capitalizing on their critical existing assets. He is the founder and lead developer of the [Microcks.io](https://microcks.io/) open-source project: a Kubernetes-native tool for API mocking and testing. For this, he is using his 10+ years experience as an architect in financial services where he defined API transformation strategies, including governance and delivery process._\n\n_[Madou Coulibaly](https://gitlab.com/madou) is a senior solutions architect at GitLab._\n",[1469,1989,108,850,9],{"slug":2626,"featured":6,"template":696},"microcks-and-gitlab-part-one","content:en-us:blog:microcks-and-gitlab-part-one.yml","Microcks And Gitlab Part One","en-us/blog/microcks-and-gitlab-part-one.yml","en-us/blog/microcks-and-gitlab-part-one",{"_path":2632,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2633,"content":2639,"config":2646,"_id":2648,"_type":13,"title":2649,"_source":15,"_file":2650,"_stem":2651,"_extension":18},"/en-us/blog/microservices-integrated-solution",{"title":2634,"description":2635,"ogTitle":2634,"ogDescription":2635,"noIndex":6,"ogImage":2636,"ogUrl":2637,"ogSiteName":683,"ogType":684,"canonicalUrls":2637,"schema":2638},"Tackling the microservices repository explosion challenge","Microservices have spawned an explosion of dependent projects with multiple repos, creating the need for an integrated solution – we're working on it right now.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662898/Blog/Hero%20Images/microservices-explosion.jpg","https://about.gitlab.com/blog/microservices-integrated-solution","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"It's raining repos: The microservices repo explosion, and what we're doing about it\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Aricka Flowers\"}],\n        \"datePublished\": \"2018-11-26\",\n      }",{"title":2640,"description":2635,"authors":2641,"heroImage":2636,"date":2643,"body":2644,"category":739,"tags":2645},"It's raining repos: The microservices repo explosion, and what we're doing about it",[2642],"Aricka Flowers","2018-11-26","\nGone are the days of \"set it and forget it\"-style software development. The increased demand for code and operations on all projects, especially [microservices](/topics/microservices/), means more repos. This calls for a more integrated solution to incorporate testing, security updates, monitoring, and more, says GitLab CEO [Sid Sijbrandij](/company/team/#sytses):\n\n>\"The bar's going up for software development. It's no longer enough to just write the code; you also have to write the tests. It's no longer enough to just ship it; you also have to monitor it. You can no longer make it once and forget about it; you have to stay current with security updates. For every product you make you have to integrate more of these tools. It used to be that only the big projects got all these things, but now every single service you ship should have these features, because other projects are dependent on it. One security vulnerability can be enough to take a company down.\"\n\nAn increasing number of project repos means exponential growth in the number of tools needed to handle them – bad news for those saddled managing project dependencies. A streamlined workflow is essential to alleviate this burden – here's how we want to help you get there.\n\n### Everything under one roof\n\n\"With GitLab, we want to enable you to simply commit your code and have all the tools you need integrated out of the box,\" Sid said. \"You don't have to do anything else. It's monitored; we measure whether your dependencies have a vulnerability and fix it for you automatically. I think that's the big benefit of GitLab; that you don't have to go into stitching together 10 tools for every project that you make.\"\n\nBy using an integrated solution to manage an ever-growing number of microservices, you can avoid having engineers siloed off with their respective teams and tools. Creating visibility among teams and getting rid of the need for handoffs leads to a faster [DevOps lifecycle](/topics/devops/) while also ensuring that your projects deploy and remain stable, Sid explains.\n\n\"Our customers that switched from a fragmented setup and were only able to get projects through that cycle a few times a year are now deploying a few times a week,\" Sid said. \"The ability to go from planning to monitoring it in production is what GitLab brings to the table. We have an ample amount of customer case studies showing how we helped improve their speed.\"\n\n### Better support for microservices\n\nWe are boning up our support of microservices, and have a number of features in the works to improve this area, including [group level Kubernetes clusters](https://gitlab.com/gitlab-org/gitlab-ce/issues/34758), a [global Docker registry browser](https://gitlab.com/gitlab-org/gitlab-ce/issues/49336), and adding the [ability to define multiple pipelines](https://gitlab.com/gitlab-org/gitlab-ce/issues/22972). This is to build on what's already there:\n\n\"We have great support for microservices. GitLab has [multi-project pipelines](/blog/use-multiproject-pipelines-with-gitlab-cicd/) and [can trigger pipelines from multi-projects via API](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html),\" Sid detailed. \"The CI Working Group of the CNCF (Cloud Native Computing Foundation), the most cloud native organization in the world probably, uses GitLab to test their projects. We've got great support for things like [Kubernetes](/solutions/kubernetes/) and cloud native technologies. In GitLab, every project you have can be attached to a Kubernetes cluster, and GitLab uses that to run everything that’s going on. We know that a lot of our users and customers are using microservices, and we work great with them.\"\n\n### Future focus: best-in-class solutions\n\nGitLab is much more than just version control. Having started with the planning, creating and verifying stages in 2011 and 2012, we’ve had time to make those capabilities very strong. We are now strengthening our offerings in the other steps of the DevOps lifecycle: managing, packaging, releasing, configuring, monitoring and security.\n\n\"We are seeing enormous progress in those areas, but they can't go head to head with the best-in-class solutions just yet. So that's going be the theme for GitLab next year, to make sure each of our solutions is best in class instead of just the three things we started with,\" Sid says. \"And we won't take our eyes off the ball.\"\n\n[Cover image](https://unsplash.com/photos/wplxPRCF7gA) by [Ruben Bagues](https://unsplash.com/@rubavi78) on Unsplash\n{: .note}\n",[785,9,1040,716,1989],{"slug":2647,"featured":6,"template":696},"microservices-integrated-solution","content:en-us:blog:microservices-integrated-solution.yml","Microservices Integrated Solution","en-us/blog/microservices-integrated-solution.yml","en-us/blog/microservices-integrated-solution",{"_path":2653,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2654,"content":2659,"config":2665,"_id":2667,"_type":13,"title":2668,"_source":15,"_file":2669,"_stem":2670,"_extension":18},"/en-us/blog/migrating-repositories-to-gitlab-just-became-easier",{"title":2655,"description":2656,"ogTitle":2655,"ogDescription":2656,"noIndex":6,"ogImage":884,"ogUrl":2657,"ogSiteName":683,"ogType":684,"canonicalUrls":2657,"schema":2658},"Migrating repositories to GitLab just became easier","Automate data and user migration into GitLab using open core software Congregate.","https://about.gitlab.com/blog/migrating-repositories-to-gitlab-just-became-easier","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Migrating repositories to GitLab just became easier\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Bryan May\"}],\n        \"datePublished\": \"2021-10-26\",\n      }",{"title":2655,"description":2656,"authors":2660,"heroImage":884,"date":2662,"body":2663,"category":1244,"tags":2664},[2661],"Bryan May","2021-10-26","\n\nAs customers begin their journey with GitLab, they often start by moving their source code repositories to GitLab. The GitLab Professional Services team has been helping customers with large scale [migrations](/services/migration/) for years and during this time have built a utility to automate the migration process - [Congregate](https://gitlab.com/gitlab-org/professional-services-automation/tools/migration/congregate#congregate). To ensure we’re aligned with the [GitLab values](https://handbook.gitlab.com/handbook/values/) of transparency and collaboration, we’re making it available to customers and partners. As of today, Congregate has been moved to a [source available](https://en.wikipedia.org/wiki/Source-available_software) disposition. \n\nFor smaller customers this might not be too important because they can use [GitLab import functionality](https://docs.gitlab.com/ee/user/project/settings/import_export.html) to migrate themselves. But for customers moving hundreds or thousands of source code repositories and associated users to GitLab, this is a game changer. And perhaps most importantly, our growing team of [channel services partners](https://partners.gitlab.com/) can now leverage Congregate functionality as they help customers move data. And for each contribution that partners or customers make back to Congregate, the larger [community](/community/) benefits. \n\n## Why are you doing this? Customers pay you for these services!\n\nGitLab Professional Services falls under the umbrella of Customer Success and its [mission](https://about.gitlab.com/handbook/customer-success/#mission-statement) is to _deliver value to all customers by engaging in a consistent, repeatable, scalable way across defined segments so that customers see the value in their investment with GitLab_. While Professional Services needs to maintain a balanced business (we are not a cost center), we believe that our paramount goal is to help our customers. As GitLab grows and the number of customers also increases, we will rely more heavily on our channel partners. We see making Congregate source available as a means to reach the largest quantity of customers with the highest quality migration service offering. Similar to how GitLab has [over 3,000 contributions from the wider community](/blog/3000-contributors-post/), we think welcoming contributions for this migration tool will help ensure GitLab and its partners converge on a single solution rather than diverging to many. \n\n## What do you mean by _Source Available_?\n\nCongregate will be licensed under the GitLab EE license. For services partners and customers, this means:\n\n![Legal Guidelines](https://about.gitlab.com/images/blogimages/2021-10-20-migration-automation/legal-guidelines2.png)\n\n## I’m a partner, will GitLab PS support my migration?\n\n- No, but support is available on a fee-based engagement. As an example if you have a customer migration that you need support on, you can engage GitLab PS as the Prime and GitLab will work with you to subcontract the engagement to you and provide the  necessary support.  \n- If a Partner is using Congregate on its own contract directly with the customer, GitLab PS will not provide support for Congregate. As such, Congregate is a USE AT YOUR OWN RISK tool. \n- Customer engagements on a partner contract intending to migrate to gitlab.com can be subcontracted to GitLab PS to help with these migration activities. \n\n_Note: GitLab PS will always need to be involved for migrations to gitlab.com as certain elevated privileges are required to maintain data integrity._\n\n## It's just a bunch of scripted API calls, what's so special?\n\nCongregate is using all of the published APIs so there isn’t a ton of “secret sauce” in the project. However, we have spent time optimizing for performance using multiprocessing techniques to reduce the time it takes to gather and push data. We’ve also created a standard logging format to provide auditability of what happened during a migration. Congregate can migrate data from many popular source systems to help the majority of our prospects and customers move to GitLab.  \n\n## How can I use it?\n\nWe are releasing a learning path for partners (or customers) to earn a [certified GitLab migration engineer badge](https://gitlab.badgr.com/public/badges/zzzdONLxRaCW5cDQSlHsgw). This learning journey will initially be released to GitLab team members and partners. It will include general information about importing data into GitLab, quizzes and exams to validate your knowledge, and a hands-on workshop where you will use Congregate to move data to a test GitLab instance. Once you pass, you will receive a badge that you can post in a **#humblebrag** to your social media network - that's what social media is for, right? We recommend going through this training to understand how to use Congregate. As a partner, you can access this certification learning journey [here](https://partners.gitlab.com/prm/English/c/Training). \n\n![Certified Migration Services Engineer](https://about.gitlab.com/images/blogimages/2021-10-20-migration-automation/migration-badge.png){: .shadow.center}\n\n\n\n\n",[851,9,693],{"slug":2666,"featured":6,"template":696},"migrating-repositories-to-gitlab-just-became-easier","content:en-us:blog:migrating-repositories-to-gitlab-just-became-easier.yml","Migrating Repositories To Gitlab Just Became Easier","en-us/blog/migrating-repositories-to-gitlab-just-became-easier.yml","en-us/blog/migrating-repositories-to-gitlab-just-became-easier",{"_path":2672,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2673,"content":2679,"config":2685,"_id":2687,"_type":13,"title":2688,"_source":15,"_file":2689,"_stem":2690,"_extension":18},"/en-us/blog/migrating-your-jira-issues-into-gitlab",{"title":2674,"description":2675,"ogTitle":2674,"ogDescription":2675,"noIndex":6,"ogImage":2676,"ogUrl":2677,"ogSiteName":683,"ogType":684,"canonicalUrls":2677,"schema":2678},"Migrating your JIRA issues to GitLab","We're migrating all of our working tools to open-source ones, and moving to GitLab has made all the difference.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667509/Blog/Hero%20Images/continuous-integration-from-jenkins-to-gitlab-using-docker.jpg","https://about.gitlab.com/blog/migrating-your-jira-issues-into-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Migrating your JIRA issues to GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Abdulkader Benchi\"}],\n        \"datePublished\": \"2017-08-21\",\n      }",{"title":2674,"description":2675,"authors":2680,"heroImage":2676,"date":2682,"body":2683,"category":739,"tags":2684},[2681],"Abdulkader Benchi","2017-08-21","\n\n Here at [Linagora](https://linagora.com/), we believe in open source. If you have read my [last article](/blog/docker-my-precious/), you should know that we have recently migrated from [Atlassian](https://www.atlassian.com/) to [GitLab](https://gitlab.com/).\n\n\u003C!-- more -->\n\n_Editor's note: We don't currently have a native way to migrate JIRA issues into GitLab issues, although we are [working on one](https://gitlab.com/gitlab-org/gitlab-ee/issues/2780)! In the meantime, we are very appreciative of community efforts to provide workarounds like this one._\n\nMigrating our repositories from [Bitbucket](https://bitbucket.org/) to GitLab was so easy thanks to Git. However, migrating our issues (aka tickets) from [JIRA](https://www.atlassian.com/software/jira) to GitLab was not so obvious. In fact, there are several alternative solutions to integrate JIRA as a plugin inside GitLab so as to continue using JIRA along with GitLab. However, our main goal was to completely leverage GitLab as our only open-source development tool.\n\nIf you want to know how to migrate your JIRA issues into GitLab, then you are on the right article. Once you read it, you will discover that it is really so easy to do the migration from JIRA to GitLab. Yes, as you can see, winter is coming to GitLab rivals, because everything is possible with GitLab.\n\n### Migrating JIRA issues into GitLab Issues\n\nOur migration process will leverage the [REST APIs](http://www.restapitutorial.com/) provided by both [JIRA REST API](https://developer.atlassian.com/jiradev/jira-apis/jira-rest-apis) and GitLab Issues [REST API](https://docs.gitlab.com/ee/api/issues.html).\n\n#### API calls:\n\nTo perform REST API cals, you can use your own preferred library. For me, I will use [axios](https://github.com/mzabriskie/axios), which is my preferred promise based HTTP client for the browser and node.js. You can simply install it locally by doing:\n\n```\nnpm install axios\n\n```\n\n#### JIRA side:\n\nBefore requesting the endpoints provided by JIRA, we need to gather the following information:\n\n```\n// the base url to your JIRA\nconst JIRA_URL = 'https://your-jira-url.com/';\n\n// the JIRA project ID (short)\nconst JIRA_PROJECT = 'PRO';\n\n// JIRA username and password used to login\nconst JIRA_ACCOUNT = {\n  username,\n  password\n};\n\n```\n\nNow, we need to call two endpoints call during the migration process. The first endpoint is to get all **JIRA issues**:\n\n```\naxios.request({\n  method: 'get',\n  url: `${JIRA_URL}/rest/api/2/search?jql=project=${JIRA_PROJECT}+order+by+id+asc&startAt=${offset}&maxResults=${limit}`,\n  auth: {\n    username: JIRA_ACCOUNT.username,\n    password: JIRA_ACCOUNT.password\n  }\n})\n```\n\nThe second endpoint is to get the **attachments** and the **comments** related to a given issue:\n\n```\naxios.request({\n  method: 'get',\n  /*\n  * JIRA_ISSUE = the JIRA issue that we get from the previous call\n  */\n  url: `${JIRA_URL}/rest/api/2/issue/${JIRA_ISSUE.id}/?fields=attachment,comment`,\n  auth: {\n    username: JIRA_ACCOUNT.username,\n    password: JIRA_ACCOUNT.password\n  }\n})\n```\n\n#### GitLab side:\n\nAs for JIRA, we need to gather some information before starting sending REST requests:\n\n```\n// the base url to your GitLab\nconst GITLAB_URL = 'http://your-gitlab-url.com/';\n\n// the project in gitlab that you are importing issues to\nconst GITLAB_PROJECT = 'namespaced/project/name';\n\n// GitLab username and password used to login\nconst GITLAB_ACCOUNT = {\n  username,\n  password\n};\n\n/* this token will be used whenever the API is invoked and\n* the jira's author of (the comment / attachment / issue) is not a gitlab user.\n* So, this identity will be used instead.\n* GITLAB_TOKEN is visible in your account: https://ci.linagora.com/profile/account\n*/\nconst GITLAB_TOKEN = 'get-this-token-from-your-profile';\n```\n\nEach JIRA issue has several fields which represent JIRA users, e.g., *assignee* and *reporter*. Once migrating to GitLab we should try to link these users to GitLab users (if they already exist on GitLab). However, if the user is not a GitLab user, then we have to leverage the **GITLAB_TOKEN** (line 18 in the last gist). That is, if the user does not exist on GitLab, then the identity of the user who is doing the migration will be used instead.\n\nTo search all GitLab users we need to send the following REST call:\n\n```\naxios.request({\n  method: 'get',\n  // 10000 users, should be enough to get them all\n  url: `${GITLAB_URL}/api/v4/users?active=true&search=&per_page=10000`,\n  headers: {\n    'PRIVATE-TOKEN': GITLAB_TOKEN\n  }\n})\n```\n\nAnd now, we can find the corresponding GitLab user for each JIRA user by doing:\n\n```\nfunction jiraToGitlabUser(JIRAUser) {\n    // GitLabUsers = the list of GitLab users we get from the last call\n    return JIRAUser ? _.find(GitLabUsers, { email: JIRAUser.emailAddress }) : null\n  }\n```\n\nIt is worth noting that JIRA and GitLab issues are different in nature, so you need to migrate one type of issue to another. After searching all [JIRA issues](https://medium.com/linagora-engineering/gitlab-rivals-winter-is-here-584eacf1fe9a) and [JIRA attachments](https://medium.com/linagora-engineering/gitlab-rivals-winter-is-here-584eacf1fe9a) and comments, we can now transfer them into GitLab issues by doing the following mapping:\n\n```\n{\n    title: JIRAIssue.fields.summary,\n    description: JIRAIssue.fields.description,\n    labels: [JIRAIssue.fields.issuetype.name],\n    created_at: JIRAIssue.fields.created,\n    updated_at: JIRAIssue.fields.updated,\n    done: issue.fields.status.statusCategory.name === 'Done' ? true : false,\n    assignee: jiraToGitlabUser(JIRAIssue.fields.assignee ),\n    reporter: jiraToGitlabUser(JIRAIssue.fields.reporter),\n    comments: JIRAComments.map(JIRAComment => ({\n      author: jiraToGitlabUser(JIRAComment.author),\n      comment: JIRAComment.body,\n      created_at: JIRAComment.created\n    })),\n    attachments: JIRAAttachments.map(JIRAAttachment => ({\n      author: jiraToGitlabUser(JIRAAttachment.author),\n      filename: JIRAAttachment.filename,\n      content: JIRAAttachment.content,\n      created_at: JIRAAttachment.created\n    }))\n};\n```\n\nNow our GitLab issue is created, all what we need to do is to post it:\n\n```\naxios.request({\n  method: 'post',\n  url: `${GITLAB_URL}/api/v4/projects/${encodeURIComponent(GITLAB_PROJECT)}/issues`,\n  // the GitLab issue that we have just created\n  data: GITLAB_ISSUE\n  headers: {\n    'PRIVATE-TOKEN': GITLAB_TOKEN\n  }\n})\n```\n\nAs you can see, migrating your JIRA tickets to GitLab is all about some REST API calls. As a developer, I think that you do such REST API calls every day. So we really do not need to stuck with JIRA nor to add it as a plugin to GitLab.\n\nIf you think that this article helps you discover something interesting that you feel you want to do every day, so please do not hesitate and join us. We are looking for new talents. For more information, you can have a look at our [Job site](https://job.linagora.com/en/).\n\n\nThis post originally appeared on _[Medium](https://medium.com/linagora-engineering/gitlab-rivals-winter-is-here-584eacf1fe9a)_.\n\n### About the Guest Author\n\nAbdulkader Benchi is the Javascript team leader at [Linagora](https://linagora.com/careers).\n",[9,872],{"slug":2686,"featured":6,"template":696},"migrating-your-jira-issues-into-gitlab","content:en-us:blog:migrating-your-jira-issues-into-gitlab.yml","Migrating Your Jira Issues Into Gitlab","en-us/blog/migrating-your-jira-issues-into-gitlab.yml","en-us/blog/migrating-your-jira-issues-into-gitlab",{"_path":2692,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2693,"content":2699,"config":2704,"_id":2706,"_type":13,"title":2707,"_source":15,"_file":2708,"_stem":2709,"_extension":18},"/en-us/blog/mobile-static-application-security-testing-for-android",{"title":2694,"description":2695,"ogTitle":2694,"ogDescription":2695,"noIndex":6,"ogImage":2696,"ogUrl":2697,"ogSiteName":683,"ogType":684,"canonicalUrls":2697,"schema":2698},"Android App Security Testing with SAST","Learn how to secure your Android application with Static Application Security Testing.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666816/Blog/Hero%20Images/security-cover.png","https://about.gitlab.com/blog/mobile-static-application-security-testing-for-android","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Android App Security Testing with SAST\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2020-12-16\",\n      }",{"title":2694,"description":2695,"authors":2700,"heroImage":2696,"date":2701,"body":2702,"category":716,"tags":2703},[1220],"2020-12-16","\n\nAt GitLab, everyone can contribute! [GitLab 13.5](/releases/2020/10/22/gitlab-13-5-released/) included an [integration for Mobile Static\nApplication Security Testing (SAST)](/releases/2020/10/22/gitlab-13-5-released/#sast-support-for-ios-and-android-mobile-apps) from one of our customers. For their contribution, the \n[H-E-B Digital](https://digital.heb.com/) team were [October 2020's MVP](/releases/2020/10/22/gitlab-13-5-released/#mvp).\n\nTheir contribution enables SAST for mobile applications. This includes iOS apps written in Objective-C\nand Swift as well as Android apps written in Java and Kotlin. \n\nThis blog post will go over how Mobile SAST works on Android.\n\n## Static Application Security Testing\n\n[Static Application Security Testing](https://docs.gitlab.com/ee/user/application_security/sast/) analyzes source code for known vulnerabilities.\nSAST is used to detect potentially dangerous attributes in a class, or unsafe code that can\nlead to unintended code execution, as well as other issues such as SQL Injection. More information\non SAST can be seen in the [OWASP Documentation](https://owasp.org/www-community/controls/Static_Code_Analysis).\n\nHere is a video which goes over [setting up SAST for Mobile](https://docs.gitlab.com/ee/user/application_security/sast/#experimental-features), as well as a sample application\nyou can use to get started:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/v0GhEHZWtdw\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nIn a nutshell, after the scanner has been configured, whenever an MR is created the\nscanner runs on the application source code and looks for patterns to determine if\nthat code is vulnerable. This is covered below.\n\nInitially this analyzer supports source code analysis but we intend to [expand support for binary\nscanning](https://gitlab.com/gitlab-org/gitlab/-/issues/269915) of .ipa and .apk files in the near future.\n\n## Understanding security rules\n\nSAST for mobile applications uses the Mobile Security Framework (MobSF) to scan source code. MobSF\nuses certain rules in order to determine if an application is vulnerable. The rules used to scan\nmobile applications can be seen in their [rules file](https://github.com/MobSF/Mobile-Security-Framework-MobSF/tree/master/StaticAnalyzer/views/android/rules).\nThese rules use [regex](https://en.wikipedia.org/wiki/Regular_expression) in order to find vulnerabilities in the static code.\n \nYou can also [contribute your own rules](https://github.com/MobSF/Mobile-Security-Framework-MobSF/blob/master/.github/CONTRIBUTING.md) if you have thoghts on enhancements.\nI made a small change to [enable a regex to work on Kotlin](https://github.com/MobSF/Mobile-Security-Framework-MobSF/pull/1611).\nNot only can everyone contribute at GitLab, we encourage team members to contribute to other open source projects.\n\nNote: You will have to test your changes before they can be approved. In order to do this, you must [install\nyour branch as seen here](https://mobsf.github.io/docs/#/installation).\n\n## Adding your own scanners\n\nGitLab allows for lots of extensibility. Using our [integration guidance](https://docs.gitlab.com/ee/development/integrations/secure.html), you can bring your own scanners into the\nmerge request pipeline and the security dashboards. This was done for MobSF SAST, as well as the [WhiteSource\nDependency Scanner](/blog/whitesource-for-dependency-scanning/).\n\nI hope you enjoyed this blog post. Now you can start making your Android applications more secure.\nYou can reach out on Twitter and share your thoughts with us [@GitLab](https://twitter.com/gitlab)!\n",[716,851,742,9,693],{"slug":2705,"featured":6,"template":696},"mobile-static-application-security-testing-for-android","content:en-us:blog:mobile-static-application-security-testing-for-android.yml","Mobile Static Application Security Testing For Android","en-us/blog/mobile-static-application-security-testing-for-android.yml","en-us/blog/mobile-static-application-security-testing-for-android",{"_path":2711,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2712,"content":2718,"config":2725,"_id":2727,"_type":13,"title":2728,"_source":15,"_file":2729,"_stem":2730,"_extension":18},"/en-us/blog/monitoring-your-gitlab-environment-with-the-elk-stack",{"title":2713,"description":2714,"ogTitle":2713,"ogDescription":2714,"noIndex":6,"ogImage":2715,"ogUrl":2716,"ogSiteName":683,"ogType":684,"canonicalUrls":2716,"schema":2717},"GitLab monitoring: Setting up Logz.io and ELK stack","ELK, together with GitLab’s logging framework, gives organizations a comprehensive view for monitoring, troubleshooting, and analyzing team activity.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680160/Blog/Hero%20Images/gitlab-logz-io-cover.png","https://about.gitlab.com/blog/monitoring-your-gitlab-environment-with-the-elk-stack","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to set up advanced monitoring for your GitLab environment with Logz.io and the ELK stack\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Daniel Berman\"}],\n        \"datePublished\": \"2018-04-13\",\n      }",{"title":2719,"description":2714,"authors":2720,"heroImage":2715,"date":2722,"body":2723,"category":739,"tags":2724},"How to set up advanced monitoring for your GitLab environment with Logz.io and the ELK stack",[2721],"Daniel Berman","2018-04-13","GitLab comes with some built-in monitoring and visualization capabilities,\nsuch as [Cycle Analytics](/solutions/value-stream-management/)\nand the [per-project\ncontributors](https://docs.gitlab.com/ee/user/group/contribution_analytics/)\nand\n[repository](https://docs.gitlab.com/ee/user/project/repository/#repository-graph)\ngraphs, as well as [integration with\nPrometheus](https://docs.gitlab.com/ee/administration/monitoring/prometheus/)\nto monitor your GitLab instance at the server level. Cycle Analytics is\nespecially useful as it enables teams to analyze their efficiency. However,\nif you want to analyze the data by searching and querying, or if you want to\nvisualize the data yourself, you might find it helpful to adopt a more\ncentralized methodology by integrating with the [ELK\nStack](https://logz.io/learn/complete-guide-elk-stack/) (Elasticsearch,\nLogstash and Kibana).\n\n\n\u003C!-- more -->\n\n\nELK provides powerful log aggregation, analysis and visualization\ncapabilities that, used in tandem with GitLab’s extensive logging framework,\nwill give organizations an accurate and comprehensive bird's eye view of the\nsystem for monitoring, troubleshooting, and analyzing team activity. Using\nGitLab’s log data, for example, rich dashboards can be created to monitor\nnot only the system’s general health but also specific team metrics, such as\nthe number of commits, issues opened and closed, and so forth.\n\n\n[Logz.io](https://logz.io/) users can benefit from a built-in integration\nwith GitLab and the additional analysis tools provided by the service, but\nif you’re using your own ELK deployment you’ll be able to set up the\ndescribed integration as well.\n\n\n## How to integrate GitLab and Logz.io\n\n\nThe steps outlined below presume the following:\n\n\n* You have an [Omnibus GitLab](https://docs.gitlab.com/omnibus/)\ninstallation up and running. If you haven't installed GitLab already, visit\nthe [installation page](/installation/).\n\n* You have an ELK Stack up and running (either your own ELK deployment or a\nLogz.io account). We will be using Filebeat to ship the logs into\nElasticsearch, so Logstash is only required if you want to apply advanced\nparsing to the data.\n\n\n### GitLab logs\n\nAs mentioned above, GitLab has an [advanced logging\nframework](https://docs.gitlab.com/ee/administration/logs.html) that ships a\nvariety of different system logs.\n\n\nOf course, what log data you want to ship is entirely up to you. You can\nship all the log data, or you can be a bit more selective. These logs can be\npretty verbose, so depending on storage and retention considerations, it’s\ngood practice to first understand what logs you need to monitor in the first\nplace.\n\n\nThe Filebeat configurations provided below are designed for shipping the\nfollowing logs.\n\n\n### production_json.log\n\nThis JSON-formatted log records requests sent by GitLab to the Ruby\ncontrollers. Here is a sample log:\n\n\n```json\n\n{\"method\":\"GET\",\"path\":\"/-/metrics\",\"format\":\"html\",\"controller\":\n\n\"MetricsController\",\"action\":\"index\",\"status\":200,\"duration\":1.69,\n\n\"view\":0.23,\"db\":0.0,\"time\":\"2017-12-26T14:47:49.505Z\",\"params\":{},\n\n\"remote_ip\":null,\"user_id\":null,\"username\":null}\n\n```\n\n\nAs you can see, the information in the log includes the request method, the\ncontroller, the action performed, the request status, duration, remote IP,\nand more.\n\n\nThe location of the file will vary according to your installation types. In\nthe case of the Omnibus GitLab packages (recommended installation), the file\nwill reside at:\n\n\n```\n\n/var/log/gitlab/gitlab-rails/production_json.log\n\n```\n\n\n### production.log\n\nThis is a plain text log file that contains information about all performed\nrequests. It includes the request URL, type, and origin IP as well the parts\nof code that serviced it. The log also provides details on all SQL requests\nand how long they took. Here is a sample log:\n\n\n```\n\nCompleted 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 3.2ms |\n\nElasticsearch: 1.5ms)\n\n```\n\n\nAgain, the location of the file varies. In the case of the GitLab Omnibus\npackages, the file resides at:\n\n\n```\n\n/var/log/gitlab/gitlab-rails/production.log\n\n```\n\n\n### api_json.log\n\nA specific, JSON-formatted, file for logging API requests only.\n\n\n```json\n\n{\"time\":\"2017-12-10T18:30:11.219Z\",\"severity\":\"INFO\",\"duration\":5.22,\n\n\"db\":0.82,\"view\":10.11,\"status\":200,\"method\":\"POST\",\"path\":\"/api/v4/\n\ninternal/allowed\",\"params\":{\"action\":\"git-upload-pack\",\"changes\":\"_any\",\"\n\n\u003Cspan style=\"font-weight:\n400;\">project\":\"hello-world\",\"protocol\":\"ssh\",\"env\":\"{}\",\"key_id\":\"[FILTERED]\"\n\n,\"secret_token\":\"[FILTERED]\"},\"host\":\"127.0.0.1\",\"ip\":\"127.0.0.1\",\"ua\":\"Ruby\"}\u003C/span>\n\n```\n\n\nLocation:\n\n\n```\n /var/log/gitlab/gitlab-rails/api_json.log\n```\n\n\n### application.log\n\nThis plain text log file tracks GitLab actions such as adding a new user,\ncreating a new project or group, and so forth. Can act as an audit trail for\nmonitoring user activity.\n\n\nExample:\n\n\n```\n\nDecember 24, 2017 15:10: User Created: username=dbirtin email=xxx@gmail.com\n\nip=xx.xx.xxx.xx confirmed:true\n\n```\n\n\nLocation:\n\n```\n\n/var/log/gitlab/gitlab-rails/application.log\n\n```\n\n\nIn any case, I recommend reading GitLab’s [excellent\ndocumentation](https://docs.gitlab.com/ee/administration/logs.html) to read\nup on these log files and the information included in them before\ncommencing.\n\n\n### Configuring Filebeat\n\n\nFilebeat is a log shipper belonging to the Beats family of shippers. Written\nin Go and extremely lightweight, Filebeat is the easiest and most\ncost-efficient way of shipping log files into the ELK Stack.\n\n\nIf you haven’t already installed Filebeat, here are some instructions (for\nDebian):\n\n\n```\n\ncurl -L -O\nhttps://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.1-amd64.deb\n\nsudo dpkg -i filebeat-6.1.1-amd64.deb\n\n```\n\n\nOpen up the Filebeat configuration file at: `/etc/filebeat/filebeat.yml`:\n\n\n```\n\nsudo vim /etc/filebeat/filebeat.yml\n\n```\n\n\nThe following configuration defines the different GitLab files to track and\nship into ELK. I’ve defined a prospector for each log type so I can add\ncustom fields to each. Alternatively, I could have defined one prospector\nfor all of the files.\n\n\n```\n\nfilebeat.prospectors:\n\n- type: log\n  enabled: true\n  paths:\n    - /var/log/gitlab/gitlab-rails/production_json.log\n  fields:\n    log: production_json\n  json.keys_under_root: true\n- type: log\n  enabled: true\n  paths:\n    - /var/log/gitlab/gitlab-rails/production.log\n  fields:\n    log: production\n- type: log\n  enabled: true\n  paths:\n    - /var/log/gitlab/gitlab-rails/api_json.log\n  fields:\n    log: api_json\n  json.keys_under_root: true\n- type: log\n  enabled: true\n  paths:\n    - /var/log/gitlab/gitlab-rails/application.log\n  fields:\n    log: application\noutput.elasticsearch:\n  # Array of hosts to connect to.\n  hosts: [\"localhost:9200\"]\n```\n\n\nStart Filebeat with:\n\n\n```\n\nsudo service filebeat start\n\n```\n\n\nAfter a while, a new index will be created and you can define a new index\npattern (filebeat-*) in Kibana to begin analyzing the data.\n\n\n### Shipping to Logz.io\n\nIf you are using Logz.io, a few small modifications need to be applied to\nestablish the logging pipeline.\n\n\nFirst, you will need to download an SSL certificate to use encryption:\n\n\n```\n\nwget\nhttps://raw.githubusercontent.com/logzio/public-certificates/master/COMODORSADomainValidationSecureServerCA.crt\n\n\nsudo mkdir -p /etc/pki/tls/certs\n\n\nsudo cp COMODORSADomainValidationSecureServerCA.crt /etc/pki/tls/certs/\n\n```\n\n\nYou can now edit the Filebeat configuration file. If you like, you can make\nuse of the Logz.io Filebeat wizard to generate the FIlebeat YAML file\nautomatically (available in the Filebeat section, under Log Shipping in the\nUI).\n\n\nEither way, the configurations should look something like this:\n\n\n```\n\nfilebeat:\n  prospectors:\n    -\n      paths:\n        - /var/log/gitlab/gitlab-rails/production_json.log\n      fields:\n        logzio_codec: json\n        token: \u003CyourToken>\n        type: gitlab-production-json\n      fields_under_root: true\n      encoding: utf-8\n      ignore_older: 3h\n    -\n      paths:\n        - /var/log/gitlab/gitlab-rails/production.log\n      fields:\n        logzio_codec: plain\n        token: \u003CyourToken>\n        type: gitlab-production\n      fields_under_root: true\n      encoding: utf-8\n      ignore_older: 3h\n    -\n      paths:\n        - /var/log/gitlab/gitlab-rails/api_json.log\n      fields:\n        logzio_codec: json\n        token: \u003CyourToken>\n        type: gitlab-api-json\n      fields_under_root: true\n      encoding: utf-8\n      ignore_older: 3h\n    -\n      paths:\n        - /var/log/gitlab/gitlab-rails/application.log\n      fields:\n        logzio_codec: plain\n        token: \u003CyourToken>\n        type: gitlab-application\n      fields_under_root: true\n      encoding: utf-8\n      ignore_older: 3h\n  registry_file: /var/lib/filebeat/registry\noutput:\n  logstash:\n    hosts: [\"listener.logz.io:5015\"]\n    ssl:\n      certificate_authorities: ['/etc/pki/tls/certs/COMODORSADomainValidationSecureServerCA.crt']\n```\n\n\nThe main differences are:\n\n\n* Logz.io specific fields added to each prospector. Replace \u003CyourToken> with\nyour Logz.io account token (can be found in the Logz.io UI, under Settings).\n\n* The output section defines the Logz.io listener and the SSL certificate to\nuse.\n\n\nOnce you start (or restart) Filebeat, the GitLab logs will begin to show up\nin Logz.io.\n\n\n### Analyzing the GitLab logs\n\nNow that your logging pipeline is up and running, it’s time to look into the\ndata with some simple analysis operations in Kibana.\n\n\nSome of the fields can be used to get some visibility into the logs. Adding,\nfor example, the ‘type’ field (the ‘log’ field in case you are using your\nown ELK), helps give the logs some context.\n\n\nWe can use Kibana queries to search for specific log data. Say, for example,\nyou want to take a look at failed logins into the system. To do this, we\nwould use this combination of a field-level and free-text search:\n\n\n```\n\ntype:gitlab-application AND \"failed\"\n\n```\n\n\n![Analyzing\nlogs](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/analyzing-logs.png){:\n.shadow.center}\n\n\nAnother example could be querying Elasticsearch for error responses for\nGitLab requests:\n\n\n```\n\ntype:gitlab-production-json AND status:[400 TO *]\n\n```\n\n\n![GitLab\nrequests](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/gitlab-requests.png){:\n.shadow.center}\n\n\nUsing Kibana’s visualization capabilities, you can create a series of simple\ncharts and metric visualizations for giving you a nice overview of your\nGitLab environment. Here are a few examples.\n\n\n### Visualizing commits\n\nWhat organization does not want to monitor its team’s productivity? A simple\nmetric visualization will give you a counter on how many commits were\nperformed by your team:\n\n\n![Fourteen\ncommits](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/14.png){:\n.shadow.center}\n\n\nLikewise, we can create a line chart visualization that gives us an overview\nover time of the commits, per user:\n\n\n![Fourteen\ncommits](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/line-chart.png){:\n.shadow.center}\n\n\n### Visualizing issues\n\nIn a similar fashion, you can use Kibana to keep track of opened and closed\nissues. A simple data table visualization gives us a breakdown of the issues\nopened:\n\n\n![Visualize\nissues](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/visualize-issues-1.png){:\n.shadow.center}\n\n\nA line chart can give us a depiction of how many issues were opened over\ntime:\n\n\n![Line\nchart](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/line-1.png){:\n.shadow.center}\n\n\nThe list goes on. You can monitor projects created, merges, user activity,\nCI/CD processes, and more. The logs generated by GitLab include a wealth of\ninformation that can be tapped into for monitoring, and adding these\nvisualizations into one Kibana dashboard gives you a nice overview of your\nenvironment.\n\n\n![End\ndashboard](https://about.gitlab.com/images/blogimages/monitoring-your-gitlab-environment-with-the-elk-stack/end-dashboard.png){:\n.shadow.center}\n\n\n### End notes\n\nThe ELK Stack offers built-in storage, search and visualization features\nthat complement GitLab’s rich logging capabilities. Using Filebeat, building\na logging pipeline for shipping data into ELK is simple. If you want to\nfurther process the logs, you might want to consider adding Logstash into\nyour pipeline setup.\n\n\nLogz.io provides some tools to help you hit the ground running – easy\nintegration steps, as well as the monitoring dashboard above. To install the\ndashboard, simply search for ‘GitLab’ in ELK Apps and hit the install\nbutton.\n\n\nEnjoy!\n\n\n## About the guest author\n\n\nDaniel Berman is Product Evangelist at Logz.io. He is passionate about log\nanalytics, big data, cloud, and family and loves running, Liverpool FC, and\nwriting about disruptive tech stuff. Follow him\n[@proudboffin](https://twitter.com/proudboffin).\n",[9],{"slug":2726,"featured":6,"template":696},"monitoring-your-gitlab-environment-with-the-elk-stack","content:en-us:blog:monitoring-your-gitlab-environment-with-the-elk-stack.yml","Monitoring Your Gitlab Environment With The Elk Stack","en-us/blog/monitoring-your-gitlab-environment-with-the-elk-stack.yml","en-us/blog/monitoring-your-gitlab-environment-with-the-elk-stack",{"_path":2732,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2733,"content":2739,"config":2746,"_id":2748,"_type":13,"title":2749,"_source":15,"_file":2750,"_stem":2751,"_extension":18},"/en-us/blog/monkton-moves-to-gitlab-customer-story",{"title":2734,"description":2735,"ogTitle":2734,"ogDescription":2735,"noIndex":6,"ogImage":2736,"ogUrl":2737,"ogSiteName":683,"ogType":684,"canonicalUrls":2737,"schema":2738},"Monkton's journey to GitLab: Focusing on automation","Monkton is migrating from a suite of disparate tools to GitLab, enabling them to better help their customers build safe, secure mobile apps.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670123/Blog/Hero%20Images/moving-to-gitlab-cover.png","https://about.gitlab.com/blog/monkton-moves-to-gitlab-customer-story","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Monkton's #movingtogitlab story: Going all in on automation and repeatability\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"},{\"@type\":\"Person\",\"name\":\"Aricka Flowers\"}],\n        \"datePublished\": \"2019-05-21\",\n      }",{"title":2740,"description":2735,"authors":2741,"heroImage":2736,"date":2742,"body":2743,"category":848,"tags":2744},"Monkton's #movingtogitlab story: Going all in on automation and repeatability",[1790,2642],"2019-05-21","\n\nEven with all the [#movingtogitlab](/blog/movingtogitlab/) excitement last year, it never gets old to hear about folks migrating to us.\nSo when Harold Smith, CEO and co-founder of [Monkton Incorporated](https://monkton.io/) – a company dedicated to helping enterprises build safe, secure, and compliant mobile solutions – wrote about [moving Monkton to GitLab](https://medium.com/@h3smith/migration-to-gitlab-dde59fc98315) earlier this year, we asked him to sit down with us to talk about the whys and hows.\n\n## From hodge podge of tools, to consolidated lifecycle\n\n\"We’ve been using some of your competitors’ tools.\nIt sort of became a hodge podge of tools – they’re still good tools, but there are different tools to do different things in the development life cycle. We had known GitLab had existed for a while.\nAnd I think, like many others who know about GitLab, it was an assumption on our end that it's just a source control repository.\nThen we started to realize and peel back a little bit of everything GitLab does – the continuous integration, integrations with other services, the whole pipeline.\nWe really started to focus on it and say, 'This is something we should spend time looking into and investing in.'\n\n\"It turned out to be a really good investment of time – we’ve seen time savings just in our ability to watch projects, our onboarding.\nIt’s cutting out a lot of the managing of all these different tools and different servers.\nIt’s just one thing to go in and manage that does most of the work we need.\nIt's also a huge advantage for us and our customers operating under the constraints of a higher-security environment, that we're able to do continuous integration and development, secure DevOps, in a secure environment that passes their auditing needs.\n\n>It’s cutting out a lot of the managing of all these different tools and different servers.\nIt’s just one thing to go in and manage that does most of the work we need.\n\n\"A lot of tools we were using, like some of the other continuous integration tools, are all open source software, which is great.\nBut that comes with some responsibilities: you need to really dig to figure out how to manage it correctly, how to set things up.\nSo, that was probably the biggest disadvantage of working with a collection of open source tools that didn’t have the proper documentation that we needed to move forward.\nSo, once we started looking at GitLab, it really enabled us to consolidate those things.\nAll the documentation is one place. The services that were available …\nIt was really easy to figure out what we needed to do.\nAnd your support has been a big help as well in enabling us to rapidly deliver and stand up these environments.\n\n\"Before, some of our processes were manual, like uploading code scans to Fortify.\nWe’ve automated all of that now on specific branches of the software that we’re building.\nSo, it’s taken out those manual processes that had to go through the checks.\nWhen we build a mobile application and push it through the pipeline, we’re working on how can we automatically publish that to MDM.\nSo, as soon as that code is checked in, scanned, what’s the process to get that into production?\nAnd that’s where we’ve focused a lot of effort of just entirely automation.\"\n\n## Automate all.the.things.\n\n\"Our collective vision within Monkton, and working with you at GitLab, and all these other companies, is how do we automate and take out human error from the equation?\nOur goal is that the moment code is checked in and has been reviewed, the testing lifecycle, the deployment lifecycle, the security vulnerability scanning lifecycle, should all be automated.\nSo, it’s more of humans reviewing reports at the end versus humans having to do the inspections themselves. We really envisioned that these tools could do a much better job than humans can.\n\n\"We’re not trying to replace human jobs. But how can we free people up to do what people do best, versus laborious efforts like pen testing mobile applications or pen testing web applications?\nA lot of that can be automated through scripting tools – Amazon Device Farm – all of which GitLab can automate and push out.\nSo, we’re focusing on what tools can we bring in to automate that process, tie them into GitLab, and automate everything. Or virtually everything.\"\n\n## Repeatability is key\n\n\"Repeatability is probably from our vantage point, one of the cornerstones of what we have to be able to do.\nIf we have a Department of Defense customer that builds a hundred mobile apps using our software, and they discover a vulnerability in one of them – if there’s not a repeatable process to build and deliver the solutions, it would take a year to update those hundred mobile apps if they’re doing it in a very siloed environment.\nBut with a repeatable process, they could change it out once and propagate it out, they can patch and push everything within an hour.\nA repeatable process allows you to have repeatable, consistent outcomes every single time, so you know that you can trust the process as part of your security program versus maybe a hodge podge of different tools and manual processes.\"\n\n## Lessons from the migration process\n\n\"It’s been a learning opportunity for us to see what are the best practices that we can collectively share – even with you at GitLab, there might be things that we’re all collectively learning, that we can use to help the community together.\nBecause this isn’t just a proprietary company effort on our end and your end, or even our customers’ end.\nI look at it as a good learning experience for all of us to improve processes, security, compliance, and everything that goes along with that.\"\n\nHere's a bit more from our chat with Harold:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/kT5qZ8W7yXM\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nVideo produced by [Aricka Flowers](/company/team/#arickaflowers)\n{: .note}\n",[266,9,693,2745],"user stories",{"slug":2747,"featured":6,"template":696},"monkton-moves-to-gitlab-customer-story","content:en-us:blog:monkton-moves-to-gitlab-customer-story.yml","Monkton Moves To Gitlab Customer Story","en-us/blog/monkton-moves-to-gitlab-customer-story.yml","en-us/blog/monkton-moves-to-gitlab-customer-story",{"_path":2753,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2754,"content":2760,"config":2766,"_id":2768,"_type":13,"title":2769,"_source":15,"_file":2770,"_stem":2771,"_extension":18},"/en-us/blog/mr-reviews-with-vs-code",{"title":2755,"description":2756,"ogTitle":2755,"ogDescription":2756,"noIndex":6,"ogImage":2757,"ogUrl":2758,"ogSiteName":683,"ogType":684,"canonicalUrls":2758,"schema":2759},"How to do GitLab merge request reviews in VS Code","Code review is critical to modern software development. We're making it easier by bringing merge request reviews right into VS Code.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749666775/Blog/Hero%20Images/cover.jpg","https://about.gitlab.com/blog/mr-reviews-with-vs-code","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to do GitLab merge request reviews in VS Code\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tomas Vik\"}],\n        \"datePublished\": \"2021-01-25\",\n      }",{"title":2755,"description":2756,"authors":2761,"heroImage":2757,"date":2763,"body":2764,"category":739,"tags":2765},[2762],"Tomas Vik","2021-01-25","\n\nThis post will give you an idea of how VS Code can aid your code review process. You'll get an overview of the features that GitLab VS Code Extension currently supports, as well as what we plan to introduce in the future.\n\nReviewing merge requests is a core part of GitLab: both the product (since [version 2.0.0](https://gitlab.com/gitlab-org/gitlab/blob/6a3621202e3f7274150862198f59d2579c326650/changelogs/archive.md#L7222), released in 2011) and the company. We recognize that certain review tasks are hard to do just by looking at the diff, and we strive to make them easier. One such task might be looking in the codebase for duplicated code or examples of a particular coding style.\n\nWe decided to aid code reviewers in two ways:\n\n## First way: The GitLab Web IDE\n\nFirst, we introduced the [Web IDE](/blog/introducing-gitlab-s-integrated-development-environment/), which helps our users work [with the codebase in the browser](/direction/create/ide/web_ide/#overview). You can quickly open multiple files, make changes, and commit them. The Web IDE is handy when you need to make a small change, or you don't have the project cloned locally.\n\nThe second way is more recent. We always wanted to bring the code review experience closer to code editors, where developers spend a large portion of their time. But the editor market is very fragmented (you find out the hard way if Emacs and Vim users meet at a party). And it isn't feasible to build GitLab support into all major editors (however, there are plenty of editor plugins maintained by the community[^1]). \n\n## Second way: Bringing code reviews into the editor\n\nRecently, as [VS Code gained a significant user share](https://insights.stackoverflow.com/survey/2019#development-environments-and-tools), it started to make sense to [commit to maintaining the GitLab VS Code extension](/blog/use-gitlab-with-vscode/), which was started as a community project by one, at the time, GitLab employee: [Fatih](https://gitlab.com/fatihacet). After an initial housekeeping period, we started chipping away tasks that will ultimately bring the code review experience into the editor.\n\nIn my previous post I talked about the great [VS Code Extension API](/blog/vscode-extension-development-with-gitlab/). This API gives extensions almost full control over the editor. When the API introduced commenting functionality two years ago, extensions could start contributing comments to the editor windows. These comments are shown similarly as comments on a Google Doc. Being able to natively show comments is perfect for reviewing code changes in the editor and other extensions that provide code reviews are already using this commenting API[^2].\n\n![Merge request review in VS Code](https://about.gitlab.com/images/blogimages/mr-reviews-with-vs-code/full-mr-review-screen.png){: .shadow.medium.center}\nMerge request review in VS Code\n{: .note .text-center}\n\nOver the last few milestones, we started showing MR changes in VS Code and even showing discussions on these. This means that you can open an MR in your editor and read through the code and comments without switching windows and context. I find this really useful because I can still interact with my editor the way I'm used to, even as I'm reviewing MRs. I can use full-text search to find if the MR duplicates existing code or I can open a different test file and compare whether the code style matches.\n\nCurrently, the interaction with MR is mostly read-only. That means you can see the changes and discussions, but you can't add or change comments, yet[^3]. But even in this current form, you can benefit from having the VS Code functionality so close to your review, especially for the initial understanding of the change.\n\n![VS Code supports Markdown in the comments](https://about.gitlab.com/images/blogimages/mr-reviews-with-vs-code/mr-review-long-comment.png){: .shadow.medium.center}\nVS Code supports Markdown in the comments\n{: .note .text-center}\n\n## What's next\n\nOver the next few milestones, we plan to make the commenting as interactive as you know it from the GitLab web interface. We'll start with editing existing comments, adding emoji reactions and resolving discussion threads. Lastly, we'll implement the full review functionality with creating comments and reviews[^4]. Each [iteration](https://handbook.gitlab.com/handbook/values/#iteration) will make the feature a bit more useful.\n\nI'm excited about the potential to stay in my editor for both creating and reviewing merge requests. I'm already using the current merge request review feature to get the initial understanding of what the MR tries to achieve. I can explore the related code more quickly in my editor. If you'd like to help us build the code review feature or just look at the current state of development, visit the [Merge Request Review epic](https://gitlab.com/groups/gitlab-org/-/epics/4607).\n\nYou can check out a walkthrough our initial proof of concept of merge request reviews in VS Code below:\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/kKA6i8oqZAA\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n[^1]: [IntelliJ](https://plugins.jetbrains.com/plugin/7447-gitlab-integration-plugin), [Atom](https://atom.io/packages/search?q=gitlab), [vim](https://github.com/shumphrey/fugitive-gitlab.vim), [Emacs](https://github.com/nlamirault/emacs-gitlab), ...\n[^2]: [Jira and Bitbucket](https://marketplace.visualstudio.com/items?itemName=Atlassian.atlascode), [GitHub Pull Requests and Issues](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github)\n[^3]: You can work around that by using the MR overview and commenting there.\n[^4]: [MR review: interacting with existing comments - POC](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/269) and [MR review: new comments and reviews POC](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/293) represent the initial investigation.\n\n[Cover image](https://art.ljubicapetkovic.com/cc-licensed/) by [Ljubica Petkovic](https://art.ljubicapetkovic.com), licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\n{: .note}\n",[975,9,807],{"slug":2767,"featured":6,"template":696},"mr-reviews-with-vs-code","content:en-us:blog:mr-reviews-with-vs-code.yml","Mr Reviews With Vs Code","en-us/blog/mr-reviews-with-vs-code.yml","en-us/blog/mr-reviews-with-vs-code",{"_path":2773,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2774,"content":2779,"config":2785,"_id":2787,"_type":13,"title":2788,"_source":15,"_file":2789,"_stem":2790,"_extension":18},"/en-us/blog/multi-account-aws-sam-deployments-with-gitlab-ci",{"title":2775,"description":2776,"ogTitle":2775,"ogDescription":2776,"noIndex":6,"ogImage":1132,"ogUrl":2777,"ogSiteName":683,"ogType":684,"canonicalUrls":2777,"schema":2778},"How to set up multi-account AWS SAM deployments with GitLab CI/CD","Our guest author, an AWS Serverless hero, shares how to automate SAM deployments using GitLab CI/CD.","https://about.gitlab.com/blog/multi-account-aws-sam-deployments-with-gitlab-ci","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to set up multi-account AWS SAM deployments with GitLab CI/CD\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Forrest Brazeal\"}],\n        \"datePublished\": \"2019-02-04\",\n      }",{"title":2775,"description":2776,"authors":2780,"heroImage":1132,"date":2782,"body":2783,"category":739,"tags":2784},[2781],"Forrest Brazeal","2019-02-04","I've been working with [serverless](/topics/serverless/) applications in AWS\nfor about three years – that makes me an old salt in serverless terms! So I\nknow that deploying and maintaining a serverless app can be tricky; the\ntooling often has critical gaps.\n\n\nAWS's [SAM (Serverless Application\nModel)](https://aws.amazon.com/serverless/sam/) is an open source framework\nthat makes it easier to define AWS resources – such as Lambda functions, API\nGateway APIs and DynamoDB tables – commonly used in serverless applications.\nOnce you lay out your app in a SAM template, the next thing you need is a\nconsistent, repeatable way to get that template off your laptop and deployed\nin the cloud.\n\n\nYou need CI/CD.\n\n\nI've used several different [CI/CD systems](/topics/ci-cd/) to automate SAM\ndeployments, and I always look for the following features:\n\n\n- A single deployment pipeline that can build once and securely deploy to\nmultiple AWS accounts (dev, staging, prod).\n\n- Dynamic feature branch deployments, so serverless devs can collaborate in\nthe cloud without stepping on each other.\n\n- Automated cleanup of feature deployments.\n\n- Review of our SAM application directly integrated with the CI/CD tool's\nuser interface.\n\n- Manual confirmation before code is released into production.\n\n\nIn this post, we'll find out how [GitLab\nCI](/solutions/continuous-integration/) can check these boxes on its way to\ndelivering effective CI/CD for AWS SAM. You can follow along using [the\nofficial example code, available\nhere](https://gitlab.com/gitlab-examples/aws-sam).\n\n\n## Multi-account AWS deployments\n\n\nWe'll want to set up our deployment pipeline across multiple AWS accounts,\nbecause accounts are the only true security boundary in AWS. We don't want\nto run any risk of deploying prod data in dev, or vice versa. Our\nmulti-account setup will look something like this:\n\n\nAny time we work with multiple AWS accounts, we need cross-account [IAM\nroles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) in\norder to authorize deployments. We'll handle this task through the following\nsteps. (All referenced scripts are available in the [example\nrepo](https://gitlab.com/gitlab-examples/aws-sam))\n\n\n### 1\\. Establish three AWS accounts for development, staging, and\nproduction deployments\n\n\nYou can use existing AWS accounts if you have them, or [provision new ones\nunder an AWS\nOrganization](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_create.html).\n\n\n### 2\\. Set up GitLab IAM roles in each account\n\n\nRun the following AWS CLI call with admin credentials in each of the three\naccounts:\n\n\n```\n\naws cloudformation deploy --stack-name GitLabCIRoles --template-file\nsetup-templates/roles.yml --capabilities CAPABILITY_NAMED_IAM\n--parameter-overrides CIAccountID=\"\u003CAWS Account ID where your GitLab CI/CD\nrunner lives>\" CIAccountSTSCondition=\"\u003CThe aws:userid for the IAM principal\nused by the Gitlab runner>\"\n  ```\n\nReplace `CIAccountID` and `CIAccountSTSCondition` as indicated with values\nfrom the AWS account where your GitLab CI/CD runner exists. (Need help\nfinding the `aws:userid` for your runner’s IAM principal? Check out [this\nguide](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable).)\n\n\nThis CloudFormation template defines two roles: `SharedServiceRole` and\n`SharedDeploymentRole`. The `SharedServiceRole` is assumed by the GitLab\nCI/CD runner when calling the AWS CloudFormation service. This role trusts\nthe GitLab CI/CD runner's role. It has permissions to call the\nCloudFormation service, pass a role via IAM, and access S3 and CloudFront:\nnothing else. This role is not privileged enough to do arbitrary AWS\ndeployments on its own.\n\n\nThe `SharedDeploymentRole`, on the other hand, has full administrative\naccess to perform any AWS action. A such, it cannot be assumed directly by\nthe GitLab CI/CD runner. Instead, this role must be \"passed\" to\nCloudFormation using the service's `RoleArn` parameter. The CloudFormation\nservice trusts the `SharedDeploymentRole` and can use it to deploy whatever\nresources are needed as part of the pipeline.\n\n\n### 3\\. Create an S3 bucket for CI artifacts\n\n\nGrab the AWS account ID for each of your development, staging, and\nproduction accounts, then deploy this CloudFormation template **in the\naccount where your GitLab CI/CD Runner exists**:\n\n\n`aws cloudformation deploy --stack-name GitLabCIBucket --template-file\nsetup-templates/ci-bucket.yml --parameter-overrides DevAwsAccountId=\"\u003CAWS\nAccount ID for dev>\" StagingAwsAccountId=\"\u003CAWS Account ID for staging>\"\nProdAwsAccountId=\"\u003CAWS Account ID for prod>\" ArtifactBucketName=\"\u003CA unique\nname for your bucket>\"`\n\n\nThis CloudFormation template creates a centralized S3 bucket which holds the\nartifacts created during your pipeline run. Artifacts are created once for\neach branch push and reused between staging and production. The bucket\npolicy allows the development, test, and production accounts to reference\nthe same artifacts when deploying CloudFormation stacks -- checking off our\n\"build once, deploy many\" requirement.\n\n\n### 4\\. Assume the `SharedServiceRole` before making any cross-account AWS\ncalls\n\nWe have provided the script `assume-role.sh`, which will assume the provided\nrole and export temporary AWS credentials to the current shell. It is\nsourced in the various `.gitlab-ci.yml` build scripts.\n\n\n## Single deployment pipeline\n\n\nThat brings us to the `.gitlab-ci.yml` file you can see at the root of our\nexample repository. GitLab CI/CD is smart enough to dynamically create and\nexecute the pipeline based on that template when we push code to GitLab. The\nfile has a number of variables at the top that you can tweak based on your\nenvironment specifics.\n\n\n### Stages\n\n\nOur Gitlab CI/CD pipeline contains seven possible stages, defined as\nfollows:\n\n\n![Multi-account AWS SAM deployment model with GitLab\nCI](https://about.gitlab.com/images/blogimages/multi-account-aws-sam/deployment-model.png){:\n.shadow.medium.center}\n\n\n```yaml\n\nstages:\n - test\n - build-dev\n - deploy-dev\n - build-staging\n - deploy-staging\n - create-change-prod\n - execute-change-prod\n```\n\n\n![Deployment lifecycle\nstages](https://about.gitlab.com/images/blogimages/multi-account-aws-sam/deployment-lifecycle-stages.png){:\n.shadow.medium.center}\n\n\n\"Stages\" are used as a control flow mechanism when building the pipeline.\nMultiple build jobs within a stage will run in parallel, but all jobs in a\ngiven stage must complete before any jobs belonging to the next stage in the\nlist can be executed.\n\n\nAlthough seven stages are defined here, only certain ones will execute,\ndepending on what kind of Git action triggered our pipeline. We effectively\nhave three stages to any deployment: a \"test\" phase where we run unit tests\nand dependency scans against our code, a \"build\" phase that packages our SAM\ntemplate, and a \"deploy\" phase split into two parts: creating a\n[CloudFormation change\nset](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html)\nand then executing that change set in the target environment.\n\n\n#### Test\n\n\nOur `.gitlab-ci.yml` file currently runs two types of tests: unit tests\nagainst our code, and dependency scans against our third-party Python\npackages.\n\n\n##### Unit tests\n\n\nUnit tests run on every branch pushed to the remote repository. This\nbehavior is defined by the `only: branches` property in the job shown below:\n\n\n```yaml\n\ntest:unit:\n stage: test\n only:\n   - branches\n script: |\n   if test -f requirements.txt; then\n       pip install -r requirements.txt\n   fi\n   python -m pytest --ignore=functions/\n```\n\n\nEvery GitLab CI/CD job runs a script. Here, we install any dependencies,\nthen execute Python unit tests.\n\n\n##### Dependency scans\n\n\n[Dependency\nscans](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/),\nwhich can take a few minutes, run only on code pushed to the master branch;\nit would be counterproductive for developers to wait on them every time they\nwant to test code.\n\n\nThese scans use a hardcoded, standard Docker image to mount the code and run\n\"Docker in Docker\" checks against a database of known package\nvulnerabilities. If a vulnerability is found, the pipeline will log the\nerror without stopping the build (that's what the `allow-failure: true`\nproperty does).\n\n\n#### Build\n\n\nThe build stage turns our SAM template into CloudFormation and turns our\nPython code into a valid AWS Lambda deployment package. For example, here's\nthe `build:dev` job:\n\n\n```yaml\n\nbuild:dev:\n stage: build-dev\n \u003C\u003C: *build_script\n variables:\n   \u003C\u003C: *dev_variables\n artifacts:\n   paths:\n     - deployment.yml\n   expire_in: 1 week\n only:\n   - branches\n except:\n   - master\n```\n\n\nWhat's going on here? Note first the combination of `only` and `except`\nproperties to ensure that our development builds happen only on pushes to\nbranches that aren't `master`. We're referring to `dev_variables`, the set\nof development-specific variables defined at the top of `.gitlab-ci.yml`.\nAnd we're running a script, pointed to by `build_script`, which packages our\nSAM template and code for deployment using the `aws cloudformation package`\nCLI call.\n\n\nThe artifact `deployment.yml` is the CloudFormation template output by our\npackage command. It has all the implicit SAM magic expanded into\nCloudFormation resources. By managing it as an artifact, we can pass it\nalong to further steps in the build pipeline, even though it isn't committed\nto our repository.\n\n\n#### Deploy\n\nOur deployments use AWS CloudFormation to deploy the packaged application in\na target AWS environment.\n\n\nIn development and staging environments, we use the `aws cloudformation\ndeploy` command to create a change set and immediately execute it. In\nproduction, we put a manual \"wait\" in the pipeline at this point so you have\nthe opportunity to review the change set before moving onto the \"Execute\"\nstep, which actually calls `aws cloudformation execute-changeset` to update\nthe underlying stack.\n\n\nOur deployment jobs use a helper script, committed to the top level of the\nexample repository, called `cfn-wait.sh`. This script is needed because the\n`aws cloudformation` commands don't wait for results; they report success as\nsoon as the stack operation starts. To properly record the deployment\nresults in our job, we need a script that polls the CloudFormation service\nand throws an error if the deployment or update fails.\n\n\n## Dynamic feature branch deployments and Review Apps\n\n\n![Dynamic feature branch deployments and Review\nApps](https://about.gitlab.com/images/blogimages/multi-account-aws-sam/dynamic-feature-branch-deployments.png){:\n.shadow.medium.center}\n\n\nWhen a non-master branch is pushed to GitLab, our pipeline runs tests,\nbuilds the [updated source\ncode](/solutions/source-code-management/), and deploys and/or\nupdates the changed CloudFormation resources in the development AWS account.\nWhen the branch is merged into master, or if someone clicks the \"Stop\"\nbutton next to the branch's environment in GitLab CI, the CloudFormation\nstack will be torn down automatically.\n\n\nIt is perfectly possible, and indeed desirable, to have multiple development\nfeature branches simultaneously deployed as live environments for more\nefficient parallel feature development and QA. The serverless model makes\nthis a cost-effective strategy for collaborating in the cloud.\n\n\nIf we are dynamically deploying our application on every branch push, we\nmight like to view it as part of our interaction with the GitLab console\n(such as during a code review). GitLab supports this with a nifty feature\ncalled [Review Apps](https://docs.gitlab.com/ee/ci/review_apps/). Review\nApps allow you to specify an \"environment\" as part of a deployment job, as\nseen in our `deploy:dev` job below:\n\n\n```yaml\n\ndeploy:dev:\n \u003C\u003C: *deploy_script\n stage: deploy-dev\n dependencies:\n   - build:dev\n variables:\n   \u003C\u003C: *dev_variables\n environment:\n   name: review/$CI_COMMIT_REF_NAME\n   url: https://${CI_COMMIT_REF_NAME}.${DEV_HOSTED_ZONE_NAME}/services\n   on_stop: stop:dev\n only:\n   - branches\n except:\n   - master\n```\n\n\nThe link specified in the `url` field of the `environment` property will be\naccessible in the `Environments` section of GitLab CI/CD or on any merge\nrequest of the associated branch. (In the case of the sample SAM application\nprovided with our example, since we don't have a front end to view, the link\njust takes you to a GET request for the `/services` API endpoint and should\ndisplay some raw JSON in your browser.)\n\n\n![Link to live\nenvironment](https://about.gitlab.com/images/blogimages/multi-account-aws-sam/link-live-environment.png){:\n.shadow.medium.center}\n\n\nThe `on_stop` property specifies what happens when you \"shut down\" the\nenvironment in GitLab CI. This can be done manually or by deleting the\nassociated branch. In the case above, we have stopped behavior for dev\nenvironments linked to a separate job called `stop:dev`:\n\n\n```yaml\n\nstop:dev:\n stage: deploy-dev\n variables:\n   GIT_STRATEGY: none\n   \u003C\u003C: *dev_variables\n \u003C\u003C: *shutdown_script\n when: manual\n environment:\n   name: review/$CI_COMMIT_REF_NAME\n   action: stop\n only:\n   - branches\n except:\n   - master\n```\n\n\nThis job launches the `shutdown_script` script, which calls `aws\ncloudformation teardown` to clean up the SAM deployment.\n\n\nFor safety's sake, there is no automated teardown of staging or production\nenvironments.\n\n\n## Production releases\n\n\n![Production\nreleases](https://about.gitlab.com/images/blogimages/multi-account-aws-sam/production-releases.png){:\n.shadow.medium.center}\n\n\nWhen a change is merged into the master branch, the code is built, tested\n(including dependency scans) and deployed to the staging environment. This\nis a separate, stable environment that developers, QA, and others can use to\nverify changes before attempting to deploy in production.\n\n\n![Staging\nenvironment](https://about.gitlab.com/images/blogimages/multi-account-aws-sam/staging-environment.png){:\n.shadow.medium.center}\n\n\nAfter deploying code to the staging environment, the pipeline will create a\nchange set for the production stack, and then pause for a manual\nintervention. A human user must click a button in the Gitlab CI/CD\n\"Environments\" view to execute the final change set.\n\n\n## Now what?\n\n\nStep back and take a deep breath – that was a lot of information! Let's not\nlose sight of what we've done here: we've defined a secure, multi-account\nAWS deployment pipeline in our GitLab repo, integrated tests, builds and\ndeployments, and successfully rolled a SAM-defined serverless app to the\ncloud. Not bad for a few lines of config!\n\n\nThe next step is to try this on your own. If you'd like to start with our\nsample \"AWS News\" application, you can simply run `sam init --location\ngit+https://gitlab.com/gitlab-examples/aws-sam` to download the project on\nyour local machine. The AWS News app contains a stripped-down,\nsingle-account version of the `gitlab-ci.yml` file discussed in this post,\nso you can try out deployments with minimal setup needed.\n\n\n## Further reading\n\n\nWe have barely scratched the surface of GitLab CI/CD and AWS SAM in this\npost. Here are some interesting readings if you would like to take your work\nto the next level:\n\n\n### SAM\n\n\n- [Implementing safe AWS Lambda deployments with AWS SAM and\nCodeDeploy](https://aws.amazon.com/blogs/compute/implementing-safe-aws-lambda-deployments-with-aws-codedeploy/)\n\n- [Running and debugging serverless applications locally using the AWS SAM\nCLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-test-and-debug.html)\n\n\n### GitLab CI\n\n\n- [Setting up a GitLab Runner on\nEC2](https://hackernoon.com/configuring-gitlab-ci-on-aws-ec2-using-docker-7c359d513a46)\n\n- [Scheduled\npipelines](https://docs.gitlab.com/ee/ci/pipelines/schedules.html)\n\n- [ChatOps](https://docs.gitlab.com/ee/ci/chatops/)\n\n\nPlease [let me know](https://twitter.com/forrestbrazeal) if you have further\nquestions!\n\n\n### About the guest author\n\n\nForrest Brazeal is an [AWS Serverless\nHero](https://aws.amazon.com/developer/community/heroes/forrest-brazeal/).\nHe currently works as a senior cloud architect at\n[Trek10](https://trek10.com), an AWS Advanced Consulting Partner. You can\n[read more about Trek10's GitLab journey here](/customers/trek10/).\n",[108,1408,9,693,2288,2745],{"slug":2786,"featured":6,"template":696},"multi-account-aws-sam-deployments-with-gitlab-ci","content:en-us:blog:multi-account-aws-sam-deployments-with-gitlab-ci.yml","Multi Account Aws Sam Deployments With Gitlab Ci","en-us/blog/multi-account-aws-sam-deployments-with-gitlab-ci.yml","en-us/blog/multi-account-aws-sam-deployments-with-gitlab-ci",{"_path":2792,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2793,"content":2799,"config":2804,"_id":2806,"_type":13,"title":2807,"_source":15,"_file":2808,"_stem":2809,"_extension":18},"/en-us/blog/netlify-launches-gitlab-support",{"title":2794,"description":2795,"ogTitle":2794,"ogDescription":2795,"noIndex":6,"ogImage":2796,"ogUrl":2797,"ogSiteName":683,"ogType":684,"canonicalUrls":2797,"schema":2798},"Netlify CMS launches support for GitLab","Make it even easier to bring developers and content creators together, so everyone can contribute.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671196/Blog/Hero%20Images/gitlab-netlify-cover.png","https://about.gitlab.com/blog/netlify-launches-gitlab-support","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Netlify CMS launches support for GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2018-06-13\",\n      }",{"title":2794,"description":2795,"authors":2800,"heroImage":2796,"date":2801,"body":2802,"category":298,"tags":2803},[1790],"2018-06-13","\n\nMaking it possible that “[everyone can contribute](/company/mission/#mission)” is our mission, and any development that brings us closer to it is great news! That’s why we’re happy to tell you that open source content management system [Netlify CMS](https://www.netlify.com/) is [launching support for GitLab as a back end](https://www.netlifycms.org/blog/2018/06/netlify-cms-now-supports-gitlab-as-a-backend/) today.\n\nAs more developers move to static site generators to pre-build their site’s front end for a more reliable, secure, and fast site experience, it’s important that other team members are empowered to contribute to site content easily. While [all GitLab team-members learn to contribute to this very site using GitLab itself](/blog/people-ops-using-gitlab/), most non-technical folks are accustomed to a CMS with a familiar user interface and a WYSIWYG. A simple UI wrapper for your Git repository, Netlify CMS automatically syncs all content edits made through its UI to the repository, so changes are treated in exactly the same way as code (including versioning, rollbacks, continuous deployment, and so on).\n\nThis is one of Netlify CMS’ most highly requested integrations, so much so that the plan to make it happen it is responsible for their project’s single largest contributor coming on board! GitLab users can now take advantage of the integration to simplify publishing with any SSG. Check out how it works:\n\n![Netlify CMS GitLab integration demo](https://about.gitlab.com/images/blogimages/gitlab-netlifycms-gif.gif){: .shadow.medium.center}\n\n1. An editor makes a change in the Netlify CMS\n2. That change automatically syncs to your GitLab repository\n3. And that action triggers a build to your published site\n\nReady to give it a spin? The easiest way to get started is to click on the button below: it'll automatically deploy a Netlify CMS template to a GitLab repository. It's prepackaged with the Hugo static site generator and deploys to Netlify so you can see a real, working site right away. You can also check out [the documentation](https://www.netlifycms.org/docs/start-with-a-template/). Enjoy!\n\n\u003Ca href=\"https://app.netlify.com/start/deploy?repository=https://gitlab.com/netlify-templates/one-click-hugo-cms&stack=cms\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">\u003Cimg src=\"https://www.netlify.com/img/deploy/button.svg\" alt=\"Deploy to Netlify\">\u003C/a>\n",[9,693],{"slug":2805,"featured":6,"template":696},"netlify-launches-gitlab-support","content:en-us:blog:netlify-launches-gitlab-support.yml","Netlify Launches Gitlab Support","en-us/blog/netlify-launches-gitlab-support.yml","en-us/blog/netlify-launches-gitlab-support",{"_path":2811,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2812,"content":2817,"config":2823,"_id":2825,"_type":13,"title":2826,"_source":15,"_file":2827,"_stem":2828,"_extension":18},"/en-us/blog/new-default-container-image-gitlab-saas-linux-runnners",{"title":2813,"description":2814,"ogTitle":2813,"ogDescription":2814,"noIndex":6,"ogImage":1501,"ogUrl":2815,"ogSiteName":683,"ogType":684,"canonicalUrls":2815,"schema":2816},"Using Ruby 3.1 as default on GitLab SaaS Linux runners","Learn about the new image and how to ensure CI job compatibility.","https://about.gitlab.com/blog/new-default-container-image-gitlab-saas-linux-runnners","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to use Ruby 3.1 as the default container image on GitLab SaaS Runners on Linux\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Darren Eastman\"}],\n        \"datePublished\": \"2022-12-13\",\n      }",{"title":2818,"description":2814,"authors":2819,"heroImage":1501,"date":2820,"body":2821,"category":739,"tags":2822},"How to use Ruby 3.1 as the default container image on GitLab SaaS Runners on Linux",[1506],"2022-12-13","\nOn January 12, 2023, we will change the [default container](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html) image used on GitLab Saas Runners on Linux from Ruby 2.5, which is end of life, to Ruby 3.1.\n\nIf you have specified a container image in your CI/CD job, then there is no impact to you. In other words, your GitLab SaaS CI/CD job will only run in the default container if no image is set for the job in the `.gitlab-ci.yml` pipeline file.\n\nTo check, open the log view of a CI job and note the image used. For example, if you have not added an image to your CI job on GitLab SaaS, then the job log will have the following:\n\n```\nUsing Docker executor with image ruby:2.5 ...\n\n```\n\nIf you have not set a container image in your CI job, then after this change, the job will run in a Ruby 3.1 container.\n\n## How can I check for any build issues on Ruby 3.1?\n\nWhile it is not expected that running a CI/CD job on Ruby 2.5 is incompatible with Ruby 3.1, to check, simply configure the job to run in a Ruby 3.1 container. To do so, edit the `.gitlab-ci.yml` and add the following:\n\n```\ndefault:\n  image: ruby:3.1\n```\n\n## Future plans\n\nIn addition to this change, we plan to [define](https://gitlab.com/gitlab-org/gitlab/-/issues/384992) a new container image maintenance process for GitLab SaaS Runners on Linux. The new policy aims to ensure that the default image used is updated so that it contains the latest security fixes.\n\n_This blog post and linked pages contain information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. As with all projects, the items mentioned in this blog post and linked pages are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc._\n\n",[851,1161,785,2168,9],{"slug":2824,"featured":6,"template":696},"new-default-container-image-gitlab-saas-linux-runnners","content:en-us:blog:new-default-container-image-gitlab-saas-linux-runnners.yml","New Default Container Image Gitlab Saas Linux Runnners","en-us/blog/new-default-container-image-gitlab-saas-linux-runnners.yml","en-us/blog/new-default-container-image-gitlab-saas-linux-runnners",{"_path":2830,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2831,"content":2835,"config":2840,"_id":2842,"_type":13,"title":2843,"_source":15,"_file":2844,"_stem":2845,"_extension":18},"/en-us/blog/next-generation-container-registry",{"title":2832,"description":1520,"ogTitle":2832,"ogDescription":1520,"noIndex":6,"ogImage":884,"ogUrl":2833,"ogSiteName":683,"ogType":684,"canonicalUrls":2833,"schema":2834},"Introducing the next generation of the GitLab.com Container Registry","https://about.gitlab.com/blog/next-generation-container-registry","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Introducing the next generation of the GitLab.com Container Registry\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Rizzi\"}],\n        \"datePublished\": \"2022-04-12\",\n      }",{"title":2832,"description":1520,"authors":2836,"heroImage":884,"date":2837,"body":2838,"category":763,"tags":2839},[1525],"2022-04-12","\n\n_This blog post and linked pages contain information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. As with all projects, the items mentioned in this blog post and linked pages are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc._\n\nIn the coming weeks, we will begin the second phase of the rollout of the new version of the Container Registry on GitLab.com. Prior to deploying this update, we wanted to clearly communicate the planned changes, what to expect, and why we are excited.\n\nIf you have any questions or concerns, please don't hesitate to comment in the [epic](https://gitlab.com/groups/gitlab-org/-/epics/5523).\n\n## Context \n\nIn [Milestone 8.8](/releases/2016/05/22/gitlab-8-8-released/), GitLab launched the MVC of the Container Registry. This feature integrated the Docker Distribution registry into GitLab so that any GitLab user could have a space to publish and share container images.\n\nBut there was an inherent limitation with Docker Distribution, as all metadata associated with a given image/tag was stored in the object storage backend. This made using that metadata to build API features (like storage usage visibility, sorting, and filtering) unfeasible. The most recent Container Registry update added a new PostgreSQL backend, which is used to store the metadata. Additionally, this new version also includes an automatic online garbage collector to remove untagged images and recover storage space.\n\nIn November 2021, we started [phase 1](/blog/gitlab-com-container-registry-update/) of the migration. This completed in January 2022 without any significant issues. Since then, every new image repository pushed to GitLab.com uses the new, metadata database-backed registry. Today, nearly 20% of Container Registry traffic is already routed to the new version.\n\nNow we are ready to begin [Phase 2 of the migration](https://gitlab.com/gitlab-org/container-registry/-/issues/374#phase-2-migrate-existing-repositories). This will migrate image repositories created before January 22, 2022, to the new Container Registry. Once complete, we can unblock many of the features that you've been asking for.\n\n## Why we are excited \n\n- [Storage visibility for the Container Registry](https://gitlab.com/groups/gitlab-org/-/epics/7225)\n\n- Performance improvements for list operations when using the GitLab API and UI\n\n- [Redesign of the UI](https://gitlab.com/groups/gitlab-org/-/epics/3211)\n  - [Build and commit metadata for tags built via CI](https://gitlab.com/gitlab-org/gitlab/-/issues/197996)\n  - [Search by tag name](https://gitlab.com/gitlab-org/gitlab/-/issues/255614)\n  \n- [Resolve: Group/project path updates break the Container Registry](https://gitlab.com/gitlab-org/gitlab/-/issues/18383)\n\n## The plan \n\nWe're planning a [phased migration](https://gitlab.com/gitlab-org/container-registry/-/issues/374#phase-2-migrate-existing-repositories), starting with GitLab.org repositories. After that, we'll move on to the Free tier, then on to Premium and Ultimate. We'll roll this out incrementally to maintain safety for customers and provide our team with an opportunity to identify and address any concerns.\n\n## Timing \n\nMigration begins: April 18th, 2022\nMigration ends: July 8th, 2022.\n\nTentative dates by tier:\n\n- GitLab internal projects: April 14 - April 18\n- Free: April 18 - May 18\n- Premium: May 18 to June 18\n- Ultimate: June 18 to July 8\n\nFor more information about the planned, percentage-based rollout, please refer to this [epic](https://gitlab.com/groups/gitlab-org/-/epics/6427).\n\n## What to expect\n\n- For each repository, the migration will only target _tagged_ images. Untagged and unreferenced manifests, and the layers they reference, will be left behind and become inaccessible. Untagged images were never visible through the GitLab UI or API, but they were left behind in the backend after becoming dangling.\n\n- Once migrated to the new registry, repositories will be subject to continuous online garbage collection, deleting any untagged and unreferenced manifests and layers that remain as such for longer than 24 hours.\n\n- To ensure data consistency, the migration of each repository requires the enforcement of a small read-only period at the very end. This period is expected to be less than ten seconds for the vast majority of repositories. During this period, an error message will be returned when trying to upload or delete data, prompting clients to try again. Most clients, will automatically retry several times, which should eventually succeed as the read-only enforcement lifts. We also put a mechanism in place to automatically cancel and reschedule migrations that are taking longer than expected. Nevertheless, if you experience any issues, please comment in the [epic](https://gitlab.com/groups/gitlab-org/-/epics/5523).\n\n## FAQ \n\n- Do I need to do anything?\n  - No, the process is fully automated. But if you have any untagged images that you'd like to preserve, please be sure to tag them as soon as possible.\n\n- Is there anything I can do to help? \n  - Yes! Although no action is necessary, we recommend activating the Container Registry [cleanup policies](https://docs.gitlab.com/ee/user/packages/container_registry/#cleanup-policy) for any relevant projects.\n\n- Is the update required? \n  - Yes. With this change, we can deliver a more modern and scalable product. You don't want to miss out on those features!\n",[851,1161,9],{"slug":2841,"featured":6,"template":696},"next-generation-container-registry","content:en-us:blog:next-generation-container-registry.yml","Next Generation Container Registry","en-us/blog/next-generation-container-registry.yml","en-us/blog/next-generation-container-registry",{"_path":2847,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2848,"content":2854,"config":2858,"_id":2860,"_type":13,"title":2861,"_source":15,"_file":2862,"_stem":2863,"_extension":18},"/en-us/blog/one-click-clone-to-xcode",{"title":2849,"description":2850,"ogTitle":2849,"ogDescription":2850,"noIndex":6,"ogImage":2851,"ogUrl":2852,"ogSiteName":683,"ogType":684,"canonicalUrls":2852,"schema":2853},"Announcing GitLab one-click clone to Xcode","GitLab's Xcode integration allows you to clone repos to Xcode with a single click!","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680081/Blog/Hero%20Images/apple-xcode-cover.jpg","https://about.gitlab.com/blog/one-click-clone-to-xcode","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Announcing GitLab one-click clone to Xcode\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"William Chia\"}],\n        \"datePublished\": \"2018-06-06\",\n      }",{"title":2849,"description":2850,"authors":2855,"heroImage":2851,"date":1138,"body":2856,"category":298,"tags":2857},[1137],"\n\nYesterday at WWDC, [Apple announced our Xcode integration with GitLab](https://twitter.com/gitlab/status/1003764673454342144), which makes it easier to work with your Xcode projects hosted in GitLab.\n\nProjects that contain a `.xcodeproj` or `.xcworkspace` file can now be cloned in Xcode using the new **Open in Xcode** button in GitLab. When viewing Xcode projects in the GitLab interface, the button will be available in GitLab next to the Git URL for cloning your project.\n\n![Open in Xcode Button](https://about.gitlab.com/images/blogimages/open-in-xcode-button.png){: .shadow.medium.center}\n\nThe button is available on GitLab.com, and will be available to self-managed GitLab instances in GitLab 11.0 from June 22, 2018. The button works with Xcode 9 and above.\n\nBe on the lookout as we have even more enhancements on the way with GitLab 11.0.\n",[9,763],{"slug":2859,"featured":6,"template":696},"one-click-clone-to-xcode","content:en-us:blog:one-click-clone-to-xcode.yml","One Click Clone To Xcode","en-us/blog/one-click-clone-to-xcode.yml","en-us/blog/one-click-clone-to-xcode",{"_path":2865,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2866,"content":2872,"config":2878,"_id":2880,"_type":13,"title":2881,"_source":15,"_file":2882,"_stem":2883,"_extension":18},"/en-us/blog/optimize-gitops-workflow",{"title":2867,"description":2868,"ogTitle":2867,"ogDescription":2868,"noIndex":6,"ogImage":2869,"ogUrl":2870,"ogSiteName":683,"ogType":684,"canonicalUrls":2870,"schema":2871},"Optimize GitOps workflow with version control from GitLab","A GitOps workflow improves development, operations and business processes and GitLab’s CI plays a vital role.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749673081/Blog/Hero%20Images/gitops-image-unsplash.jpg","https://about.gitlab.com/blog/optimize-gitops-workflow","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Optimize GitOps workflow with version control from GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brein Matturro\"}],\n        \"datePublished\": \"2019-10-28\",\n      }",{"title":2867,"description":2868,"authors":2873,"heroImage":2869,"date":2875,"body":2876,"category":691,"tags":2877},[2874],"Brein Matturro","2019-10-28","\nGitOps is a way for IT operations to manage changes across infrastructure and development teams. At GitLab\nConnect in Denver, [Tyler Sparks](https://www.linkedin.com/in/sparksconcept/), principal engineer and\nowner of Sparks Concept, presented a talk on why GitOps is a productive workflow and how\nusing GitLab can increase communication and version control.\n\n[GitOps](/topics/gitops/) uses infrastructure as code but with processes in place on top of it, including extensive use of\nmerge requests for everything from policy to infrastructure changes. “Success for most companies and\nengineering groups is based on the interactions of a large, complex, distributed system,” Tyler says.\nThe goal of GitOps is to incorporate Git beyond development and operations teams, improving the\nbusiness as a whole with the right tool. “It's a really cool way that GitLab integrates and it's a way to\nshift things left in your organization.”\n\n## The Git in GitOps\n\n“Git is the single source of truth. You shouldn’t be able to make any change outside of Git,” Tyler says. This creates one clean transaction between teams. Git establishes a unified location for anything from security, infrastructure changes, deployments, process changes, and even the integration of other tools. “Git is serving as the glue to make these safe transitions so that you can move faster as a team,” Tyler says.\n\nCreating that interaction between groups is often elaborate and difficult to manage. “Anyone building software these days is finding it more and more complex...everything is changing, the landscape is constantly changing,” Tyler says. Services are being run on stacks upon stacks and there is a lot of risk involved in maintenance. A tool, like [GitLab CI](/solutions/continuous-integration/), simplifies the processes and grants visibility.\n\n## GitOps best practices\n\nIn a GitOps workflow, where one simple change can impact three different teams, a strong [version control is imperative for communication](/topics/version-control/). Between disparate tools and poorly defined handoffs, the solution is to move into one repository for all tools and teams. With one overarching repository, “You can have a bunch of parallel workstreams running safely… you will have minimum viable change and a way to observe it,” Tyler says.\n\nWith GitLab’s version control system in place, teams can see what’s going on to work together and to know what change is going to impact where. “GitLab CI is one of the original products that made it possible to start to take an integrative view of the system,” Tyler says. “This is the penultimate way to [promote collaboration](/topics/gitops/gitops-gitlab-collaboration/) and to break down silos within an organization. GitLab is a tool that helps with that.”\n\nGitLab’s version control not only safeguards the infrastructure, but ultimately trickles throughout the entire enterprise. “As companies adopt GitLab, they’re not just more successful with their technology...it really comes down to how they’re functioning as a group,” Tyler says. “GitLab encourages some really good practices around development and how teams interact.”\n\n>“That’s why GitLab is the clear winner...They’re not just leading Gartner and Forrester because they paid somebody off. They’re actually an amazing tool.” Tyler Sparks, principal engineer and owner of Sparks Concept\n\nLearn more about GitOps best practices and Tyler’s work with GitLab CI in his presentation below:\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/5ykRuaZvY-E\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\nCover image by [David Rangel](https://unsplash.com/@rangel) on [Unsplash](https://unsplash.com)\n{: .note}\n",[2048,2128,9,2745],{"slug":2879,"featured":6,"template":696},"optimize-gitops-workflow","content:en-us:blog:optimize-gitops-workflow.yml","Optimize Gitops Workflow","en-us/blog/optimize-gitops-workflow.yml","en-us/blog/optimize-gitops-workflow",{"_path":2885,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2886,"content":2892,"config":2898,"_id":2900,"_type":13,"title":2901,"_source":15,"_file":2902,"_stem":2903,"_extension":18},"/en-us/blog/postman-integration-with-gitlab-makes-your-api-workflows-easier",{"title":2887,"description":2888,"ogTitle":2887,"ogDescription":2888,"noIndex":6,"ogImage":2889,"ogUrl":2890,"ogSiteName":683,"ogType":684,"canonicalUrls":2890,"schema":2891},"Postman integration with GitLab makes API workflows easier","Learn how to use the git integration to link APIs in Postman to GitLab cloud repos.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671434/Blog/Hero%20Images/introducing-continuous-workflows.jpg","https://about.gitlab.com/blog/postman-integration-with-gitlab-makes-your-api-workflows-easier","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Postman integration with GitLab makes API workflows easier\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Andy Rogers\"}],\n        \"datePublished\": \"2022-08-24\",\n      }",{"title":2887,"description":2888,"authors":2893,"heroImage":2889,"date":2895,"body":2896,"category":739,"tags":2897},[2894],"Andy Rogers","2022-08-24","\n\nAPIs are more than just an interface. From a development lifecycle perspective, an API includes source code, definition files, tests, performance measurements, documentation, security audits, deployments, and feedback from API consumers. All of these elements are required for a successful API implementation. So, in partnership with GitLab, Postman created a git integration that allows users to link APIs in Postman to their GitLab cloud repos (on-prem versions of GitLab are only supported on [Postman Enterprise](https://www.postman.com/pricing/)).\n\nThe [Postman API Platform](https://blog.postman.com/new-postman-api-platform-redefining-api-management-for-api-first-world/) is designed to help teams collaborate seamlessly by providing tools for the entire API lifecycle. We understand that a fundamental part of the API lifecycle includes [developer workflows](https://blog.postman.com/the-reimagined-api-first-workflow-for-developers/) centered around code and source control.\n\n![illustration](https://about.gitlab.com/images/blogimages/postman1.png){: .shadow}\n\n## 4 key benefits for better collaboration\n\nThe launch of this integration earlier in the year provides four key benefits that empower teams to work faster and better together:\n\n**1.** It introduces the concept of version control into Postman. Users are now able to manage and sync branches, releases, versions, and tags for their APIs in GitLab and Postman. \n\n\n![screenshot of drop-down menu](https://about.gitlab.com/images/blogimages/postman2.png){: .shadow}\n\n\n**2.** Elements created in Postman can be pushed to a user’s GitLab repository, where the schema and collections can coexist alongside the source code. Likewise, branching workflows that your team might already be using can now be followed in Postman; external changes to code and API definitions are reviewable and can be merged back to Postman.\n\n\n![screenshot of branch info](https://about.gitlab.com/images/blogimages/postman3.png){: .shadow}\n\n**3.** This integration enables developers to think about API elements as the API itself, instead of treating code, API definitions, documentation, collections, tests, monitors, etc. as independent entities. All of these constitute the API. Moreover, this allows a higher-level view of the entire API, rather than just the source code — a critical requirement for any organization who wants to build a structured and robust API program.\n\n\n![screenshot of API info](https://about.gitlab.com/images/blogimages/postman4.png){: .shadow}\n\n\n**4.** The Postman-GitLab integration greatly minimizes the likelihood that downstream teams and API consumers will interact with outdated (or even deprecated) APIs or API elements. Users don’t have to spend time deciphering what API, collection, or documentation is current, since they can see what version they are working with all the way back to the code. In Postman, users also have direct access to real-time collaborative tools such as commenting and forking/merging to maintain synchronization between downstream API consumption and the source of truth.\n\n![illustration](https://about.gitlab.com/images/blogimages/postman5.png){: .shadow}\n\n## An integration for the API-first world\n\nOur partnership with GitLab supports our commitment to building Postman as the platform for the [API-first world](https://api-first-world.com/). With integrations like this, [API-first companies](https://blog.postman.com/what-is-an-api-first-company/) are now more productive, can deliver higher-quality products, and are able to build stronger ecosystems of developers, partners, and consumers. \n\nTo get started with the GitLab integration, check out [our guide](https://blog.postman.com/the-reimagined-api-first-workflow-for-developers/) and our how-to video for GitLab integration config:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/BL8DFOPncMc\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n_Andy Rogers is product manager at Postman._\n\n\n",[851,872,9],{"slug":2899,"featured":6,"template":696},"postman-integration-with-gitlab-makes-your-api-workflows-easier","content:en-us:blog:postman-integration-with-gitlab-makes-your-api-workflows-easier.yml","Postman Integration With Gitlab Makes Your Api Workflows Easier","en-us/blog/postman-integration-with-gitlab-makes-your-api-workflows-easier.yml","en-us/blog/postman-integration-with-gitlab-makes-your-api-workflows-easier",{"_path":2905,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2906,"content":2912,"config":2917,"_id":2919,"_type":13,"title":2920,"_source":15,"_file":2921,"_stem":2922,"_extension":18},"/en-us/blog/provision-group-runners-with-google-cloud-platform-and-gitlab-ci",{"title":2907,"description":2908,"ogTitle":2907,"ogDescription":2908,"noIndex":6,"ogImage":2909,"ogUrl":2910,"ogSiteName":683,"ogType":684,"canonicalUrls":2910,"schema":2911},"Provision group runners with Google Cloud Platform and GitLab CI","This tutorial will teach you how to set up a new group runner on GitLab.com using Google Cloud Platform in less than 10 minutes.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098300/Blog/Hero%20Images/Blog/Hero%20Images/AdobeStock_623844718_4E5Fx1Q0DHikigzCsQWhOG_1750098300048.jpg","https://about.gitlab.com/blog/provision-group-runners-with-google-cloud-platform-and-gitlab-ci","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Provision group runners with Google Cloud Platform and GitLab CI\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sarah Matthies\"},{\"@type\":\"Person\",\"name\":\"Noah Ing\"}],\n        \"datePublished\": \"2024-11-19\",\n      }",{"title":2907,"description":2908,"authors":2913,"heroImage":2909,"date":2914,"body":2915,"category":739,"tags":2916},[993,994],"2024-11-19","Are you interested in hosting your own servers to run your GitLab CI/CD\npipelines but don’t know where to begin? Setting up a GitLab Runner to run\nyour pipelines on your own infrastructure can seem like a daunting task as\nit requires infrastructure knowledge and the know-how to maintain that\ninfrastructure. Typically this process requires the provision of\ninfrastructure, the installing of dependency, and testing that it works with\nyour GitLab instance.\n\n\nThis article highlights how easy it is to easily spin up a GitLab Runner of\nyour own utilizing GitLab’s Google Cloud Integration. Follow this tutorial\nand it will teach you how to set up a new group runner on GitLab.com using\nGoogle Cloud Platform in less than 10 minutes!\n\n\nYou will learn how to:\n\n\n- Create a new group runner.\n\n- Configure the new group runner’s tags and description.\n\n- Register the new group runner by adding in configurations.\n\n- Provision the GitLab Runner utilizing `gcloud cli` and Terraform.\n\n- Have your GitLab Runner pick up its first GitLab CI job.\n\n\n## Prerequisites\n\n- A terminal with Bash installed\n\n- Owner access on a Google Cloud Platform project\n\n- Terraform (or OpenTofu) [Version\n1.5](https://releases.hashicorp.com/terraform/1.5.7/) or greater \n\n- [gcloud CLI](https://cloud.google.com/sdk/docs/install) \n\n- 10 minutes\n\n\n## Tutorial\n\n1. Create a new group runner under __Build > Runners > New Group Runner__.\n\n\n__Note:__ Navigate to the group level.\n\n\n![GitLab Runner setup\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image7_aHR0cHM6_1750098317126.png)\n\n\n2. Configure the new group runner's tags, description, and any additional\nconfigurations.\n\n\n![New Group Runner\nsetup](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750098317127.png)\n\n\n3. Select __Google Cloud__.\n\n\n![Select Google Cloud\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750098317129.png)\n\n\n4. Copy your project ID from Google Cloud Platform.\n\n\n![Copy project ID from GCP\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750098317131.png)\n\n\n5. Fill out your Google Cloud project ID and choose a region, zone, and type\nof machine you want to use.\n\n\n![Screen to fill out Google Cloud\ninformation](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image8_aHR0cHM6_1750098317132.png)\n\n\n6\\. Once this information is filled out, click **Setup instructions**.\n\n\nRun the bash script provided in Step 1 above.\n\n\n**Note:** This script was saved to a file called `setup.sh` for ease of use.\nYou may copy this right into your terminal if you are confident in\ndebugging.\n\n\n![Setup instructions\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image6_aHR0cHM6_1750098317134.png)\n\n\n![Script for GitLab\nRunner](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image10_aHR0cHM6_1750098317135.png)\n\n\n7\\. Create a `main.tf` file and follow the instructions in GitLab.\n\n\n**Note:** If you want to use OpenTofu instead of Terraform, you can still\ncopy the code and only have to adjust the Terraform commands for applying\nthe configuration. \n\n\n![Install and register GitLab Runner\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image9_aHR0cHM6_1750098317136.png)\n\n\nOnce successfully provisioned, you should be see the following:\n\n\n![GitLab Runner\ncode](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750098317137.png)\n\n\n8\\. If you close the instructions and click the **View runners** button, you\nwill now have a newly provisioned runner present with \"Never contacted\" as\nits status.\n\n\n![Newly provisioned runner on\nscreen](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098317/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750098317139.png)\n\n\n9\\. In any project, add the following `.gitlab-ci.yml`.\n\n\n```  \n\nstages:  \n  - greet\n\nhello_job:  \n  stage: greet  \n  tags:  \n    - gcp-runner  \n  script:  \n    - echo \"hello\"  \n```\n\n\nVolia! You have set up your first GitLab Runner utilizing Google Cloud\nPlatform.\n\n\n# Next steps\n\n\nNow that you have provisioned your very own GitLab Runner, consider\noptimizing it for your specific use case. Some things to consider with your\nrunner moving forward:\n\n\n- Is the runner I provisioned the right size? Does it need additional\nresources for my use case? \n\n- Does the GitLab Runner contain all the dependency my builds need?  \n\n- How can I store the GitLab Runner as infrastructure as code?\n\n\n> Make sure to bookmark the [Provisioning runners in Google Cloud\ndocumentation](https://docs.gitlab.com/ee/ci/runners/provision_runners_google_cloud.html)\nfor easy reference.\n",[807,493,785,108,998,741,9],{"slug":2918,"featured":6,"template":696},"provision-group-runners-with-google-cloud-platform-and-gitlab-ci","content:en-us:blog:provision-group-runners-with-google-cloud-platform-and-gitlab-ci.yml","Provision Group Runners With Google Cloud Platform And Gitlab Ci","en-us/blog/provision-group-runners-with-google-cloud-platform-and-gitlab-ci.yml","en-us/blog/provision-group-runners-with-google-cloud-platform-and-gitlab-ci",{"_path":2924,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2925,"content":2931,"config":2937,"_id":2939,"_type":13,"title":2940,"_source":15,"_file":2941,"_stem":2942,"_extension":18},"/en-us/blog/proximus-customer-story-clearcase-to-gitlab",{"title":2926,"description":2927,"ogTitle":2926,"ogDescription":2927,"noIndex":6,"ogImage":2928,"ogUrl":2929,"ogSiteName":683,"ogType":684,"canonicalUrls":2929,"schema":2930},"Proximus shares its #movingtoGitLab story","Moving to GitLab resulted in an 80 percent drop in support tickets and an increase in developer productivity.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749678603/Blog/Hero%20Images/traffic-at-sunset.jpg","https://about.gitlab.com/blog/proximus-customer-story-clearcase-to-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Proximus shares its #movingtoGitLab story\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Bert Van Eyck\"}],\n        \"datePublished\": \"2019-06-07\",\n      }",{"title":2926,"description":2927,"authors":2932,"heroImage":2928,"date":2934,"body":2935,"category":848,"tags":2936},[2933],"Bert Van Eyck","2019-06-07","\n[Proximus](https://www.proximus.com/) is a telecommunication company providing services to residential, enterprise, and public users. We are the leading provider of telephony, internet, television, and network-based ICT services in Belgium, with more than 2 million customers.\n\n## Our road to GitLab\n\nThe technical divisions of Proximus deliver a big part of the applications and systems required for delivering the best possible service to our end users. It includes all types of capabilities such as network construction, network maintenance, product ordering, product selling, billing, etc.\nSome examples of our development include:\n\n- Our website, [Proximus.be](https://www.proximus.be), on which users can find product info, support info and so much more.\n- A mobile app where everyone can check their usage, products, bills, etc.\n- Television interface.\n- A television app.\n\nTo ensure a performant and stable working environment for our developers, we have been working for several years to create a CI/CD DevOps workflow.\n\nThe first complete chain started in 2014 and used tools like ClearCase, Jenkins, Nexus, etc. By 2015 we had about 200 applications which were using our end-to-end chain to build and deploy in all different environments.\n\nIn 2016, to continue to improve our delivery chain, we considered switching ClearCase to Git. Despite ClearCase being a powerful tool, we noticed that the learning curve and the ease of use of ClearCase was not optimal. Also some of the tools we used were starting to lose compatibility.\n\nWe quickly came across GitLab and decided to try our first setup with [GitLab CE](/blog/gitlab-tiers/) in mid-2016.\n\n## The evolution of GitLab inside Proximus\n\nOur first implementation of Gitlab was rapidly a real success and the popularity of GitLab was increasing exponentially within our developer community. So, we decided to set up a corporate GitLab CE server at Proximus and to promote the creation of all new applications using our existing CI/CD chain with GitLab as source code management.\nIn just one year of using GitLab, we grew to 325 projects and about 600 users.\n\nBecause GitLab was becoming a big part of our tool set, we switched to GitLab EE in Q2 of 2017. This allowed us to use more features of GitLab such as: LDAP groups, push rules, mirror repositories, etc.\nAnd of course, with the enterprise edition you also receive additional support. With the enterprise edition we also started moving applications from ClearCase to GitLab.\n\nWe were also investigating and testing other features to expand our use of GitLab in the meantime:\n\n- Some projects have started using GitLab CI to build.\n- Integration with Jira has been implemented.\n- Currently experimenting with a first setup of GitLab’s global search function in combination with Elasticsearch.\n\nBy the end of 2018 we had grown to almost 1,000 users and 1,700 projects.\n\n## Challenges\n\nOur biggest challenge was to maintain and ensure a stable environment while growing rapidly. When we started using GitLab CI we encountered some issues with the large number of pipelines and jobs being created, which were consuming a lot of our resources. But [as of GitLab 11.6 a feature has been provided to remove pipelines with their job logs when using API](/releases/2018/12/22/gitlab-11-6-released/#pipelines-can-now-be-deleted-by-project-maintainers-using-api), which helped a lot.\n\n## Results\n\nSince we started using GitLab, we have been able to provide our developers with faster setup and support. Another very noticeable side effect of switching to GitLab was the significant drop in the number of support tickets created by the developers. Our first full year of using GitLab inside our CI/CD setup resulted in **80 percent** fewer tickets.\n\nEven in 2018, after our total number of users had grown to almost 1,000, the number of projects had multiplied by five and we migrated 75 applications to GitLab. We still had **65 percent** fewer tickets.\n\nIn the future, we will continue looking into expanding our GitLab environment and we hope to continue the positive evolution together with the support of GitLab.\n",[266,2048,9,2745,693],{"slug":2938,"featured":6,"template":696},"proximus-customer-story-clearcase-to-gitlab","content:en-us:blog:proximus-customer-story-clearcase-to-gitlab.yml","Proximus Customer Story Clearcase To Gitlab","en-us/blog/proximus-customer-story-clearcase-to-gitlab.yml","en-us/blog/proximus-customer-story-clearcase-to-gitlab",{"_path":2944,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2945,"content":2951,"config":2956,"_id":2958,"_type":13,"title":2959,"_source":15,"_file":2960,"_stem":2961,"_extension":18},"/en-us/blog/publishing-an-astro-site-with-pages",{"title":2946,"description":2947,"ogTitle":2946,"ogDescription":2947,"noIndex":6,"ogImage":2948,"ogUrl":2949,"ogSiteName":683,"ogType":684,"canonicalUrls":2949,"schema":2950},"How to publish your Astro Site with GitLab Pages","Learn how to deploy an Astro Site with GitLab Pages.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682473/Blog/Hero%20Images/shot-by-cerqueira-0o_GEzyargo-unsplash.jpg","https://about.gitlab.com/blog/publishing-an-astro-site-with-pages","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to publish your Astro Site with GitLab Pages\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Janis Altherr\"}],\n        \"datePublished\": \"2022-10-24\",\n      }",{"title":2946,"description":2947,"authors":2952,"heroImage":2948,"date":2953,"body":2954,"category":739,"tags":2955},[1015],"2022-10-24","Astro is an amazing new framework to create content-focused static sites and\nGitLab Pages is a great way to deploy a site built with Astro. Here's a\nstep-by-step guide on how to build and deploy an Astro Site with GitLab\nPages.\n\n\n## Create the project locally\n\n\nFirst, create the Astro Project locally using the Astro CLI.\n\n\nNote: Even though we're offering a [project\ntemplate](https://gitlab.com/pages/astro),\n\nwe recommend using the CLI locally to scaffold your project. This ensures\nyou can create your project with the latest defaults.\n\n\n```shell\n\nnpm create astro@latest\n\n```\n\n\nNow follow the CLI instructions. As part of the setup, Astro will create the\n\nproject folder for you. During the course of the setup Astro will ask\nwhether you'd like to initialize a new Git repository. Answer this with `y`\n(yes).\n\n\nOnce the Astro CLI is done scaffolding your project, `cd` into the new\nfolder:\n\n\n```shell\n\ncd \u003Cyour-project>\n\n```\n\n\n## Configure Astro for GitLab Pages\n\n\nAstro comes with a few defaults that are incompatible with GitLab Pages. So\nbefore continuing, we need to set up a compatible config.\n\nEdit your `astro.config.mjs` to include the following:\n\n\n```javascript\n\n// astro.config.mjs\n\nimport { defineConfig } from 'astro/config';\n\n\n// https://astro.build/config\n\nexport default defineConfig({\n  // GitLab Pages requires exposed files to be located in a folder called \"public\".\n  // So we're instructing Astro to put the static build output in a folder of that name.\n  outDir: 'public',\n\n  // The folder name Astro uses for static files (`public`) is already reserved\n  // for the build output. So in deviation from the defaults we're using a folder\n  // called `static` instead.\n  publicDir: 'static',\n});\n\n```\n\n\nWhy are we doing this? GitLab Pages is a way to publish some files in a\n\nrepository, no matter what build tool you used to generate them. Unlike with\n\nother deployment tools the exposed files and the source code can live \n\ntogether in one place. So to ensure you don't accidentally expose sensitive\n\nfiles we're requiring you to consciously put them into a\n\nfolder named \"public\".\n\n\nBy default, Astro uses `public` for something different – the static \n\nassets. So we have to change that behavior. The above config tells Astro\n\nthat we'll put the static files in a folder named `static` and want the\n_output_\n\nfiles to be put in a folder named, as required, `public`.\n\n\nAstro already generated that assets folder under the old name while\n\nscaffolding, so we'll have to rename it. Inside your Astro project folder,\nrun:\n\n\n```shell\n\nmv public static\n\n```\n\n\nDepending on your project configuration, GitLab Pages will deploy your site \n\nat a URL that follows the format simlar to `https://\u003Cuser-or-group>.gitlab.\n\nio/\u003Cproject-name>`. If you want to use the default URL, you need to adjust\nAstro\n\nto the fact that the site is not mounted at the root path, otherwise it may \n\nnot load static assets (such as the CSS files) correctly. \n\n\n[Visit the\ndocumentation](https://docs.gitlab.com/ee/user/project/pages/getting_started_part_one.html#gitlab-pages-default-domain-names)\n\nto find out the URL schema of the project you intend to create, then add the\n\nfollowing line to your `astro.config.mjs`. (Skip this step if you're\ncreating\n\na user or group page):\n\n\n```javascript\n\n// astro.config.mjs\n\nexport default defineConfig({\n  // ...\n  base: '/\u003Cproject-name>'\n  // In case the project is owned by a subgroup, use:\n  // base: '/\u003Csubgroup>/\u003Cproject-name>'\n});\n\n```\n\n\nAstro\n[recommends](https://docs.astro.build/en/reference/configuration-reference/#site) \n\nadding the final site's full URL to generate the sitemap, so add it now to\nyour\n\n`astro.config.mjs`:\n\n\n```javascript\n\n// astro.config.mjs\n\nexport default defineConfig({\n  // ...\n  site: 'https://\u003Cuser-or-group>.gitlab.io'\n  \n  // Note: Instead of specifying both `base` and `site`, you can simply\n  // use the full URL here:\n  // site: 'https://\u003Cuser-or-group>.gitlab.io/\u003Cproject-name>'\n  // or for pages owned by a subgroup:\n  // site: 'https://\u003Cgroup>.gitlab.io/\u003Csubgroup>/\u003Cproject-name>'\n});\n\n```\n\n\nNow that you've successfully configured your project, you can commit your\n\nchanges.\n\n\n```shell\n\ngit add -A\n\ngit commit -m \"Initial commit\"\n\n```\n\n\n## Set up the remote repository\n\n\nYou can't push the code as we have yet to set up the remote repository.\nVisit\n\nGitLab and create a new project. When asked, select \"Create blank project.\"\n\n\nIn the setup screen, select \"GitLab Pages\" as the deployment target. Choose\nthe\n\nvisibility level however you like. This is mainly asking whether your\nsource \n\ncode is public, although it does affect the initial setting (see \"Making a \n\nprivate project's site public\" below).\n\n\nMake sure you unset the checkbox next to \"Initialize repository with a\nREADME\",\n\notherwise GitLab will begin a new Git history that you will have to\nreconcile\n\nwith your existing local one.\n\n\nOnce the Project is set up, follow the instructions on how to add an\n_existing\n\nrepository_ – if you don't have an existing remote, so you can just run:\n\n\n```shell\n\ngit remote add origin \u003Cgit-project-url>\n\ngit push -u origin --all\n\n```\n\n\nNow you've synced your local code with Gitlab, let's finish publishing it\nwith\n\nPages.\n\n\n## Create a Pages pipeline\n\n\nIn GitLab, go to your project's settings and select Pages. You will be\nwelcomed\n\nby a screen that helps you build a `.gitlab-ci.yml` file.\n\n\n![Screenshot: The \"Get stated with Pages\"\nUI](https://about.gitlab.com/images/blogimages/astro-pages/wizard_step_1.png)\n\n\nEnter \"node:lts\" as the build image. This will give you the latest node \n\nenvironment with long-time support.\n\n\nWe've already configured Astro to output our files in a folder named\n`public`,\n\nso you can check the checkbox asking you to confirm this.\n\n\nOn the next page, enter `npm ci` as the installation step. Running `npm ci` \n\ninstead of `npm install` is recommended for CI environments such as GitLab\n\nPipelines as it uses the `package-lock.json` to match the installed version \n\nwith the one you used during development. See the [npm\ndocumentation](https://docs.npmjs.com/cli/v8/commands/npm-ci)\n\nto learn more about `npm ci`.\n\n\n![Screenshot: Inputting the installation\nstep](https://about.gitlab.com/images/blogimages/astro-pages/wizard_step_2.png)\n\n\nOn the last page, enter the build command \"npm run build\". Again, click\n\"next\".\n\n\n![Screenshot: Inputting the build\nstep](https://about.gitlab.com/images/blogimages/astro-pages/wizard_step_3.png)\n\n\nNext to the inputs you see the pipeline file that has been built for you. \n\nThis is the one we want to add to the repository to enable Pages.\n\n\n![Screenshot: The finished file and the commit\nstep](https://about.gitlab.com/images/blogimages/astro-pages/wizard_step_4.png)\n\n\nHow does it work in detail? If GitLab sees a job named `pages`, it will \n\nlook for artifacts inside a root folder `public` and then create a \n\nGitLab Pages deployment from it.\n\n\nThe `rules` section ensures the pages deployment is only triggered by \n\ncommits to the default branch. Every time you push a change to your default \n\nbranch, Pages will publish the new changes. \n\n\nIf you're happy with the pipeline, enter a commit message and click\n\"commit\".\n\n(Make sure you run `git pull` locally before doing any more changes to \n\nprevent issues with diverging histories.)\n\n\nNow having added a commit with a `.gitlab-ci.yml` file, GitLab has kicked\noff\n\na pipeline. Visit CI/CD > Pipelines to see the progress. After a couple of \n\nminutes, you should see the pipeline has succeeded. (If it's showing\n\"failed\", \n\nclick on the status button to see the job logs.)\n\n\n![Screenshot:\nPipelines](https://about.gitlab.com/images/blogimages/astro-pages/pipeline_overview.png)\n\n\nOnce the pipeline has completed, go back to Settings > Pages. You should now\nsee\n\nthe various settings of your site, including your new site's URL. Click on \n\nit and, congratulations, you've just deployed your Astro Site wit GitLab \n\nPages!\n\n\n![Screenshot: The deployed\npage](https://about.gitlab.com/images/blogimages/astro-pages/deployed_site.png)\n\n\n## Making a private project's site public\n\n\nBy default, a private project's Pages site is only accessible to project \n\nmembers. If you want your source code to be private, but still have a\npublic \n\nsite, go to Settings/General and expand \"visibility, project features,\npermissions\", scroll down to \"Pages\" and set \n\nit to \"Everyone\".\n\n\n## Keep reading\n\n\n- [Tutorial: Use the GitLab UI to deploy your static\nsite](https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_ui.html)\n\n- [Astro Docs: Deploy your Astro Site to GitLab\nPages](https://docs.astro.build/en/guides/deploy/gitlab/)\n\n- [Watch a video on how to create a Pages Pipeline with the\nWizard](https://youtu.be/49hgxqPGofw)\n",[807,9,1019],{"slug":2957,"featured":6,"template":696},"publishing-an-astro-site-with-pages","content:en-us:blog:publishing-an-astro-site-with-pages.yml","Publishing An Astro Site With Pages","en-us/blog/publishing-an-astro-site-with-pages.yml","en-us/blog/publishing-an-astro-site-with-pages",{"_path":2963,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2964,"content":2969,"config":2976,"_id":2978,"_type":13,"title":2979,"_source":15,"_file":2980,"_stem":2981,"_extension":18},"/en-us/blog/python-3-defailt-for-license-compliance",{"title":2965,"description":2966,"ogTitle":2965,"ogDescription":2966,"noIndex":6,"ogImage":754,"ogUrl":2967,"ogSiteName":683,"ogType":684,"canonicalUrls":2967,"schema":2968},"Python 3 becomes default for license compliance scanning","Python 3 will soon become the default version used by the Secure stage License Compliance feature.","https://about.gitlab.com/blog/python-3-defailt-for-license-compliance","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Upcoming breaking change: Python 3 will be the default version used in License Compliance\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Nicole Schwartz\"}],\n        \"datePublished\": \"2019-07-19\",\n      }",{"title":2970,"description":2966,"authors":2971,"heroImage":754,"date":2973,"body":2974,"category":763,"tags":2975},"Upcoming breaking change: Python 3 will be the default version used in License Compliance",[2972],"Nicole Schwartz","2019-07-19","\n\nWith the release of GitLab 12.2 on August 22, Python 3 will become the default version used in the Secure\nstage License Compliance\u003Csup>1\u003C/sup> feature. GitLab.com users should expect to see the change at\nthe beginning of August.\n\n### What do I do if I use Python 2.0?\n\nGitLab self-managed users with Python 2 will need to set the CI variable `LM_PYTHON_VERSION` to \"2\" when\nthey start using GitLab 12.2. GitLab.com users will need to do so at the beginning of August.\n\nIn the GitLab 12.0 release post, [we announced License Compliance\u003Csup>1\u003C/sup> will change the\ndefault version of Python from version\n2 to version 3](/releases/2019/06/22/gitlab-12-0-released/#license-management-will-use-python-3-as-the-default-in-gitlab-12.2)\nin GitLab 12.2, and that support for Python 2 would be deprecated in a future release due\nto [Python 2.7 reaching the end of its life](https://pythonclock.org/) on Jan. 1, 2020.\n\n### What if I currently use Python 3?\n\nYou can change License Compliance\u003Csup>1\u003C/sup> to use Python 3 by setting the CI\nvariable `LM_PYTHON_VERSION` to \"3\" today. If you do not make this change before the default\nis changed, it will only begin to work starting with GitLab 12.2.\n\n##### \u003Csup>1\u003C/sup>What is License Compliance?\n\nLicense Compliance, formerly called License\nManagement, [is being renamed to better align with common industry vernacular starting in 12.2](/releases/2019/06/22/gitlab-12-0-released/#secure-license-management-renamed-to-license-compliance-in-gitlab-12.0).\nThe purpose of License Compliance is to track which licenses are used by third-party\ncomponents included in your project, like libraries and external dependencies, and to check that\nthey are compatible with your organizations licensing model. License Compliance is part of our\n[Secure Composition Analysis group](https://handbook.gitlab.com/handbook/product/categories/#composition-analysis-group).\n\nYou can view the [documentation for License Management here](https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html).\n",[764,763,9],{"slug":2977,"featured":6,"template":696},"python-3-defailt-for-license-compliance","content:en-us:blog:python-3-defailt-for-license-compliance.yml","Python 3 Defailt For License Compliance","en-us/blog/python-3-defailt-for-license-compliance.yml","en-us/blog/python-3-defailt-for-license-compliance",{"_path":2983,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":2984,"content":2990,"config":2995,"_id":2997,"_type":13,"title":2998,"_source":15,"_file":2999,"_stem":3000,"_extension":18},"/en-us/blog/redbox-on-demand-delivers-with-gitlab",{"title":2985,"description":2986,"ogTitle":2985,"ogDescription":2986,"noIndex":6,"ogImage":2987,"ogUrl":2988,"ogSiteName":683,"ogType":684,"canonicalUrls":2988,"schema":2989},"Redbox delivers On Demand with GitLab","Redbox's Joel Vasallo and Nicholas Konieczko explain how they ‘deliver software like a fox’ with GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749673064/Blog/Hero%20Images/redbox-blog-jannes-glas-unsplash.jpg","https://about.gitlab.com/blog/redbox-on-demand-delivers-with-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Redbox delivers On Demand with GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brein Matturro\"}],\n        \"datePublished\": \"2019-10-01\",\n      }",{"title":2985,"description":2986,"authors":2991,"heroImage":2987,"date":2992,"body":2993,"category":691,"tags":2994},[2874],"2019-10-01","\nAt GitLab Connect Chicago, Redbox's [Joel Vasallo](https://www.linkedin.com/in/joelvasallo) and [Nicholas Konieczko](https://www.linkedin.com/in/nick-konieczko-42895354) presented a talk called “Delivering software like a fox.” Redbox, primarily known for providing movie and video game rentals via automated retail kiosks, has recently expanded to provide streaming services.\n\nRedbox On Demand is the company's newest streaming platform, built on .NET Core in containers on Linux in the cloud. The video retail company had a few goals in mind when building its latest platform. Joel, cloud DevOps manager, and Nicholas, mobile applications manager, share their three main objectives and how GitLab provides the tool that ensures success.\n\n## Goal #1: Modernize software development processes\n\nThe mobile and development teams wanted to be able to create the platform using the latest technology in order to provide the best product for the customer. “[There was] nothing wrong with the way they were done, but in the sense that the world has really come a long way from traditional Windows servers... in a data center running .NET frameworks and stuff like that, we really wanted to empower developers to use containers,” Joel says.\n\n**Outcome**: The mobile and development teams currently use GitLab CI, leveraging Fastlane. The power of GitLab and its ability to work along with other tools helped to modernize software development processes.\n\n## Goal #2: Speed up delivery to the cloud\n\nProviding an on-demand service means that the application has to actually be ready at the very moment of demand. Being new to the streaming arena, it was important for Redbox to move to the cloud. “We also wanted to leverage the power of the cloud and have the scaling perspective of the cloud. We wanted to be in the cloud, as everyone wants to be nowadays. We also wanted to ensure that our features go out the door faster because, in the streaming business, it's all about being first to market with your features,” Joel says.\n\n**Outcome**: The teams now use GitLab CI along with Spinnaker. “We wanted to increase software delivery and do what's best for the teams. I don't want to dictate what developers should do in their day-to-day workflow,” Joel says.\n\n## Goal #3: Empower developers to own their applications\n\nThe hope was that a developer would be able to deploy code to production at any time with a single click of a button. Developers would then have the ability to just write the code and a working tool will be able to pick up the errors. “Code goes out the door based on an approval process. Developers are able to own and operate their code, essentially,” Joel says.\n\n**Outcome**: The objective was achieved, according to Joel. “Ultimately, developers own their own apps. GitLab Enterprise allowed teams to own their own verticals as well as Spinnaker, which allows them to deploy it to whatever cloud provider that they so choose.”\n\nTo learn more about how GitLab helped the mobile and development teams achieve their platform goals (and more), watch the presentation below.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/3eG8Muorafo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n## Key takeaways\n\n### Putting the version in version control\n\n“There was a disparate amount of Git and source control tools. Namely, we had an internal Git server, which... I don't know what it was actually running. We had GitHub.com. We had Team Foundation Server. We had Azure DevOps. So all this stuff... Teams were really all over the place. They all had their source code. Getting access to things was just a nightmare.\n\n“So what did we do? Let's get another version control system into the mix. We need a fifth one. So we picked GitLab. Honestly, GitLab was the most tried and true solution from our perspective. It has support for a few things, like on-prem, also in the cloud as well on the .com offering. But, more than that, at the end of the day it let developers control their namespace within a large organization.” – _Joel Vasallo_\n\n### GitLab works for mobile development\n\n“The mobile teams were the first to get to try out GitLab.com. It's simple. It's extremely easy to get started. There's a lot of documentation out there, all the things I love. It's very cost effective. We were able to get a free trial running, get repos open, test out different things, different features, to see if it could work for our teams.\" – _Nick Konieczko_\n\n### Yes, you can use Jenkins too\n\n“This is, honestly, one of the best things about GitLab, is they just want us to be successful. Batteries are included. There's a lot of great tools in there, such as GitLab CI, the GitLab Issue Board... and GitLab's Artifact Repository. It's built into the platform. GitLab's pipelines with the CI/CD process, all of this comes in. But if you don't want to use it, it'll adapt to your business model.\n\n“For example, my team uses Jenkins. We can still use GitLab. There's no blocking event where it says, ‘Oh, you're using Jenkins. You can't talk to us. Error. Blocked.’ No, we use Jira. We type ‘Jira, take us into GitLab’ all the time. We have JFrog Artifactory. We also use Spinnaker for our software delivery. Again, it transforms to what you need as a business, and that's the thing that I really appreciate, being on the DevOps side.” – _Joel Vasallo_\n\nCover image by [Jannes Glas](https://unsplash.com/@jannesglas) on [Unsplash](https://www.unsplash.com)\n{: .note}\n",[2745,2128,2048,9],{"slug":2996,"featured":6,"template":696},"redbox-on-demand-delivers-with-gitlab","content:en-us:blog:redbox-on-demand-delivers-with-gitlab.yml","Redbox On Demand Delivers With Gitlab","en-us/blog/redbox-on-demand-delivers-with-gitlab.yml","en-us/blog/redbox-on-demand-delivers-with-gitlab",{"_path":3002,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3003,"content":3009,"config":3014,"_id":3016,"_type":13,"title":3017,"_source":15,"_file":3018,"_stem":3019,"_extension":18},"/en-us/blog/secure-and-publish-python-packages-a-guide-to-ci-integration",{"title":3004,"description":3005,"ogTitle":3004,"ogDescription":3005,"noIndex":6,"ogImage":3006,"ogUrl":3007,"ogSiteName":683,"ogType":684,"canonicalUrls":3007,"schema":3008},"Secure and publish Python packages: A guide to CI integration","Learn how to implement a secure CI/CD pipeline across five stages with the GitLab DevSecOps platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662080/Blog/Hero%20Images/AdobeStock_1097303277.jpg","https://about.gitlab.com/blog/secure-and-publish-python-packages-a-guide-to-ci-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Secure and publish Python packages: A guide to CI integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tim Rizzi\"}],\n        \"datePublished\": \"2025-01-21\",\n      }",{"title":3004,"description":3005,"authors":3010,"heroImage":3006,"date":3011,"body":3012,"category":716,"tags":3013},[1525],"2025-01-21","Supply chain security is a critical concern in software development.\nOrganizations need to verify the authenticity and integrity of their\nsoftware packages. This guide will show you how to implement a secure CI/CD\npipeline for Python packages using GitLab CI, incorporating package signing\nand attestation using Sigstore's Cosign.\n\n\nYou'll learn:\n\n\n- [Why sign and attest your Python\npackages?](#why-sign-and-attest-your-python-packages%3F)\n\n- [Pipeline overview](#pipeline-overview)\n\n- [Complete pipeline implementation: Setting up the\nenvironment](#complete-pipeline-implementation-setting-up-the-environment)\n   * [Environment configuration](#environment-configuration)\n   * [Configuration breakdown](#configuration-breakdown)\n-  The 6 stages\n\n    1. [Building](#building-crafting-the-package)\n    2. [Signing](#signing-the-digital-notarization)\n    3. [Verification](#verification-the-security-checkpoint)\n    4. [Publishing](#publishing-the-controlled-release)\n    5. [Publishing signatures](#publishing-signatures-making-verification-possible)\n    6. [Consumer verification](#consumer-verification-testing-the-user-experience)\n\n## Why sign and attest your Python packages?\n\n\nHere are four reasons to sign and attest your Python packages:\n\n\n* **Supply chain security:** Package signing ensures that the code hasn't\nbeen tampered with between build and deployment, protecting against supply\nchain attacks.\n\n* **Compliance requirements:** Many organizations, especially in regulated\nindustries, require cryptographic signatures and provenance information for\nall deployed software.\n\n* **Traceability:** Attestations provide a verifiable record of build\nconditions, including who built the package and under what circumstances.\n\n* **Trust verification:** Consumers of your package can cryptographically\nverify its authenticity before installation.\n\n\n## Pipeline overview\n\n\nEnsuring your code's integrity and authenticity is necessary. Imagine a\npipeline that doesn't just compile your code but creates a cryptographically\nverifiable narrative of how, when, and by whom your package was created.\nEach stage acts as a guardian, checking and documenting the package's\nprovenance.\n\n\nHere are six stages of a GitLab pipeline that ensure your package is secure\nand trustworthy:\n\n\n* Build: Creates a clean, standard package that can be easily shared and\ninstalled.\n\n* Signing: Adds a digital signature that proves the package hasn't been\ntampered with since it was created.\n\n* Verification: Double-checks that the signature is valid and the package\nmeets all our security requirements.\n\n* Publishing: Uploads the verified package to GitLab's package registry,\nmaking it available for others to use.\n\n* Publishing Signatures: Makes signatures available for verification.\n\n* Consumer Verification: Simulates how end users can verify package\nauthenticity.\n\n\n## Complete pipeline implementation: Setting up the environment\n\n\nBefore we build our package, we need to set up a consistent and secure build\nenvironment. This configuration ensures every package is created with the\nsame tools, settings, and security checks.\n\n\n### Environment configuration\n\n\nOur pipeline requires specific tools and settings to work correctly.\n\n\nPrimary configurations:\n\n\n* Python 3.10 for consistent builds\n\n* Cosign 2.2.3 for package signing\n\n* GitLab package registry integration\n\n* Hardcoded package version for reproducibility\n\n\n**Note about versioning:** We've chosen to use a hardcoded version\n(`\"1.0.0\"`) in this example rather than deriving it from git tags or\ncommits. This approach ensures complete reproducibility and makes the\npipeline behavior more predictable. In a production environment, you might\nwant to use semantic versioning based on git tags or another versioning\nstrategy that fits your release process.\n\n\nTool requirements:\n\n\n* Basic utilities: `curl`, `wget`\n\n* Cosign for cryptographic signing\n\n* Python packaging tools: `build`, `twine`, `setuptools`, `wheel`\n\n\n### Configuration breakdown\n\n\n```yaml\n\nvariables:\n  PYTHON_VERSION: '3.10'\n  PACKAGE_NAME: ${CI_PROJECT_NAME}\n  PACKAGE_VERSION: \"1.0.0\"\n  FULCIO_URL: 'https://fulcio.sigstore.dev'\n  REKOR_URL: 'https://rekor.sigstore.dev'\n  CERTIFICATE_IDENTITY: 'https://gitlab.com/${CI_PROJECT_PATH}//.gitlab-ci.yml@refs/heads/${CI_DEFAULT_BRANCH}'\n  CERTIFICATE_OIDC_ISSUER: 'https://gitlab.com'\n  PIP_CACHE_DIR: \"$CI_PROJECT_DIR/.pip-cache\"\n  COSIGN_YES: \"true\"\n  GENERIC_PACKAGE_BASE_URL: \"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${PACKAGE_NAME}/${PACKAGE_VERSION}\"\n```\n\n\nWe use caching to speed up subsequent builds:\n\n\n```yaml\n\ncache:\n  paths:\n    - ${PIP_CACHE_DIR}\n```\n\n\n## Building: Crafting the package\n\n\nEvery software journey begins with creation. In our pipeline, the build\nstage is where raw code transforms into a distributable package, ready to\ntravel across different Python environments.\n\n\nThe build process creates two standardized formats:\n\n\n* a wheel package (.whl) for quick, efficient installation\n\n* a source distribution (.tar.gz) that carries the complete code\n\n\nHere's the build stage implementation:\n\n\n```yaml\n\nbuild:\n  extends: .python-job\n  stage: build\n  script:\n    - git init\n    - git config --global init.defaultBranch main\n    - git config --global user.email \"ci@example.com\"\n    - git config --global user.name \"CI\"\n    - git add .\n    - git commit -m \"Initial commit\"\n    - export NORMALIZED_NAME=$(echo \"${CI_PROJECT_NAME}\" | tr '-' '_')\n    - sed -i \"s/name = \\\".*\\\"/name = \\\"${NORMALIZED_NAME}\\\"/\" pyproject.toml\n    - sed -i \"s|\\\"Homepage\\\" = \\\".*\\\"|\\\"Homepage\\\" = \\\"https://gitlab.com/${CI_PROJECT_PATH}\\\"|\" pyproject.toml\n    - python -m build\n  artifacts:\n    paths:\n      - dist/\n      - pyproject.toml\n```\n\n\nLet's break down what this build stage does:\n\n\n1. Initializes a Git repository (`git init`) and configures it with basic\nsettings\n\n2. Normalizes the package name by converting hyphens to underscores, which\nis required for Python packaging\n\n3. Updates the package metadata in `pyproject.toml` to match our project\nsettings\n\n4. Builds both wheel and source distribution packages using `python -m\nbuild`\n\n5. Preserves the built packages and configuration as artifacts for\nsubsequent stages\n\n\n## Signing: The digital notarization\n\n\nIf attestation is the package's biography, signing is its cryptographic seal\nof authenticity. This is where we transform our package from a mere\ncollection of files into a verified, tamper-evident artifact.\n\n\nThe signing stage uses Cosign to apply a digital signature as an unbreakable\nseal. This isn't just a stamp — it's a complex cryptographic handshake that\nproves the package's integrity and origin.\n\n\n```yaml\n\nsign:\n  extends: .python+cosign-job\n  stage: sign\n  id_tokens:\n    SIGSTORE_ID_TOKEN:\n      aud: sigstore\n  script:\n    - |\n      for file in dist/*.whl dist/*.tar.gz; do\n        if [ -f \"$file\" ]; then\n          filename=$(basename \"$file\")\n          cosign sign-blob --yes \\\n            --fulcio-url=${FULCIO_URL} \\\n            --rekor-url=${REKOR_URL} \\\n            --oidc-issuer $CI_SERVER_URL \\\n            --identity-token $SIGSTORE_ID_TOKEN \\\n            --output-signature \"dist/${filename}.sig\" \\\n            --output-certificate \"dist/${filename}.crt\" \\\n            \"$file\"\n        fi\n      done\n  artifacts:\n    paths:\n      - dist/\n```\n\n\nThis signing stage performs several crucial operations:\n\n\n1. Obtains an OIDC token from GitLab for authentication with Sigstore\nservices\n\n2. Processes each built package (both wheel and source distribution)\n\n3. Uses Cosign to create a cryptographic signature (`.sig`) for each package\n\n4. Generates a certificate (`.crt`) that proves the signature's authenticity\n\n5. Stores both signatures and certificates alongside the packages as\nartifacts\n\n\n## Verification: The security checkpoint\n\n\nVerification is our final quality control gate. It's not just a check — it's\na security interrogation where every aspect of the package is scrutinized.\n\n\n```yaml\n\nverify:\n  extends: .python+cosign-job\n  stage: verify\n  script:\n    - |\n      failed=0\n      for file in dist/*.whl dist/*.tar.gz; do\n        if [ -f \"$file\" ]; then\n          filename=$(basename \"$file\")\n          if ! cosign verify-blob \\\n            --signature \"dist/${filename}.sig\" \\\n            --certificate \"dist/${filename}.crt\" \\\n            --certificate-identity \"${CERTIFICATE_IDENTITY}\" \\\n            --certificate-oidc-issuer \"${CERTIFICATE_OIDC_ISSUER}\" \\\n            \"$file\"; then\n            failed=1\n          fi\n        fi\n      done\n      if [ $failed -eq 1 ]; then\n        exit 1\n      fi\n```\n\n\nThe verification stage implements several security checks:\n\n\n1. Examines each package file in the `dist` directory\n\n2. Uses Cosign to verify the signature matches the package content\n\n3. Confirms the certificate's identity matches our expected GitLab pipeline\nidentity\n\n4. Validates our trusted OIDC provider issued the certificate\n\n5. Fails the entire pipeline if any verification check fails, ensuring only\nverified packages proceed\n\n\n## Publishing: The controlled release\n\n\nPublishing is where we make our verified packages available through GitLab's\npackage registry. It's a carefully choreographed release that ensures only\nverified, authenticated packages reach their destination.\n\n\n```yaml\n\npublish:\n  extends: .python-job\n  stage: publish\n  script:\n    - |\n      cat \u003C\u003C EOF > ~/.pypirc\n      [distutils]\n      index-servers = gitlab\n      [gitlab]\n      repository = ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi\n      username = gitlab-ci-token\n      password = ${CI_JOB_TOKEN}\n      EOF\n      TWINE_PASSWORD=${CI_JOB_TOKEN} TWINE_USERNAME=gitlab-ci-token \\\n        twine upload --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi \\\n        dist/*.whl dist/*.tar.gz\n```\n\n\nThe publishing stage handles several important tasks:\n\n\n1. Creates a `.pypirc` configuration file with GitLab package registry\ncredentials\n\n2. Uses the GitLab CI job token for secure authentication\n\n3. Uploads both wheel and source distribution packages to the GitLab PyPI\nregistry\n\n4. Makes the packages available for installation via pip\n\n\n## Publishing signatures: Making verification possible\n\n\nAfter publishing the packages, we must make their signatures and\ncertificates available for verification. We store these in GitLab's generic\npackage registry, making them easily accessible to users who want to verify\npackage authenticity.\n\n\n```yaml\n\npublish_signatures:\n  extends: .python+cosign-job\n  stage: publish_signatures\n  script:\n    - |\n      for file in dist/*.whl dist/*.tar.gz; do\n        if [ -f \"$file\" ]; then\n          filename=$(basename \"$file\")\n          curl --header \"JOB-TOKEN: ${CI_JOB_TOKEN}\" \\\n               --fail \\\n               --upload-file \"dist/${filename}.sig\" \\\n               \"${GENERIC_PACKAGE_BASE_URL}/${filename}.sig\"\n\n          curl --header \"JOB-TOKEN: ${CI_JOB_TOKEN}\" \\\n               --fail \\\n               --upload-file \"dist/${filename}.crt\" \\\n               \"${GENERIC_PACKAGE_BASE_URL}/${filename}.crt\"\n        fi\n      done\n```\n\n\nThe signature publishing stage performs these key operations:\n\n\n1. Processes each built package to find its corresponding signature files\n\n2. Uses the GitLab API to upload the signature (`.sig`) file to the generic\npackage registry\n\n3. Uploads the corresponding certificate (`.crt`) file\n\n4. Makes these verification artifacts available for downstream package\nconsumers\n\n5. Uses the same version and package name to maintain the connection between\npackages and signatures\n\n\n## Consumer verification: Testing the user experience\n\n\nThe final stage simulates how end users will verify your package's\nauthenticity. This stage acts as a final check and a practical example of\nthe verification process.\n\n\n```yaml\n\nconsumer_verification:\n  extends: .python+cosign-job\n  stage: consumer_verification\n  script:\n    - |\n      git init\n      git config --global init.defaultBranch main\n      mkdir -p pkg signatures\n\n      pip download --index-url \"https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/pypi/simple\" \\\n          \"${NORMALIZED_NAME}==${PACKAGE_VERSION}\" --no-deps -d ./pkg\n\n      pip download --no-binary :all: \\\n          --index-url \"https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/pypi/simple\" \\\n          \"${NORMALIZED_NAME}==${PACKAGE_VERSION}\" --no-deps -d ./pkg\n\n      failed=0\n      for file in pkg/*.whl pkg/*.tar.gz; do\n        if [ -f \"$file\" ]; then\n          filename=$(basename \"$file\")\n          sig_url=\"${GENERIC_PACKAGE_BASE_URL}/${filename}.sig\"\n          cert_url=\"${GENERIC_PACKAGE_BASE_URL}/${filename}.crt\"\n\n          curl --fail --silent --show-error \\\n               --header \"JOB-TOKEN: ${CI_JOB_TOKEN}\" \\\n               --output \"signatures/${filename}.sig\" \\\n               \"$sig_url\"\n\n          curl --fail --silent --show-error \\\n               --header \"JOB-TOKEN: ${CI_JOB_TOKEN}\" \\\n               --output \"signatures/${filename}.crt\" \\\n               \"$cert_url\"\n\n          if ! cosign verify-blob \\\n            --signature \"signatures/${filename}.sig\" \\\n            --certificate \"signatures/${filename}.crt\" \\\n            --certificate-identity \"${CERTIFICATE_IDENTITY}\" \\\n            --certificate-oidc-issuer \"${CERTIFICATE_OIDC_ISSUER}\" \\\n            \"$file\"; then\n            failed=1\n          fi\n        fi\n      done\n\n      if [ $failed -eq 1 ]; then\n        exit 1\n      fi\n```\n\n\nThis consumer verification stage simulates the end-user experience by:\n\n\n1. Creating a clean environment to test package installation\n\n2. Downloading the published packages from the GitLab PyPI registry\n\n3. Retrieving the corresponding signatures and certificates from the generic\npackage registry\n\n4. Performing the same verification steps that end users would perform\n\n5. Ensuring the entire process works from a consumer's perspective\n\n6. Failing the pipeline if any verification step fails, providing an early\nwarning of any issues\n\n\n## Summary\n\n\nThis comprehensive pipeline provides a secure and reliable way to build,\nsign, and publish Python packages to GitLab's package registry. By following\nthese practices and implementing the suggested security measures, you can\nensure your packages are appropriately verified and safely distributed to\nyour users.\n\n\nThe pipeline combines modern security practices with efficient automation to\ncreate a robust software supply chain. Using Sigstore's Cosign for signing\nand attestation, along with GitLab's built-in security features, you can\nprovide users with trustworthy cryptographically verified packages.\n\n\n> #### Get started on your security journey today with a [free trial\nof GitLab\nUltimate](https://gitlab.com/-/trials/new?glm_content=default-saas-trial&glm_source=about.gitlab.com).\n\n\n## Learn more\n\n- [Documentation: Use Sigstore for keyless signing and\nverification](https://docs.gitlab.com/ee/ci/yaml/signing_examples.html)\n\n- [Streamline security with keyless signing and verification in\nGitLab](https://about.gitlab.com/blog/keyless-signing-with-cosign/)\n\n- [Annotate container images with build provenance using Cosign in GitLab\nCI/CD](https://about.gitlab.com/blog/annotate-container-images-with-build-provenance-using-cosign-in-gitlab-ci-cd/)\n",[716,9,281,742,785,108,493,807,998],{"slug":3015,"featured":90,"template":696},"secure-and-publish-python-packages-a-guide-to-ci-integration","content:en-us:blog:secure-and-publish-python-packages-a-guide-to-ci-integration.yml","Secure And Publish Python Packages A Guide To Ci Integration","en-us/blog/secure-and-publish-python-packages-a-guide-to-ci-integration.yml","en-us/blog/secure-and-publish-python-packages-a-guide-to-ci-integration",{"_path":3021,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3022,"content":3028,"config":3033,"_id":3035,"_type":13,"title":3036,"_source":15,"_file":3037,"_stem":3038,"_extension":18},"/en-us/blog/secure-and-safe-login-and-commits-with-gitlab-yubico",{"title":3023,"description":3024,"ogTitle":3023,"ogDescription":3024,"noIndex":6,"ogImage":3025,"ogUrl":3026,"ogSiteName":683,"ogType":684,"canonicalUrls":3026,"schema":3027},"Secure and safe login and commits with GitLab + Yubico","Learn how GitLab and Yubico have partnered to strengthen software development security through robust authentication measures.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663259/Blog/Hero%20Images/REFERENCE_-_display_preview_for_blog_images__3_.png","https://about.gitlab.com/blog/secure-and-safe-login-and-commits-with-gitlab-yubico","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Secure and safe login and commits with GitLab + Yubico\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2025-04-02\",\n      }",{"title":3023,"description":3024,"authors":3029,"heroImage":3025,"date":3030,"body":3031,"category":716,"tags":3032},[1220],"2025-04-02","We live in a time where data breaches and phishing attacks make daily\nheadlines. These breaches can cause harm to an organization, such as\nregulatory fines, business downtime, or even worse, reputational damage. In\nterms of authentication, passwords have been the backbone of online security\nfor decades, however, they're increasingly proving inadequate against\nsophisticated cyber threats.\n\n\nGitLab and [Yubico](https://www.yubico.com/) have partnered to strengthen\nsoftware development security through robust authentication measures. Yubico\nis the inventor of the YubiKey, a hardware security key that delivers\nphishing-resistant multi-factor authentication (MFA). By implementing FIDO\nUniversal 2nd Factor (U2F) and YubiKey hardware protection, GitLab offers\ndevelopers a powerful defense against phishing attacks and other cyber\nthreats, ensuring their code and projects remain secure. This collaboration\nexpands enterprise-grade authentication in the GitLab platform, allowing\nprogrammers to focus on creating software while maintaining confidence in\ntheir account's integrity.\n\n\nThis article explains how to configure GitLab to use YubiKeys to protect\ndevelopers from online threats. You’ll also learn how to further prevent\ntampering with GitLab verified commits.\n\n\n## How YubiKeys work\n\n\nAt their core, YubiKeys function as cryptographic hardware tokens that\ngenerate and store private keys in a secure element. These keys implement\nFIDO2/WebAuthn authentication protocols, which can be used as an additional\nfactor to login to GitLab.\n\n\nHere's how it works when logging in:\n\n\n1. You enter your username and password.  \n\n2. GitLab sends a cryptographic challenge to your browser.  \n\n3. Your browser requests the YubiKey to sign this challenge.  \n\n4. You physically touch the YubiKey to approve.\n\n5. The YubiKey creates a unique cryptographic signature for that specific\nservice and challenge.  \n\n6. GitLab verifies the signature using your public key stored during setup.\n\n\nMost major security breaches involve compromised passwords. Adding a YubiKey\nsecures your account from a remote breach, even if your password is stolen,\nso you can rest assured that your GitLab account is secure. Additional key\nsecurity benefits of using YubiKey for authentication with GitLab include:\n\n\n* **Phishing protection:** Fake sites won't have the correct cryptographic\nkeys to verify the response. \n\n* **No secrets to steal:** The private key never leaves the YubiKey.  \n\n* **Physical security:** Physical presence is required to use it (you must\ntouch the YubiKey).\n\n\n## Setting up YubiKey multifactor authentication in GitLab\n\n\nNow let’s go over how to set up a Yubikey for multifactor authentication in\nGitLab. Make sure you're using a [supported browser and operating\nsystem](https://support.yubico.com/hc/en-us/articles/360016615020-Operating-system-and-web-browser-support-for-FIDO2-and-U2F)\nas they have better WebAuthn support for hardware security keys.\n\n\n1. First, log in to your GitLab account and go to your user settings (click\nyour avatar in the top left corner and select **Preferences**). \n\n2. In the left sidebar, click on **Account** and navigate to the\n**Two-factor Authentication** section.\n\n3. If you haven't already enabled 2FA, you'll need to do that first.\n\n    a. Click **Enable two-factor authentication**.\n\n    b. Scan the QR code with your authenticator app.\n\n    c. Enter the code from your authenticator app.\n\n    d. Enter your GitLab password. If you ever need to access your GitLab account without using Google authentication, you may need to:\n    * Use the **Forgot password** option on the GitLab login page to set up a separate GitLab password.\n    * Contact your GitLab administrator to help you set up alternative login methods.\n\n   e. Save your recovery codes in a safe place.\n\n4. Once 2FA is enabled, go back to the previous screen by pressing **Manage\ntwo-factor authentication** and scroll down to the **Register hardware\ntoken** section.  \n\n5. Press the **Set up new device** button.  \n    a. A popup from your browser should appear. **Note:** This image may look different depending on your browser. You may also get popups from password managers feel free to ignore them. \n\n![Browser (Brave) Auth\nRequest](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674606/Blog/Content%20Images/browser_auth_request.png)\n\n\n&nbsp; &nbsp; b. Select **Use a phone, tablet, or security key**.\n\n\n6. A new popup will appear.\n\n\n![browser security key\nrequest](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674607/Blog/Content%20Images/browser_security_key_request.png)\n\n\n&nbsp; &nbsp; a. Insert your YubiKey into your computer's USB port.\n\n\n&nbsp; &nbsp; b. Touch the metal contact/button on your YubiKey when\nprompted. The field will automatically fill with a one-time code.\n\n\n7. Enter your GitLab Password and provide a name for your Hardware Key.  \n\n8. Click **Register** to add the YubiKey to your account.\n\n\nCongratulations, your YubiKey is now registered and can be used as a second\nfactor when logging into GitLab! You can register multiple YubiKeys to your\naccount for backup purposes. **Note:** The process may vary slightly among\nbrowsers.\n\n\n![yubikey\nregistered](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674607/Blog/Content%20Images/yubikey_registered.png)\n\n\n\u003Ccenter>\u003Ci>YubiKey registered successfully\u003C/i>\u003C/center>\n\n\n## Signing in with a YubiKey\n\n\nNow that we have our YubiKey configured, we can log in as follows:\n\n\n1. Go to GitLab.com.\n\n\n![GitLab\nlogin](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674607/Blog/Content%20Images/gitlab_login.png)\n\n\n2. Provide your username and password and then press the **Sign in** button.\n\n3. You will be sent to the following screen.\n\n\n![GitLab 2fa\nlogin](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674606/Blog/Content%20Images/2fa_login.png)\n\n\n&nbsp; &nbsp; a. A popup, like the one below, should come up. **Note:** This\nimage may look different depending on your browser. You may also get popups\nfrom password managers; feel free to ignore them.\n\n\n![Browser security key\nrequest](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674607/Blog/Content%20Images/browser_security_key_request.png)\n\n\n&nbsp; &nbsp; b. Insert your YubiKey into your computer's USB port.\n\n\n&nbsp; &nbsp; c. Touch the metal contact/button on your YubiKey when\nprompted. The field will automatically fill with a one-time code.\n\n\nNow, you should be logged in and taken to your GitLab page. **Note:** The\nprocess may vary slightly among browsers.\n\n\n## What happens if I lose my YubiKey?\n\n\nYubico recommends that you use and keep a backup YubiKey. When considering\nyour home, car, or office, you wouldn’t think twice about having a backup\nkey to keep in a safe place. Your digital self should get the same level of\nconsideration. A backup YubiKey kept in a safe place provides a quick and\nsafe backup if your primary YubiKey is lost. Keeping a backup will also\neasily enable you to deactivate the lost YubiKey and add a new primary or\nsecondary YubiKey.\n\n\nIf you do not have an additional YubiKey added, it is recommended to have\nanother form of 2FA added to your accounts. In either case, you should be\nable to get access to your account and remove the lost key from the account.\nPlease note that if a spare key or another authentication method hasn’t been\nadded, you will need to contact the service/website for help with recovering\nyour account.\n\n\n## GitLab verified commits\n\n\nTo further prevent tampering, you can also configure verified commits.\nVerified commits in GitLab use GPG (GNU Privacy Guard) signatures to prove\nthat a commit actually came from you. This adds another layer of security on\ntop of authentication by ensuring that not only is your account secure, but\nevery code change can be cryptographically verified as coming from you.\n\n\nYour YubiKey can store GPG keys:\n\n\n* The private key is stored securely on the YubiKey.  \n\n* The public key is shared with GitLab.\n\n* The key pair is used to sign your commits.\n\n\nOnce the GPG keys have been set up:\n\n\n* When you make a commit, Git uses your private key to create a signature.  \n\n* The GPG key is accessed from the attached YubiKey.  \n\n* The signature is stored with the commit metadata.  \n\n* GitLab verifies the signature using your public key.\n\n\n## Setting up verified commits\n\n\nLet’s go over how to configure verified commits. In this example, the GPG\nkey will live inside your YubiKey, providing an extra layer of security.\n\n\n1. Install required software.\n\n\n```bash\n\n# On macOS\n\nbrew install --cask yubico-yubikey-manager\n\nbrew install gnupg gpg yubikey-manager\n\n\n# On Ubuntu/Debian\n\nsudo apt install gnupg gpg yubikey-personalization\n\n\n# On Windows\n\n# Download and install Gpg4win from https://gpg4win.org\n\n```\n\n\n2. Check YubiKey GPG status.\n\n\n```bash\n\ngpg --card-status\n\n```\n\n3. Generate GPG keys directly on YubiKey (more secure).\n\n\n```bash\n\n# Start GPG edit mode\n\ngpg --card-edit\n\n\n# Enter admin mode\n\nadmin\n\n\n# Generate key directly on card\n\n# PIN = '123456' | Admin PIN = '12345678'\n\ngenerate\n\n\n# Follow prompts\n\n# See documentation for more info \n\n#\nhttps://support.yubico.com/hc/en-us/articles/360013790259-Using-Your-YubiKey-with-OpenPGP\n\n```\n\n\n4. Export your public key.\n\n\n```bash\n\n# Get your key ID\n\ngpg --list-secret-keys --keyid-format LONG\n\n\n# Export the public key\n\ngpg --armor --export YOUR_KEY_ID\n\n```\n\n\n5. Add the public key to GitLab.\n\n    a. Click on your GitLab Avatar and select **Preferences**.\n\n    b. On the side tab select **GPG Keys**.\n\n    c. Click **Add new key**.\n\n    d. Paste your public key.\n\n    e. Click **Add key**.\n\n6. Configure Git.\n\n\n```bash\n\n# Set signing key\n\ngit config --global user.signingkey YOUR_KEY_ID\n\n\n# Enable automatic signing\n\ngit config --global commit.gpgsign true\n\n\n# Tell GPG which key to use\n\necho \"default-key YOUR_KEY_ID\" >> ~/.gnupg/gpg.conf\n\n```\n\n\n7. Now let’s test the configuration by creating a test commit in a project:\n\n\n```bash\n\n# Make a change in the project\n\n# Add changes\n\ngit add .\n\n\n# Make a test commit\n\ngit commit -S -m \"Test signed commit\"\n\n\n# Verify signature\n\ngit verify-commit HEAD\n\n\n# Push the change\n\ngit push\n\n```\n\n\nThe `git verify-commit HEAD` command should show the GPG key used:\n\n\n```bash\n\ngpg: Signature made Wed Feb 26 11:45:00 2025 CST\n\ngpg:                using RSA key YOUR_KEY_ID\n\ngpg: Good signature from “NAME (DESCRIPTION) \u003CEMAIL>\" [ultimate]\n\n```\n\n\nThen, when viewing the commit in GitLab, you should now see that the commit\nis verified as follows:\n\n\n![Commit is\nverified](https://res.cloudinary.com/about-gitlab-com/image/upload/v1749674607/Blog/Content%20Images/verified.png)\n\n\n\u003Ccenter>\u003Ci>Commit verified with GPG key\u003C/i>\u003C/center>\n\n\u003Cbr>\u003C/br>\n\n\nYou can also use the [commits\nAPI](https://docs.gitlab.com/api/commits/#get-signature-of-a-commit) to\ncheck a commit’s signature allowing you to further operationalize the\nverification workflow.\n\n\n## Learn more\n\n\nTo learn more about GitLab, Yubico, and the solutions each provides, check\nout these resources:\n\n\n* [Why GitLab](https://about.gitlab.com/why-gitlab/)  \n\n* [Why Yubico](https://www.yubico.com/why-yubico/)  \n\n* [GitLab Security and Compliance\nSolutions](https://about.gitlab.com/solutions/security-compliance/)  \n\n* [GitLab listing in the \"Works with YubiKey\"\ncatalog](https://www.yubico.com/works-with-yubikey/catalog/gitlab/)  \n\n* [Verified Commits - GitLab\ndocumentation](https://docs.gitlab.com/ee/user/project/repository/signed_commits/)  \n\n* [Push Rules in\nGitLab](https://docs.gitlab.com/user/project/repository/push_rules/)  \n\n* [Sign Commit with GPG Keys\ndocumentation](https://docs.gitlab.com/user/project/repository/signed_commits/gpg/)\n",[9,716,807,493,1019,742],{"slug":3034,"featured":90,"template":696},"secure-and-safe-login-and-commits-with-gitlab-yubico","content:en-us:blog:secure-and-safe-login-and-commits-with-gitlab-yubico.yml","Secure And Safe Login And Commits With Gitlab Yubico","en-us/blog/secure-and-safe-login-and-commits-with-gitlab-yubico.yml","en-us/blog/secure-and-safe-login-and-commits-with-gitlab-yubico",{"_path":3040,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3041,"content":3047,"config":3052,"_id":3054,"_type":13,"title":3055,"_source":15,"_file":3056,"_stem":3057,"_extension":18},"/en-us/blog/security-features-in-ultimate",{"title":3042,"description":3043,"ogTitle":3042,"ogDescription":3043,"noIndex":6,"ogImage":3044,"ogUrl":3045,"ogSiteName":683,"ogType":684,"canonicalUrls":3045,"schema":3046},"Tired of afterthought security? Take a fresh look at GitLab Ultimate","Security may not be the first thing that comes to mind when thinking of our DevOps platform, but we’re going to make the case it should be. Here’s a look at some of the too-often-overlooked security features in GitLab Ultimate.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667202/Blog/Hero%20Images/gitlabultimatesecurity.jpg","https://about.gitlab.com/blog/security-features-in-ultimate","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Tired of afterthought security? Take a fresh look at GitLab Ultimate\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Cindy Blake\"}],\n        \"datePublished\": \"2020-12-08\",\n      }",{"title":3042,"description":3043,"authors":3048,"heroImage":3044,"date":3049,"body":3050,"category":716,"tags":3051},[2363],"2020-12-08","At GitLab, we have worked hard to make [application security testing](/topics/devsecops/) a natural by-product of software development. We started with the developer, bringing scan results into their native workflow, then we added a dashboard for the security pro. We acquired Gemnasium and most recently [Peach Tech and Fuzzit](/blog/fuzz-testing/). We have a board goal to be a world-class security product and have allocated just under 25% of our R&D budget to these capabilities. \n\nWe know our SAST, dependency, container, and other scanners are great but we’d also bought into the idea that people choose to use our [DevOps platform](/solutions/devops-platform/) largely because of CI or SCM and our security is just an added bonus. \n\nBut it seems we are our own worst critic, especially on how we determine product maturity. Data points include:\n\n* The technology review site G2 shows [GitLab’s static application security testing (SAST) is top rated](https://www.g2.com/categories/static-application-security-testing-sast#grid). \n* As of Dec. 4, 2020, GitLab has an Overall Rating of 4.6 out of 5 in the Application Security Testing market on [Gartner Peer Insights](https://www.gartner.com/reviews/market/application-security-testing/vendor/gitlab/product/gitlab), based on 32 reviews.\n  * _Gartner Peer Insights reviews constitute the subjective opinions of individual end users based on their own experiences and do not represent the views of Gartner or its affiliates._\n* Dev-Insider 2020 Platinum award for [best code and composition analysis](https://www.storage-insider.de/die-leser-haben-entschieden-die-gewinner-der-it-awards-2020-a-973498/).\n\nAnd customers are noticing too:\n\n* “GitLab Secure replaced Veracode, Checkmarx, and Fortify in my DevOps toolchain. GitLab scans faster, is more accurate, and doesn’t require my developers to learn new tools.” \t\n\n* “GitLab Secure enables us to ship faster. Our other scanner tools could take up to a day to finish scanning whereas GitLab scans finish in as little a few minutes.” \n\nHere’s a look at other built-in security features in Ultimate for self hosted and Gold for SaaS.\n\n## Vulnerability scans (no assembly required)\n\nIf there are two truths in security, it’s these: The more you scan, the less risk you will have, and it’s cheaper to find and fix vulnerabilities in development than later in the lifecycle. Developers need access to that data in their workflow. GitLab Ultimate/Gold offers comprehensive scanning, out of the box with no integration required: [dynamic](https://docs.gitlab.com/ee/user/application_security/dast/) and [static](https://docs.gitlab.com/ee/user/application_security/sast/) (now including mobile apps), [container scanning](https://docs.gitlab.com/ee/user/application_security/container_scanning/), [dependency scanning](https://docs.gitlab.com/ee/user/application_security/dependency_scanning/), [API scanning](https://docs.gitlab.com/ee/user/application_security/dast/#api-scan), and [fuzz testing](https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing/), along with scanning for [secrets](https://docs.gitlab.com/ee/user/application_security/secret_detection/) and [license compliance](https://docs.gitlab.com/ee/user/compliance/license_compliance/). All of these scans are built into the workflow with results presented in the MR pipeline – meaning busy developers don’t have to go hunting for results. \n\nThe scans are also easy to apply for security pros. With one click, you can choose what to do via AutoDevOps, or add in third-party scanners via the `ci.yml`. Just start with a [CI job definition](https://docs.gitlab.com/ee/development/integrations/secure.html#job-definition). We’ve even added a handy UX so non-developers can modify the `ci.yml` without coding (add link). By using CI templates you can easily set and apply [security policies](https://docs.gitlab.com/ee/user/application_security/configuration/) for merge approvals and more. You can also [limit security scanning to running offline](https://docs.gitlab.com/ee/user/application_security/offline_deployments/) for highly sensitive environments. \n\n## Comprehensive dashboards\n\nWhile this developer-first perspective will reduce vulnerabilities, they can’t all be fixed on the spot. So our [security dashboard](https://docs.gitlab.com/ee/user/application_security/security_dashboard/) capability (included with GitLab Ultimate/Gold) helps security pros manage remaining vulnerabilities. It provides a single source of truth, eliminating translation and friction between development and security, and makes it simple for anyone to see the status of remediation work, who changed what, where and when, and even who approved merge requests across the entire software development lifecycle.\n\nAnd because we know compliance also plays a key role in security, we have a dedicated [compliance dashboard](https://docs.gitlab.com/ee/user/compliance/compliance_report/index.html) that gathers key data to ensure quick and accurate reporting. \n\n## Container monitoring\n\nDevOps teams taking advantage of the modularity of containers also need a way to keep all the moving parts safe. Gitlab Ultimate offers [container threat monitoring](https://docs.gitlab.com/ee/user/application_security/) in addition to container scanning.\n\n## Integrated fuzz testing\n\nThanks to our acquisition of Peach and FuzzIt, GitLab Ultimate now offers integrated [coverage-guided fuzzing and continuous fuzzing](/topics/devsecops/what-is-fuzz-testing/), adding new types of testing previously unavailable.\n\nCover image by [Zhen Hu](https://unsplash.com/@zhenhu2424) on [Unsplash](https://unsplash.com)\n{: .note}\n",[716,851,742,9],{"slug":3053,"featured":6,"template":696},"security-features-in-ultimate","content:en-us:blog:security-features-in-ultimate.yml","Security Features In Ultimate","en-us/blog/security-features-in-ultimate.yml","en-us/blog/security-features-in-ultimate",{"_path":3059,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3060,"content":3065,"config":3071,"_id":3073,"_type":13,"title":3074,"_source":15,"_file":3075,"_stem":3076,"_extension":18},"/en-us/blog/security-scan-experience",{"title":3061,"description":3062,"ogTitle":3061,"ogDescription":3062,"noIndex":6,"ogImage":819,"ogUrl":3063,"ogSiteName":683,"ogType":684,"canonicalUrls":3063,"schema":3064},"My experience interning to work with security scanning at GitLab","Experience with doing a 4 week internship implementing security scans","https://about.gitlab.com/blog/security-scan-experience","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"My experience interning to work with security scanning at GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Eric Rosenberg\"}],\n        \"datePublished\": \"2020-08-04\",\n      }",{"title":3061,"description":3062,"authors":3066,"heroImage":819,"date":3068,"body":3069,"category":714,"tags":3070},[3067],"Eric Rosenberg","2020-08-04","\n\n{::options parse_block_html=\"true\" /}\n\n\n\nMy name is Eric Rosenberg and I am a support engineer at GitLab.  I’ve always had an interest in security and have spent my support career with \na goal in mind to one day work in a security position.  After speaking with some of our security team members, and directors, I was chosen to\nparticipate in a 4 week security internship to implement security scanners on some selected open source projects that we have hosted on GitLab.\n\nI wanted to explain the details of my internship and share my experience to hopefully help others that may be chosen for similar internships, \nand also spread knowledge about the scanners that GitLab offers.\n\nThe internship that I took part in was to integrate [GitLab Secure](https://docs.gitlab.com/ee/user/application_security/) features into \nopen-source projects that are hosted on GitLab.com to improve those projects, increase awareness of GitLab’s security offerings, and get us \nvaluable feedback to help us improve the product.  Some of the goals to achieve personally were to help others understand how simple it is to \nadd security into their pipelines, build my knowledge of using our scanners and working through any issues along the way, and to help provide \nfeedback not only to the project owners but also back to GitLab.\n\n## What I did\n\nMy first week was mainly prep work in order to find a few projects that I could reach out to, and hopefully work with, the project’s \nmaintainers/owners.  I wanted to explain the internship, what my goals were, and how the security scans could be beneficial.  I also wanted to \nhave a stable testing environment that I could copy the project over to, so that I would not interfere with their project, just in case they \ndid not want to participate and also so I would not make any changes that could potentially cause issues on their end. I wanted to also run \nthrough all of the [security scan types](https://docs.gitlab.com/ee/user/application_security/#security-scanning-tools) on my own projects so \nthat I could become more familiar with what the scans were, how to use them, and how to read their output.  I decided to focus mainly on \nproject [ASE](https://gitlab.com/ase/ase) as the project owner was happy to have some extra added security, as well as a point of contact for \nquestions on scanning their code.\n\nThe second week I had a project owner, [ASE](https://gitlab.com/ase/ase), reply to my email and was very interested in working with me.  He \nexplained he was busy and may not have a lot of time to communicate with me, however he was happy to have me take lead and add the scans so \nthat I could provide the results back to him.  I was able to copy the project to my test instance, run the scans, provide the results, and in \nthe end submit an MR so that they could implement the scans on their end and use them moving forward.  \n\nThe third week was mainly focussed on the results from the scans and helping provide the answers to many questions the project owner had.  This \nwas expected and greatly appreciated from my point of view as this not only showed me that the project owner had a lot of interest in keeping \nthe project secure, but it challenged me to work with the members of our security team and build my knowledge of what needed to be done so that \nI was able to then relay this information back to the project owner.  I felt that I gained a lot of information and towards the end of the \nweek, I was very comfortable discussing steps to not only use the scanners but to make changes to the code to keep things secure.  Using the \nSAST scanner (Static Application Security Testing) I was able to scan the Ruby code and print out known vulnerabilities within the Security & \nCompliance dashboard within the admin area.  One of the things I found interesting was finding “false negatives” when it came to the \nvulnerability report.  For example: “Password in URL detected; please remove and revoke it if this is a leak.”  This would cause alarm to \nanyone that views this in their security & compliance dashboard, however after taking a further look, the password that was being displayed was \nonly an example, which caused no issues.  \n\nMy fourth week I wanted to dedicate to wrapping up my internship and providing as much feedback as possible.  I was able to keep notes along \nthe way, as well as one on one meetings with my internship mentor every week.  I felt that the communication was amazing when it was needed.  I \nwas able to reach out over slack anytime and either receive the answers I needed, or I was pointed in the correct location so that I could \ndiscuss with the team.\n\n## Closing Thoughts\n\nSome feedback I would like to add is that the timing, while being sufficient enough to handle what I needed, was not long enough for what I \nwould have hoped for.  I would have wished for more time to work on different projects, with different project owners, in order to provide a \nbetter outcome of variety within the time of my internship.  That being said, since security is still a focus of mine, I am glad that GitLab \nallows me the flexibility to still keep in contact with the project owners I worked with, and I am happy to continue to help them with the \nknowledge I have learned from doing this internship, and I cant wait to learn even more.  \n\nI believe that in the near future, we will be able to provide internships that can open more opportunities for GitLab team members to be \ninvolved with security type positions and raise interests in working in security.  I know that it is tough to extend a “shadowing” type \ninternship into the security field as there is more sensitive data being dealt with, but hopefully this internship will continue to be offered \nand grow to even higher possibilities.\n\nOverall, I am extremely happy that I was chosen to take part in this internship, and I would hope to work more with the team in the future.  I \nhave learned a lot and I look forward to using this knowledge to help others including team members and project owners.\n",[108,9,716],{"slug":3072,"featured":6,"template":696},"security-scan-experience","content:en-us:blog:security-scan-experience.yml","Security Scan Experience","en-us/blog/security-scan-experience.yml","en-us/blog/security-scan-experience",{"_path":3078,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3079,"content":3085,"config":3091,"_id":3093,"_type":13,"title":3094,"_source":15,"_file":3095,"_stem":3096,"_extension":18},"/en-us/blog/self-managed-support-gitlab-for-jira-app",{"title":3080,"description":3081,"ogTitle":3080,"ogDescription":3081,"noIndex":6,"ogImage":3082,"ogUrl":3083,"ogSiteName":683,"ogType":684,"canonicalUrls":3083,"schema":3084},"Self-managed support extended to GitLab for Jira App","Connect GitLab with the Jira development panel to sync merge requests, commits, and transition Jira issue statuses from GitLab.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749682573/Blog/Hero%20Images/jason-goodman-Oalh2MojUuk-unsplash.jpg","https://about.gitlab.com/blog/self-managed-support-gitlab-for-jira-app","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Self-managed support extended to GitLab for Jira App\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Grant Hickman\"}],\n        \"datePublished\": \"2023-01-12\",\n      }",{"title":3080,"description":3081,"authors":3086,"heroImage":3082,"date":3088,"body":3089,"category":763,"tags":3090},[3087],"Grant Hickman","2023-01-12","\n\nDeveloping fast feedback loops is a core tenet of DevOps and is critical to the communication required between planning functions and engineering teams. GitLab provides many integrated features for Agile Planning within the DevSecOps Platform, but we understand the importance of supporting tools used within the broader DevOps ecosystem. This is why we’ve partnered with Atlassian to provide additional (and more straightforward) support between GitLab and Atlassian Jira, via the GitLab for Jira app.\n\n## GitLab for Jira app: Proxy for Self-Managed GitLab\n\nFor Jira Cloud, the GitLab for Jira app now officially supports integration with both GitLab SaaS and GitLab Self-Managed, making it easier to identify the ideal integration based on the type of installation mix you may have.\n\nWith the GitLab for Jira app, you can: \n\n- Display merge requests, commits, pipelines, deployments, feature flags, and branches directly in the Jira Development Panel, creating a quick view into progress on feature development.\n- Link commits, commit messages, and issue comments by mentioning the Jira Issue ID.\n- Transition issues from a commit, saving developers time from context switching across tools.\n- Add time tracking or custom comments to an issue with Smart Commits.\n\n## Configuring the GitLab for Jira app with GitLab Self-Managed\n\nHere are the steps to take to configure the GitLab for Jira app with GitLab Self-Managed: \n\n1. Visit the GitLab for Jira App in the Atlassian Marketplace.\n1. Click “Get it now”.\n1. Choose “GitLab (self managed)” Note: this requires a GitLab Admin role.\n1. Configure your [Instance OAuth App in GitLab](https://docs.gitlab.com/ee/integration/jira/connect-app.html#connect-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances).\n1. Provide your instance URL.\n1. Sign in to your GitLab instance.\n1. Link your namespace.\n\n## Limitations and considerations\n\n1. If you have implemented the GitLab for Jira app manually via App Manifest, proceed with caution. This is our first iteration and we’ll be improving the workflow to make it easier to migrate to the official GitLab for Jira app from the App Manifest approach.\n1. Traffic will be routed through GitLab.com for the GitLab for Jira app to configure the integration. \n1. To configure the integration, you will need to be an admin of the Jira project and the GitLab instance to enable the integration.\n\n## Deprecation and removal of Jira Cloud support for DVCS integration\n\nAs the GitLab for Jira app now supports GitLab Self-Managed, this is the recommended path for integration between Jira Cloud and GitLab (for GitLab.com and GitLab Self-Managed). The GitLab DVCS connector will only support Jira Server and Jira Data Center moving forward. Jira Cloud support within the DVCS integration is [deprecated and will be removed in %16.0](https://docs.gitlab.com/ee/update/deprecations.html#jira-github-enterprise-dvcs-integration).\n\nTo simplify how to choose which integrations are a fit for you, see below:\n\n1. Are you using Jira Cloud?\n    1. Use the [GitLab for Jira app](https://marketplace.atlassian.com/apps/1221011?tab=overview&hosting=cloud).\n    2. You can also use the [GitLab Jira Integration](https://docs.gitlab.com/ee/integration/jira/configure.html) with the GitLab for Jira app.\n\n2. Are you using Jira Server or Jira Data Center?\n    1. Use the [Jira DVCS Connector](https://docs.gitlab.com/ee/integration/jira/dvcs.html)\n    2. You can also use the [GitLab Jira Integration](https://docs.gitlab.com/ee/integration/jira/configure.html) with the Jira DVCS Connector.\n\n## Options for using the GitLab for Jira app with GitLab Self-Managed\n\nWith this release, you may now configure the [GitLab for Jira app directly from the Atlassian Marketplace](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?tab=overview&hosting=cloud). This gives you a guided workflow for enabling the app and leverages GitLab.com as a proxy for your self-managed instance, for purposes of enabling the integration.\n\nAlternatively, you may also install the GitLab for Jira app by fetching a manifest file or creating your own Marketplace listing. To explore these approaches, you can [visit our documentation](https://docs.gitlab.com/ee/integration/jira/connect-app.html#install-the-gitlabcom-for-jira-cloud-app-for-self-managed-instances).\n\n### Read more\n\n- [Epic](https://gitlab.com/groups/gitlab-org/-/epics/5650) about the extension of self-managed support to GitLab from Jira app\n- [How to integrate GitLab.com with Jira Cloud](/blog/integrating-gitlab-com-with-atlassian-jira-cloud/)\n- [Documentation](https://docs.gitlab.com/ee/integration/jira/connect-app.html) on GitLab.com for Jira Cloud app\n\n_Cover image by [Jason Goodman](https://unsplash.com/@jasongoodman_youxventures?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://www.unsplash.com)._\n",[742,9,281],{"slug":3092,"featured":6,"template":696},"self-managed-support-gitlab-for-jira-app","content:en-us:blog:self-managed-support-gitlab-for-jira-app.yml","Self Managed Support Gitlab For Jira App","en-us/blog/self-managed-support-gitlab-for-jira-app.yml","en-us/blog/self-managed-support-gitlab-for-jira-app",{"_path":3098,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3099,"content":3105,"config":3112,"_id":3114,"_type":13,"title":3115,"_source":15,"_file":3116,"_stem":3117,"_extension":18},"/en-us/blog/sentry-integration-blog-post",{"title":3100,"description":3101,"ogTitle":3100,"ogDescription":3101,"noIndex":6,"ogImage":3102,"ogUrl":3103,"ogSiteName":683,"ogType":684,"canonicalUrls":3103,"schema":3104},"Sentry's GitLab integration streamlines error remediation","Your code has bugs, my code has bugs, everyone’s code has bugs (probably). Let’s fix that.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749679964/Blog/Hero%20Images/sentry-io-blog.jpg","https://about.gitlab.com/blog/sentry-integration-blog-post","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Streamline and shorten error remediation with Sentry’s new GitLab integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Eva Sasson\"}],\n        \"datePublished\": \"2019-01-25\",\n      }",{"title":3106,"description":3101,"authors":3107,"heroImage":3102,"date":3109,"body":3110,"category":691,"tags":3111},"Streamline and shorten error remediation with Sentry’s new GitLab integration",[3108],"Eva Sasson","2019-01-25","\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/KUHk1uuXWhA?rel=0\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nSentry is open source error tracking that gives visibility across your entire stack and provides the details you need to fix bugs, ASAP. Because the only thing better than visibility and details is more visibility and details, Sentry improved their [GitLab integration](https://docs.sentry.io/workflow/integrations/global-integrations/gitlab/?utm_source=GitLab&utm_medium=blog&utm_campaign=GitLab_GTM) by adding [release](https://docs.sentry.io/workflow/releases/?platform=browser&utm_source=GitLab&utm_medium=blog&utm_campaign=GitLab_GTM) and [commit](https://docs.sentry.io/workflow/releases/?platform=browser&utm_source=GitLab&utm_medium=blog&utm_campaign=GitLab_GTM#link-repository) tracking as well as [suspect commits](https://docs.sentry.io/workflow/releases/?platform=browser&utm_source=GitLab&utm_medium=blog&utm_campaign=GitLab_GTM#after-linking-a-repository).\n\n### Streamline your workflow with issue management and creation\n\nWhen you receive an alert about an error, the last thing you want to do is to jump around 20 different tools trying to find out exactly what happened and where. Developers with both Sentry and GitLab in their application lifecycle benefit from issue management and issue creation to their GitLab accounts directly in the Sentry UI, alleviating some of the hassle of back-and-forth tool toggling.\n\n![GitLab account in Sentry](https://about.gitlab.com/images/blogimages/sentry/gitlab-sentry-integration.png){: .shadow.large.center}\n\nOf course, less tool jumping results in a more streamlined triaging process and shortened time to issue resolution – something that benefits the whole team.\n\n![Creating GitLab issue](https://about.gitlab.com/images/blogimages/sentry/create-gitlab-issue.png){: .shadow.medium.center}\n\nHave a GitLab issue that wasn’t created in Sentry? No problem. Existing issues are also easily linked.\n\n![Import GitLab issue](https://about.gitlab.com/images/blogimages/sentry/import-gitlab-issue.png){: .shadow.medium.center}\n\n### Find and fix bugs faster with release and commit tracking\n\nWhy stop at streamlining the triaging process, when we can also make issue resolution more efficient? Sentry’s GitLab integration now utilizes GitLab commits to find and fix bugs faster.\n\nWith the newly added release and commit tracking, an enhanced release overview page uncovers new and resolved issues, files changed, and authors. Developers can also resolve issues via commit messages or merge requests, see suggested assignees for issues, and receive detailed deploy emails.\n\nWant a big flashing arrow that points to an error’s root cause? Sentry’s suspect commits feature exposes the commit that likely introduced an error as well as the developer who wrote the broken code.\n\n![Suspect commits feature](https://about.gitlab.com/images/blogimages/sentry/suspect-commits-feature.png){: .shadow.medium.center}\n\nKeep in mind that this feature is available for Sentry users on “Teams” plans and above.\n{: .note}\n\nCheck out [Sentry’s GitLab integration documentation](https://docs.sentry.io/workflow/integrations/global-integrations/gitlab/?utm_source=GitLab&utm_medium=blog&utm_campaign=GitLab_GTM) to get started.\n\n### What’s next?\n\nAgain, why stop there, when we can do even more? GitLab is currently working to bring Sentry into the GitLab interface. Soon, GitLab and Sentry users will see their Sentry errors listed in their GitLab projects. Read the documentation on [the integration here](https://docs.gitlab.com/ee/operations/error_tracking.html).\n\n### About the guest author\n\nEva Sasson is a Product Marketer at [Sentry.io](https://sentry.io/welcome/), an open source error-tracking tool that gives developers the contextual information they need to resolve issues quickly, and integrates with the other development tools across the stack.\n",[108,717,851,9,693,716,1989,2745,872],{"slug":3113,"featured":6,"template":696},"sentry-integration-blog-post","content:en-us:blog:sentry-integration-blog-post.yml","Sentry Integration Blog Post","en-us/blog/sentry-integration-blog-post.yml","en-us/blog/sentry-integration-blog-post",{"_path":3119,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3120,"content":3126,"config":3132,"_id":3134,"_type":13,"title":3135,"_source":15,"_file":3136,"_stem":3137,"_extension":18},"/en-us/blog/serverless-js-project-template",{"title":3121,"description":3122,"ogTitle":3121,"ogDescription":3122,"noIndex":6,"ogImage":3123,"ogUrl":3124,"ogSiteName":683,"ogType":684,"canonicalUrls":3124,"schema":3125},"Starting a serverless JS project with GitLab","Introduction to the new serverless JS project template at GitLab","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680997/Blog/Hero%20Images/clouds-cover.jpg","https://about.gitlab.com/blog/serverless-js-project-template","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Starting a serverless JS project with GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mike Greiling\"}],\n        \"datePublished\": \"2020-01-14\",\n      }",{"title":3121,"description":3122,"authors":3127,"heroImage":3123,"date":3129,"body":3130,"category":714,"tags":3131},[3128],"Mike Greiling","2020-01-14","{::options parse_block_html=\"true\" /}\n\n\n\n\n\u003C!-- Content start here -->\n\n\nIf you've been working in web development these past few years than you've\nno doubt heard about [serverless](/topics/serverless/) FaaS solutions like\nAWS Lambda or Knative. The idea boils down to writing code as a set of\ndiscrete functions that can be triggered by events. All worries about\nprovisioning server nodes, scaling them, managing your back-end stack, and\nmany other operational tasks are abstracted away. Moreover, it often results\nin massive cost savings as compute resources are provisioned on-demand. As\nthis paradigm is growing in maturity and popularity, many tools have been\ncreated to make the process even easier and there has never been a better\ntime to try it out for yourself.\n\n\nTo demonstrate how easy it is to get started with FaaS in GitLab, we've now\nadded a project template to get you up and running even faster. If you're\ninterested in wading into the serverless waters without running a single\ncommand in your terminal, follow along and try it yourself! All that is\nneeded for this example is a free GitLab account and an AWS account.\n\n\n### 1. Creating a project\n\n\nTo start off, let's create a project with our new serverless template. Open\nup the [new project](https://gitlab.com/projects/new) page and select the\n\"Create from template\" tab. Then scroll down and select the \"Serverless\nFramework/JS\" template.\n\n\n![Step\n1](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-1.1.jpg){:\n.shadow.medium.center}\n\n\nGive your project a name and select \"Create project\"\n\n\n### 2. Configuring your AWS credentials\n\n\nNow that we have our GitLab project complete with a boilerplate serverless\napplication, it's time to give it access credentials to AWS so we can deploy\nit.\n\n\nOpen up the AWS console, sign in, and navigate to the [IAM\nsection](https://console.aws.amazon.com/iam/home). Here you can select\n\"Users\" in the left-hand column, and create a new user using the \"Add user\"\nbutton at the top of the list.\n\n\n![Step\n2-1](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-2.1.jpg){:\n.shadow.medium.center}\n\n\nGive your user a name like \"gitlab-serverless\" and make sure to select the\n\"Programatic access\" checkbox before clicking on \"Next\".\n\n\n![Step\n2-2](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-2.2.jpg){:\n.shadow.medium.center}\n\n\nNow we need to give this user the appropriate permissions to deploy\nserverless functions. On the \"Permissions\" page select \"Attach existing\npolicies directly\" and then click the \"Create policy\" button. This will open\na new window.\n\n\n![Step\n2-3](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-2.3.jpg){:\n.shadow.medium.center}\n\n\nHere you'll need to select the \"JSON\" tab and paste the following policy\nstatement:\n\n\n```json\n\n{\n  \"Statement\": [\n    {\n      \"Action\": [\n        \"apigateway:*\",\n        \"cloudformation:CancelUpdateStack\",\n        \"cloudformation:ContinueUpdateRollback\",\n        \"cloudformation:CreateChangeSet\",\n        \"cloudformation:CreateStack\",\n        \"cloudformation:CreateUploadBucket\",\n        \"cloudformation:DeleteStack\",\n        \"cloudformation:Describe*\",\n        \"cloudformation:EstimateTemplateCost\",\n        \"cloudformation:ExecuteChangeSet\",\n        \"cloudformation:Get*\",\n        \"cloudformation:List*\",\n        \"cloudformation:PreviewStackUpdate\",\n        \"cloudformation:UpdateStack\",\n        \"cloudformation:UpdateTerminationProtection\",\n        \"cloudformation:ValidateTemplate\",\n        \"dynamodb:CreateTable\",\n        \"dynamodb:DeleteTable\",\n        \"dynamodb:DescribeTable\",\n        \"ec2:AttachInternetGateway\",\n        \"ec2:AuthorizeSecurityGroupIngress\",\n        \"ec2:CreateInternetGateway\",\n        \"ec2:CreateNetworkAcl\",\n        \"ec2:CreateNetworkAclEntry\",\n        \"ec2:CreateRouteTable\",\n        \"ec2:CreateSecurityGroup\",\n        \"ec2:CreateSubnet\",\n        \"ec2:CreateTags\",\n        \"ec2:CreateVpc\",\n        \"ec2:DeleteInternetGateway\",\n        \"ec2:DeleteNetworkAcl\",\n        \"ec2:DeleteNetworkAclEntry\",\n        \"ec2:DeleteRouteTable\",\n        \"ec2:DeleteSecurityGroup\",\n        \"ec2:DeleteSubnet\",\n        \"ec2:DeleteVpc\",\n        \"ec2:Describe*\",\n        \"ec2:DetachInternetGateway\",\n        \"ec2:ModifyVpcAttribute\",\n        \"events:DeleteRule\",\n        \"events:DescribeRule\",\n        \"events:ListRuleNamesByTarget\",\n        \"events:ListRules\",\n        \"events:ListTargetsByRule\",\n        \"events:PutRule\",\n        \"events:PutTargets\",\n        \"events:RemoveTargets\",\n        \"iam:CreateRole\",\n        \"iam:DeleteRole\",\n        \"iam:DeleteRolePolicy\",\n        \"iam:GetRole\",\n        \"iam:PassRole\",\n        \"iam:PutRolePolicy\",\n        \"iot:CreateTopicRule\",\n        \"iot:DeleteTopicRule\",\n        \"iot:DisableTopicRule\",\n        \"iot:EnableTopicRule\",\n        \"iot:ReplaceTopicRule\",\n        \"kinesis:CreateStream\",\n        \"kinesis:DeleteStream\",\n        \"kinesis:DescribeStream\",\n        \"lambda:*\",\n        \"logs:CreateLogGroup\",\n        \"logs:DeleteLogGroup\",\n        \"logs:DescribeLogGroups\",\n        \"logs:DescribeLogStreams\",\n        \"logs:FilterLogEvents\",\n        \"logs:GetLogEvents\",\n        \"s3:CreateBucket\",\n        \"s3:DeleteBucket\",\n        \"s3:DeleteBucketPolicy\",\n        \"s3:DeleteObject\",\n        \"s3:DeleteObjectVersion\",\n        \"s3:GetObject\",\n        \"s3:GetObjectVersion\",\n        \"s3:ListAllMyBuckets\",\n        \"s3:ListBucket\",\n        \"s3:PutBucketNotification\",\n        \"s3:PutBucketPolicy\",\n        \"s3:PutBucketTagging\",\n        \"s3:PutBucketWebsite\",\n        \"s3:PutEncryptionConfiguration\",\n        \"s3:PutObject\",\n        \"sns:CreateTopic\",\n        \"sns:DeleteTopic\",\n        \"sns:GetSubscriptionAttributes\",\n        \"sns:GetTopicAttributes\",\n        \"sns:ListSubscriptions\",\n        \"sns:ListSubscriptionsByTopic\",\n        \"sns:ListTopics\",\n        \"sns:SetSubscriptionAttributes\",\n        \"sns:SetTopicAttributes\",\n        \"sns:Subscribe\",\n        \"sns:Unsubscribe\",\n        \"states:CreateStateMachine\",\n        \"states:DeleteStateMachine\"\n      ],\n      \"Effect\": \"Allow\",\n      \"Resource\": \"*\"\n    }\n  ],\n  \"Version\": \"2012-10-17\"\n}\n\n```\n\n\n> Note: This policy is an example that encompasses pretty much everything\nthe Serverless framework _might_ need on AWS, but much of it not likely to\nbe used. You may wish to restrict this policy to fit your needs and security\nrequirements. At minimum, the serverless credentials will need access to the\n`cloudformation`, `iam`, `lambda`, `logs`, and `s3` functions specified\nabove.\n\n\n![Step\n2-4](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-2.4.jpg){:\n.shadow.medium.center}\n\n\nClick \"Review Policy\" and you'll need to give this policy a name. I've used\n\"GitLabServerlessPolicy\". Then click \"Create policy\".\n\n\nAfter this is done, return to your \"Add user\" tab and search for the policy\nyou just created (you may need to hit the \"refresh\" icon on the right).\nCheck the box next to this policy and select the \"Next\" button.\n\n\n![Step\n2-5](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-2.5.jpg){:\n.shadow.medium.center}\n\n\nProceed to add tags or skip straight to the review. The final page should\nresemble the following:\n\n\n![Step\n2-6](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-2.6.jpg){:\n.shadow.medium.center}\n\n\nAfter clicking \"Create user\" you should finally be presented with a page\nthat shows you your access credentials for this new AWS user account. Select\n\"show\" next to the \"secret access key\" and copy both this and the access key\nID someplace for safe keeping.\n\n\n### 3. Entering your AWS credentials\n\n\nReturning back to GitLab, we'll need to enter these two credentials into our\nproject's [CI/CD settings](/topics/ci-cd/). Select \"Settings -> CI/CD\" in\nthe left-hand menu.\n\n\n![Step\n3-1](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-3.1.jpg){:\n.shadow.small.center}\n\n\nOn this page, we need to expand the Variables section and enter our AWS\ncredentials:\n\n\n![Step\n3-2](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-3.2.jpg){:\n.shadow.medium.center}\n\n\nUse `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` as the keys for the two\nvalues you copied from AWS in the previous step. Don't forget to click \"Save\nvariables\".\n\n\n### 4. Deploying your first AWS Lambda function.\n\n\nNow it's time to deploy your serverless project. If you're doing this on\ngitlab.com you've already got access to a GitLab runner with 2,000 free CI\npipeline minutes, if not you'll need to [configure a runner\nyourself](https://docs.gitlab.com/runner/#install-gitlab-runner).\n\n\nGo to \"CI/CD -> Pipelines\" in the left-hand menu and click the \"Run\nPipeline\" button. For fun, let's enter an environment variable with the key\n`A_VARIABLE` and give it whatever value you want. This will be usable by our\ndeployed function.\n\n\n![Step\n4-1](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-4.1.jpg){:\n.shadow.medium.center}\n\n\nSelect \"Run Pipeline\" and you should see your jobs start running. This\nproject template has tests which will automatically run every time you run a\npipeline. Once those are complete, the \"production\" job will deploy your\ncode to AWS Lambda and finally it will produce a landing page on [GitLab\nPages](https://docs.gitlab.com/ee/user/project/pages/). After just\na few minutes this process should complete and you can visit \"Settings ->\nPages\" to see a link to the URL where your GitLab project has been deployed.\n(It may take a few minutes before this URL is accessible the first time you\nmake a deployment).\n\n\n![Step\n4-2](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-4.2.jpg){:\n.shadow.medium.center}\n\n\nWhen you visit this page, here's what you'll see:\n\n\n![Step 4\nResult](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-4.3.gif){:\n.shadow.medium.center}\n\n\nYou can enter an input value and click \"run function\". This input is sent to\nyour serverless function which then responds and the response is printed\nunder \"Function Output:\". Note that the environment value we provided using\nthe `A_VARIABLE` key is present as well.\n\n\n### 5. Making Changes\n\n\nNow that we have a working AWS serverless project, let's try to make our own\nfunction. How about a simple calculator?\n\n\nOpen up the Web IDE and let's make the following changes:\n\n\nWithin `src/handler.js` add the following function:\n\n\n```javascript\n\nmodule.exports.add = async function(event) {\n  const A = Number(event.queryStringParameters.A);\n  const B = Number(event.queryStringParameters.B);\n  const result = A + B;\n\n  return {\n    statusCode: 200,\n    headers: {\n      \"Access-Control-Allow-Origin\": \"*\"\n    },\n    body: result\n  };\n};\n\n```\n\n\nThen open `public/index.html` and replace it with:\n\n\n```html\n\n\u003C!DOCTYPE html>\n\n\u003Chtml>\n  \u003Chead>\n    \u003Ctitle>GitLab Serverless Framework example\u003C/title>\n  \u003C/head>\n  \u003Cbody>\n    \u003Ch3>Add two values:\u003C/h3>\n    \u003Clabel>A: \u003Cinput type=\"text\" id=\"inputA\" placeholder=\"0\" name=\"A\"/>\u003C/label>\n    \u003Clabel>B: \u003Cinput type=\"text\" id=\"inputB\" placeholder=\"0\" name=\"B\"/>\u003C/label>\n    \u003Cstrong>=\u003C/strong>\n    \u003Cspan id=\"functionOutput\">?\u003C/span>\n    \u003Cbr />\n    \u003Cbutton>Calculate!\u003C/button>\n\n    \u003Cscript>\n      fetch(\"./stack.json\").then(response => {\n        response.json().then(myJson => {\n          const functionUrl = myJson.ServiceEndpoint + \"/add\";\n          const inputA = document.querySelector(\"#inputA\");\n          const inputB = document.querySelector(\"#inputB\");\n          const output = document.querySelector(\"#functionOutput\");\n\n          document.querySelector(\"button\").addEventListener(\"click\", () => {\n            const A = Number(inputA.value);\n            const B = Number(inputB.value);\n\n            fetch(functionUrl + \"?A=\" + A + \"&B=\" + B)\n              .then(response => response.text())\n              .then(result => (output.textContent = result));\n          });\n        });\n      });\n    \u003C/script>\n  \u003C/body>\n\u003C/html>\n\n```\n\n\nLastly, open `serverless.yml` and add an \"add\" function entry below our\n\"hello\" function like so:\n\n\n```yml\n\nfunctions:\n  hello:\n    handler: src/handler.hello\n    events:\n      - http:\n          path: hello\n          method: get\n          cors: true\n  add:\n    handler: src/handler.add\n    events:\n      - http:\n          path: add\n          method: get\n          cors: true\n```\n\n\nStage and commit these changes directly to the `master` branch. This will\nhave triggered a new pipeline automatically. You can visit \"CI/CD ->\nPipelines\" and watch it run.\n\n\nOnce the deployment is complete, our project page should look like this:\n\n\n![Step 5\nResult](https://about.gitlab.com/images/blogimages/serverless-js-project-template/step-5.1.gif){:\n.shadow.medium.center}\n\n\nVoilà, we've just created our own serverless function and deployed it\nwithout a single terminal command. There's a lot more you can do from here,\nbut this should be a good place to get started. Happy coding!\n\n\n\u003C!-- Content ends here -->\n\n\nCover image by [Kaushik Panchal](https://unsplash.com/@kaushikpanchal) on\n[Unsplash](https://unsplash.com/)\n\n{: .note}\n",[9,742,850],{"slug":3133,"featured":6,"template":696},"serverless-js-project-template","content:en-us:blog:serverless-js-project-template.yml","Serverless Js Project Template","en-us/blog/serverless-js-project-template.yml","en-us/blog/serverless-js-project-template",{"_path":3139,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3140,"content":3146,"config":3152,"_id":3154,"_type":13,"title":3155,"_source":15,"_file":3156,"_stem":3157,"_extension":18},"/en-us/blog/sfdx-promo-trailhead-blog",{"title":3141,"description":3142,"ogTitle":3141,"ogDescription":3142,"noIndex":6,"ogImage":3143,"ogUrl":3144,"ogSiteName":683,"ogType":684,"canonicalUrls":3144,"schema":3145},"Salesforce developers can now use GitLab for complete DevOps","Learn what’s possible with GitLab and Salesforce, whether you’re looking to reduce cycle time or increase collaboration across cross-functional teams.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749680624/Blog/Hero%20Images/gitlab-salesforce.png","https://about.gitlab.com/blog/sfdx-promo-trailhead-blog","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Salesforce developers can now use GitLab's single application for the DevOps lifecycle\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mayank Tahilramani\"}],\n        \"datePublished\": \"2019-05-29\",\n      }",{"title":3147,"description":3142,"authors":3148,"heroImage":3143,"date":3149,"body":3150,"category":298,"tags":3151},"Salesforce developers can now use GitLab's single application for the DevOps lifecycle",[1769],"2019-05-29","\n\nGreat news – we're partnering with Salesforce to offer developers more [agile delivery practices](/solutions/agile-delivery/) and [increased automation](https://docs.gitlab.com/ee/topics/autodevops/) throughout the DevOps lifecycle. Developers can leverage the following capabilities from GitLab for Salesforce DX: [Source Code Management (SCM)](/solutions/source-code-management/), [Continuous Integration (CI) and Continuous Delivery (CD)](/solutions/continuous-integration/), [Project Management](https://about.gitlab.com/solutions/agile-delivery/), and [much more](/pricing/feature-comparison/). Many businesses already run on Salesforce and are just starting to explore the latest and greatest that Salesforce DX has to offer in terms of tooling and functionality to rapidly build apps and enhancements onto their platform. Our partnership with Salesforce will help our customers to reduce cycle times and [deliver business value at the speed of business](/blog/align-business-strategy-and-app-delivery/).\n\n## How GitLab + Salesforce DX work together\n\nSalesforce has been investing in APIs and platform features that allow developers to create and administer Salesforce-connected apps in a more direct and efficient way. With GitLab, developers can now supplement Salesforce development tools through a [templatized CI/CD pipeline](https://gitlab.com/sfdx/sfdx-cicd-template) which leverages [Scratch Orgs](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs.htm) and [packaging](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp_plan_pkg_types.htm) for a structured and frictionless development experience. It’s easier than ever to get started with new Salesforce projects using our new [Salesforce project template](https://gitlab.com/sfdx/sfdx-project-template), and adopt a collaborative development workflow across teams.\n\nFor example, Salesforce development projects stored in GitLab SCM enable developers to work in a Git-based workflow similar to [GitLab Flow](https://docs.gitlab.com/ee/topics/gitlab_flow.html), while transparently collaborating through [issue tracking](https://docs.gitlab.com/ee/user/project/issues/) and [merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/). In this case, each developer can seamlessly create an ad hoc Git branch focused on specific development and functionality of code, allowing for small but continuous incremental changes. Each commit within a branch goes through automated testing and deployment into a Scratch Org.\n\nUpon approval, the changes are then packaged and deployed into a Sandbox Org and, ultimately, into production. GitLab CI/CD aims to automate the use of packaging for predictable Salesforce deployments. In this workflow example, each developer is able to leverage short-lived Scratch Orgs for development and testing of code in a much more Agile fashion.\n\n![Tanuki Badge](https://about.gitlab.com/images/blogimages/gitlab-salesforce-tanuki-badge.png){: .small.right.wrap-text}\n\n## Get hands on with a new Trailhead module and promo\n\nLearning by doing is the best way to get started. Check out our new Trailhead Module, \"[Build an automated CI/CD pipeline with GitLab](https://trailhead.salesforce.com/content/learn/projects/automate-cicd-with-gitlab)\" and learn how to automate your Salesforce development to increase productivity. Earn your Salesforce/GitLab Tanuki badge today!\n\n[Get started now.](/free-trial/)\n{: .alert .alert-gitlab-purple .text-center}\n",[851,9,763],{"slug":3153,"featured":6,"template":696},"sfdx-promo-trailhead-blog","content:en-us:blog:sfdx-promo-trailhead-blog.yml","Sfdx Promo Trailhead Blog","en-us/blog/sfdx-promo-trailhead-blog.yml","en-us/blog/sfdx-promo-trailhead-blog",{"_path":3159,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3160,"content":3166,"config":3171,"_id":3173,"_type":13,"title":3174,"_source":15,"_file":3175,"_stem":3176,"_extension":18},"/en-us/blog/sourcegraph-code-intelligence-integration-for-gitlab",{"title":3161,"description":3162,"ogTitle":3161,"ogDescription":3162,"noIndex":6,"ogImage":3163,"ogUrl":3164,"ogSiteName":683,"ogType":684,"canonicalUrls":3164,"schema":3165},"Native code intelligence is coming to GitLab","We're enhancing code review with Sourcegraph – no extra plugins required.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749673090/Blog/Hero%20Images/random_code.jpg","https://about.gitlab.com/blog/sourcegraph-code-intelligence-integration-for-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Native code intelligence is coming to GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Mayank Tahilramani\"}],\n        \"datePublished\": \"2019-11-12\",\n      }",{"title":3161,"description":3162,"authors":3167,"heroImage":3163,"date":3168,"body":3169,"category":691,"tags":3170},[1769],"2019-11-12","\nAlmost a year ago, our CEO [Sid Sijbrandij](/company/team/#sytses) opened an issue proposing [GitLab integrate with Sourcegraph to provide advanced code navigation and cross-referencing functionality for source code we host](https://gitlab.com/gitlab-org/gitlab/issues/20642). We knew this feature would be a big improvement to the Developer UX in our product, particularly for efficient code review. We also knew [Sourcegraph](https://about.sourcegraph.com/) has an open-core product with one of the best-in-class code navigation capabilities. It only made sense to have a tighter integration between the two products.\n\n## How we built this\n\nSo, our generous friends at Sourcegraph got to work. A [browser extension supporting GitLab](https://docs.sourcegraph.com/integration/gitlab) was already available, but Sourcegraph collaborated with our engineering and product management teams and added the integration directly to the GitLab codebase – powered by GitLab.com and Sourcegraph.com. The integration gives users a fully browser-based developer platform, with no extra plugins required.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/LjVxkt4_sEA\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\nGitLab CEO and co-founder Sid Sijbrandij and Sourcegraph CEO and co-founder Quinn Slack explain the new integration.\n{: .note.text-center}\n\nFor now, get a sneak preview of how our integration with Sourcegraph works by watching a [quick screencast tutorial](https://vimeo.com/372226334/de668e24fa).\n\nThe process of building the integration between Sourcegraph and GitLab is a great example of our [transparency](https://handbook.gitlab.com/handbook/values/#transparency) and [collaboration](https://handbook.gitlab.com/handbook/values/#collaboration) values at work.\n\n## Collaboration in the open\n\n[Sourcegraph’s contribution to GitLab](https://gitlab.com/gitlab-org/gitlab/merge_requests/16556) is significant for developer productivity. For example, their merge request (MR) adds native support for features like ‘go-to-definition’ and ‘find references’ within a hover tooltip. Users can engage the tooltip UI in code views, file views, merge requests, and code diffs. Developers can stay in context during code reviews when they need to investigate a function implementation by simply hovering over the name of the function to navigate efficiently. Within the tooltip, users can see the definition of the function, navigate to the definition, or show other references in the code where the function is being used. In addition to making code reviews higher quality and more efficient, developers will have an easier time investigating complex implementations when reading the source of their favorite library. With Sourcegraph, we’re enabling developers with a richer UX by gathering more information about the code they are reading.\n\nSee for yourself by reading the discussions on the [MR](https://gitlab.com/gitlab-org/gitlab/merge_requests/16556) and viewing changes made to the code. As always, we’re collaborating in the open and encourage the community to provide constructive feedback on our project. Drop a line in the blog comments to share your thoughts.\n\nFor a more detailed overview of the UX of functionality and features, check out [this blog post](https://about.sourcegraph.com/blog/gitlab-integrates-sourcegraph-code-navigation-and-code-intelligence) by Christina Forney, product manager at Sourcegraph.\n\n## What does this mean for our users?\n\nGitlab’s integration with Sourcegraph will be available in our [12.5 release](/upcoming-releases/) on November 22, 2019. We aim to provide code intelligence and code navigation functionality in this integration which was historically provided by the Sourcegraph’s browser extension. Now that we built this integration the browser extension is no longer needed to provide this functionality.\n\nIn the spirit of [iteration](https://handbook.gitlab.com/handbook/values/#iteration) our rollout strategy on GitLab.com is to **first dogfood** the functionality within our [*gitlab-org*](https://gitlab.com/gitlab-com/) group, which is where GitLab stores [source code for GitLab.com](/solutions/source-code-management/) and GitLab Enterprise. Over time, we aim to roll out Sourcegraph capabilities across code views within projects to all *public projects* on GitLab.com. Users will still require the browser extension configured to a private instance of Sourcegraph for **private projects** on GitLab.com.\n\nIf you’re self-managing your GitLab EE deployment and would like to enable Sourcegraph code intelligence, you must have a private Sourcegraph instance running as an external service. This is required because Sourcegraph.com does not index any private code for privacy and security reasons. We will have formal documentation on how to get started with GitLab EE and Sourcegraph soon, but if you’re super curious, [you can see our work in progress here](https://gitlab.com/gitlab-org/gitlab/blob/ps-sourcegraph-playground/doc/integration/sourcegraph.md) within the MR branch.\n\n## What’s next?\n\nStay tuned for our 12.5 release announcement on November 22 and updates containing details around our integration with Sourcegraph. Give us a [thumbs up](https://gitlab.com/gitlab-org/gitlab/merge_requests/16556) if you like what we’re working on. If you’re new to Sourcegraph and/or GitLab, [sign up here](https://gitlab.com/users/sign_up) and install [the browser extension](https://docs.sourcegraph.com/integration/gitlab#browser-extension) to test out these features right away. [Here is a link to a file in one of our public projects where you can test out these features](https://gitlab.com/gitlab-org/gitlab-runner/blob/master/executors/ssh/executor_ssh.go).\n\n[Cover photo](https://unsplash.com/photos/qjnAnF0jIGk) by [Markus Spiske](https://unsplash.com/@markusspiske) on Unsplash.\n{: .note}\n",[108,850,9],{"slug":3172,"featured":6,"template":696},"sourcegraph-code-intelligence-integration-for-gitlab","content:en-us:blog:sourcegraph-code-intelligence-integration-for-gitlab.yml","Sourcegraph Code Intelligence Integration For Gitlab","en-us/blog/sourcegraph-code-intelligence-integration-for-gitlab.yml","en-us/blog/sourcegraph-code-intelligence-integration-for-gitlab",{"_path":3178,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3179,"content":3185,"config":3193,"_id":3195,"_type":13,"title":3196,"_source":15,"_file":3197,"_stem":3198,"_extension":18},"/en-us/blog/stackpoint-gitlab-integration",{"title":3180,"description":3181,"ogTitle":3180,"ogDescription":3181,"noIndex":6,"ogImage":3182,"ogUrl":3183,"ogSiteName":683,"ogType":684,"canonicalUrls":3183,"schema":3184},"GitLab K8s clusters: Backup and trusted charts in 10 min","StackPointCloud partners with GitLab to create a simple, turn-key experience for developers who want to move faster into production with their apps.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671181/Blog/Hero%20Images/stackpoint-gitlab-integration.png","https://about.gitlab.com/blog/stackpoint-gitlab-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Turn-Key GitLab Enterprise Kubernetes clusters, backup, trusted charts — all in less than 10 minutes\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Matt Baldwin\"}],\n        \"datePublished\": \"2017-07-10\",\n      }",{"title":3186,"description":3181,"authors":3187,"heroImage":3182,"date":3189,"body":3190,"category":298,"tags":3191},"Turn-Key GitLab Enterprise Kubernetes clusters, backup, trusted charts — all in less than 10 minutes",[3188],"Matt Baldwin","2017-07-10","\n\n[Stackpoint.io](https://stackpointcloud.com/) is excited to announce we’ve worked with GitLab to enable an end-to-end turn-key solution that will help developers move even faster from idea to production.\n\n\u003C!-- more -->\n\nStackpoint.io advances the mandate of allowing developers to continue to focus on building product, leaving configuring the tooling to GitLab and Stackpoint.io. With this release, together, users can manage and collaborate on their clusters and ensure Gitlab EE is operating correctly — all in a turn-key, developer-friendly way.\n\nOur Kubernetes cloud management platform now allows you to:\n\n* Build a GitLab EE Kubernetes cluster on the cloud of your choice - Google Compute, AWS, or Azure-in three easy steps.\n* Deploy GitLab EE to an existing Kubernetes cluster.\n* Upgrade your GitLab EE Kubernetes cluster in one click.\n* Set up a Kubernetes backup schedule-store in Google or Amazon, recover anywhere.\n* Get all your operational components, pre-configured, at build or run time-Sysdig for monitoring, Twistlock for security, Elasticsearch with Fluentd and Kibana for logging, and more.\n* Allow your developers quick and easy access to operational tools, trimmed down. For example, they can dive into their cluster’s Prometheus metrics – one click.\n\n![StackPoint integration with GitLab](https://about.gitlab.com/images/blogimages/stackpoint-integration.png)\n\nOur GitLab integration not only allows you to run a self-healing deployment of GitLab EE on Kubernetes, but we’ve also integrated Docker Registry automatically, if you’re running on AWS we set up ELB for you and secure it all with Let’s Encrypt.\n\n## Get started\n\n1. Get a new GitLab EE Kubernetes cluster up, running, and configured for production within 10 minutes.\n\n2. Deploy your first app to Kubernetes using GitLab.\n\n3. Schedule your protection of your cluster.\n\nGive it a shot [now](https://stackpoint.io/#/clusters/new?provider=aws&solution=gitlab_ee).\n",[1040,3192,9],"webcast",{"slug":3194,"featured":6,"template":696},"stackpoint-gitlab-integration","content:en-us:blog:stackpoint-gitlab-integration.yml","Stackpoint Gitlab Integration","en-us/blog/stackpoint-gitlab-integration.yml","en-us/blog/stackpoint-gitlab-integration",{"_path":3200,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3201,"content":3206,"config":3211,"_id":3213,"_type":13,"title":3214,"_source":15,"_file":3215,"_stem":3216,"_extension":18},"/en-us/blog/stackpoint-webcast-recording-highlights",{"title":3202,"description":3203,"ogTitle":3202,"ogDescription":3203,"noIndex":6,"ogImage":3182,"ogUrl":3204,"ogSiteName":683,"ogType":684,"canonicalUrls":3204,"schema":3205},"Demo: Turn-key Kubernetes with StackPoint.io","StackPointCloud CEO Matt Baldwin shows how GitLab users can now go even faster from idea to production with an integration that takes the pain out of building Kubernetes clusters.","https://about.gitlab.com/blog/stackpoint-webcast-recording-highlights","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Demo: Turn-key Kubernetes with StackPoint.io\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2017-08-03\",\n      }",{"title":3202,"description":3203,"authors":3207,"heroImage":3182,"date":3208,"body":3209,"category":298,"tags":3210},[1790],"2017-08-03","\n\nStackPointCloud [partnered with us](/blog/stackpoint-gitlab-integration/) to bring you an end-to-end, turn-key Kubernetes solution, speeding up the process from idea to production. Watch the turn-key piece in action in our recent webcast.\n\n\u003C!-- more -->\n\nKubernetes allows you to manage an application across different resources and clouds, enabling self-healing (so if a container dies, it will be rescheduled on another host) and scaling up on demand, or scaling down as needed to save costs. With a host of benefits, it's no surprise that there's a strong and active community around Kubernetes, but for some teams, the time and effort required to install and configure a Kubernetes cluster could be better spent elsewhere.\n\nWhile GitLab covers every step of the software development lifecycle, we do require you to have a Kubernetes cluster up and running before you begin to use it, which is where some users get stuck. Watch the video below to see how our friends at [StackPoint.io](https://stackpointcloud.com/) have worked with us on a solution that does the hard work for you, to \"close the last mile\" in under 10 minutes. The demo starts at 12:02.\n\n\u003Ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/wu2AIcwjeQ8\" frameborder=\"0\" allowfullscreen>\u003C/iframe>\n\nWant to give it a try for yourself? [Launch a Kubernetes cluster with GitLab in one click](https://goo.gl/qnSp3N).\n",[1040,9],{"slug":3212,"featured":6,"template":696},"stackpoint-webcast-recording-highlights","content:en-us:blog:stackpoint-webcast-recording-highlights.yml","Stackpoint Webcast Recording Highlights","en-us/blog/stackpoint-webcast-recording-highlights.yml","en-us/blog/stackpoint-webcast-recording-highlights",{"_path":3218,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3219,"content":3225,"config":3231,"_id":3233,"_type":13,"title":3234,"_source":15,"_file":3235,"_stem":3236,"_extension":18},"/en-us/blog/staff-level-engineering-at-gitlab",{"title":3220,"description":3221,"ogTitle":3220,"ogDescription":3221,"noIndex":6,"ogImage":3222,"ogUrl":3223,"ogSiteName":683,"ogType":684,"canonicalUrls":3223,"schema":3224},"What does Staff level mean at GitLab?","Get a multifaceted view of Staff level Engineering at GitLab","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681092/Blog/Hero%20Images/staff-engineering.jpg","https://about.gitlab.com/blog/staff-level-engineering-at-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"What does Staff level mean at GitLab?\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Charlie Ablett\"}],\n        \"datePublished\": \"2020-02-18\",\n      }",{"title":3220,"description":3221,"authors":3226,"heroImage":3222,"date":3228,"body":3229,"category":714,"tags":3230},[3227],"Charlie Ablett","2020-02-18","\n\n{::options parse_block_html=\"true\" /}\n\n\n\n## What does Staff level mean at GitLab?\n\nAt GitLab, [Backend Engineers](https://handbook.gitlab.com/job-families/engineering/backend-engineer/) and [Frontend Engineers](https://handbook.gitlab.com/job-families/engineering/development/frontend/)\nwork together with Product, Design, Quality, and Security to improve the product and address technical challenges.\nAt the [Senior](https://handbook.gitlab.com/job-families/engineering/backend-engineer/#senior-backend-engineer) level,\nthey are expected to address the most complex challenges within their engineering team, as well as help their team members with technical blockers and process improvements.\n\nWhen considering a [career path or direction](/handbook/engineering/career-development/#roles) within GitLab,\nSenior Engineers — both Backend and Frontend — can choose either to advance on the management track to become an [Engineering Manager](https://handbook.gitlab.com/job-families/engineering/engineering-management/),\nor on the individual contributor (technical) track to become a [Staff Backend Engineer](https://handbook.gitlab.com/job-families/engineering/backend-engineer/#staff-backend-engineer)\nor [Staff Frontend Engineer](https://handbook.gitlab.com/job-families/engineering/development/frontend/staff/).\nEach job description gives some idea of the responsibilities of a Staff Engineer role, but how does that look in practice?\n\nCurrent and previous Staff Backend Engineers and Engineering Managers kindly agreed to talk to me in a series of one-on-one interviews.\nAs someone considering the technical track to become a Staff Backend Engineer, I wanted to find out what exactly it entails.\nMuch of what each engineer said overlapped, but each had a unique perspective based on their team and their particular experience within GitLab as an entity.\n\n**note**: The following is based on the experience of Staff backend engineers at GitLab, but there will be future\nexplorations into the world of Staff level of Design, Technical Writing, and other positions that can be Staff.\n\nThe following sums up the perspective of each of the engineers, with my takeaway _in italics_.\n\n## What Staff Backend Engineers said\n\n[**Jacob Vosmaer**, @jacobvosmaer-gitlab](https://gitlab.com/jacobvosmaer-gitlab) (Amsterdam, the Netherlands), leverages his chronological knowledge of GitLab from when it was small enough to be understood by one person.\nThis gives him the foundation to understand the product from a systemic perspective.\nGitLab is now an [enterprise-scale](/enterprise/) complex project, and uses many third-party open-source libraries as part of its product.\n\u003Cbr/>\n_A Staff Engineer can recognize a good solution when they see one, and able to clearly explain its merits to other engineers, community members, managers or customers._\n\n[**Sean McGivern**, @smcgivern](https://gitlab.com/smcgivern) (Edinburgh, Scotland) provided some historical context - Staff used to mean a role specifically on a team, but now it's more of a multidisciplinary role.\nThe impact of Staff Engineers is predicated not purely on advanced technical skill, but their ability to collaborate across teams.\nAs a former Engineering Manager, he identified an overlap between the leadership skills and time management skills required by Staff Engineers and Engineering Managers.\n\u003Cbr/>\n_A Staff Engineer has a broad skill-set with in-depth expertise in several areas (see ['Paint Drip' people](https://www.facebook.com/notes/kent-beck/paint-drip-people/1226700000696195/)*)._\n\n[**Ash McKenzie**, @ashmckenzie](https://gitlab.com/ashmckenzie) (Geelong, Australia) noted that reaching beyond his team can mean finding and identifying a niche that needs a champion, and working to improve it without oversight.\nIn Ash's case, his high-leverage work on the GitLab Development Kit (GDK) means he can help every person working on the GitLab codebase to become more efficient by removing technical blockers in the GDK itself.\n\u003Cbr/>\n_A Staff Engineer leverages their increasingly on-demand time to help others, efficiently unblock them and enable them to move forward._\n\n[**Nick Thomas**, @nick.thomas](https://gitlab.com/nick.thomas) (Shetland, Scotland) identified that one way to thrive at the Staff level was to identify systemic improvements.\nThis may involve slow, steady identification of system-level challenges, rather than solving immediate time-sensitive issues.\n\u003Cbr/>\n_A Staff Engineer is asked for technical opinions more often than at Senior level, and it allows them to have a greater technical and cultural impact._\n\n[**Andreas Brandl**, @abrandl](https://gitlab.com/abrandl) (Hamburg, Germany) noted that levels above Senior require increasing familiarity with the company, processes and culture in order to thrive.\nBecause GitLab encourages anyone in the company to [question anything](https://handbook.gitlab.com/handbook/values/#anyone-and-anything-can-be-questioned), it allows dynamic, iterative improvements to processes.\nStaff level engineers can demonstrate this publicly and encourage, enable and support others to do the same.\n\u003Cbr/>\n_A Staff Engineer questions anything, looks for process improvements and encourages the documentation of processes for clarity and transparency._\n\n[**Dylan Griffith**, @DylanGriffith](https://gitlab.com/DylanGriffith) (Sydney, Australia) emphasized the role of reaching out beyond your team and collaborating with others across GitLab and in the wider community.\nBy familiarising themselves with the vision of the product itself as well as its business value, this allows Staff Engineers the ability to better identify cross-team issues that may have escaped notice.\n\u003Cbr/>\n_A Staff Engineer identifies and addresses cross-team problems that may otherwise fall through the cracks and liaises with management, Product and customers to steward delivery to completion._\n\n[**Fabien Catteau**, @fcatteau](https://gitlab.com/fcatteau) (Compiègne, France) focused on knowledge management and transfer within the context of a broader technological vision, which complements the Product vision.\nSince GitLab is an enterprise-scale product, nobody can know everything - so Staff level engineers balance sharing what they know and being comfortable with asking for help.\nIt's important to understand what skills and knowledge are missing from a discussion, reaching out to who knows the missing piece, and bringing them into the conversation.\n\u003Cbr/>\n_A Staff level engineer not only focuses on constantly improving their own knowledge of the product, but enthusiastically empowers other developers to do the same._\n\n[**Rémy Coutable**, @rymai](https://gitlab.com/rymai) (Cannes, France) spoke particularly on having the courage to address problems outside your team or area of expertise.\nAs a Staff level engineer, your ability to show the values by example is amplified.\nVisibly asking for help and bringing in experts from other area of the product encourages others to do the same.\n\u003Cbr/>\n_A Staff Engineer reaches beyond immediate technical needs, independently considering the longer-term, and is always looking beyond for ways to have a broad impact._\n\n[**Grzegorz Bizon**, @grzesiek](https://gitlab.com/grzesiek) (Olsztyn, Poland) explained the difference between Senior and Staff as not much different technically,\nbut a Staff level engineer collaborates more with other team members and leverages their understanding of human nature to broaden their impact across the product.\nHe emphasised kindness as one of the most important values, and at Staff level there is greater opportunity, and responsibility, to help others.\n\u003Cbr/>\n_A Staff Engineer is kind, supporting others and helping them grow and succeed in a holistic way, not just limited to technical help._\n\n[**Rachel Nienaber**, @rnienaber](https://gitlab.com/rnienaber) (London, UK) has a unique perspective as an Engineering Manager who has helped multiple Engineers attain promotions, including one to Staff level.\nShe emphasised leveraging leadership competencies to facilitate technological discussions and either owning or delegating projects to completion.\nUsing your voice in technical discussion is like a muscle - the more you use it, the more natural the activity feels and the more confident you will become to contribute more often.\nSo she encourages all engineers to contribute in discussions, even if they aren't always 100% certain.\n\u003Cbr/>\n_A Staff Engineer dovetails technical strategy to product strategy, helping the team to be more productive while interfacing with other teams._\n\n[**Yorick Peterse**, @yorickpeterse](https://gitlab.com/yorickpeterse) (Hilversum, the Netherlands) described Staff level Engineering in terms of anticipating future needs and understanding the broader technical vision of the product.\nTo him, Staff level engineers proactively identify problems, define scope and work with stakeholders, Product and team management.\nThe expectations of quality, technical acumen and communication skills are higher once an engineer hits Staff level, as well as ongoing collaboration outside the team.\n\u003Cbr/>\n_A Staff Engineer bridges the gap between Management focusing on capacity planning and timing for the future, and individual contributors carrying out the work._\n\n",[9],{"slug":3232,"featured":6,"template":696},"staff-level-engineering-at-gitlab","content:en-us:blog:staff-level-engineering-at-gitlab.yml","Staff Level Engineering At Gitlab","en-us/blog/staff-level-engineering-at-gitlab.yml","en-us/blog/staff-level-engineering-at-gitlab",{"_path":3238,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3239,"content":3245,"config":3250,"_id":3252,"_type":13,"title":3253,"_source":15,"_file":3254,"_stem":3255,"_extension":18},"/en-us/blog/tasktop-gitlab-integration",{"title":3240,"description":3241,"ogTitle":3240,"ogDescription":3241,"noIndex":6,"ogImage":3242,"ogUrl":3243,"ogSiteName":683,"ogType":684,"canonicalUrls":3243,"schema":3244},"One step closer to DevOps success with GitLab + Tasktop","Good news for enterprise devs: flow GitLab Issues into your Agile tool for greater visibility and collaboration.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749671305/Blog/Hero%20Images/tasktop-integration-cover.png","https://about.gitlab.com/blog/tasktop-gitlab-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"One step closer to DevOps success with GitLab + Tasktop\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2017-09-15\",\n      }",{"title":3240,"description":3241,"authors":3246,"heroImage":3242,"date":3247,"body":3248,"category":298,"tags":3249},[1790],"2017-09-15","\n\nTasktop, the value stream integration tool for enterprise development teams, has launched their [GitLab Issues Connector](http://www.tasktop.com/integrations/gitlab-issues). Now you can automatically flow GitLab issues bi-directionally into tools such as JIRA, CA Agile Central (formerly Rally), HPE ALM, and VersionOne, facilitating effective DevOps at scale.\n\n\u003C!-- more -->\n\nGitLab Issues have endless applications: from proposing new features, to discussing implementation of new ideas, to obtaining support, an issue can serve a host of different functions.\n\nSo we're happy that Tasktop now makes it even easier to integrate issues into your workflow. It works with both the [Community and Enterprise editions](/stages-devops-lifecycle/) of GitLab to flow issues from GitLab into separate purpose-built tools, such as a development team’s Agile planning tools. An issue is then visible in both GitLab and your planning tool, and is always reflective of the current, up-to-date state. This means everyone is in the picture, whether the bulk of their work is done in GitLab or another tool.\n\nThis is great news for cross-functional teams and [collaboration](https://handbook.gitlab.com/handbook/values/#collaboration) (it's no secret, we're big fans).\n\n## We asked Tasktop, \"Why GitLab?\"\n\n\"There was (and is) strong customer demand for GitLab. We built this integration as it expands our ecosystem, especially in the Issue Tracker space. We see customers needing to connect relatively lightweight issue trackers with agile development tools, typically to allow defects to be sent to developers. GitLab Issues works with any of our connectors, but it makes the most sense when integrating with tools such as JIRA, CA Agile Central, or Microsoft TFS as customers seek to connect their software value stream from end-to-end.\" - Trevor Bruner, Product Manager, Tasktop\n\n## What we say\n\nGitLab VP of Product Job van der Voort:\n\n>\"GitLab allows anyone to reduce their time to value, bringing their ideas to production faster. With the Tasktop integration, yet another hurdle in going from one application to the next is removed. We're excited to see enterprises ship faster and more reliably.\"\n\nThe GitLab Issues Connector is now available in all editions of [Tasktop Integration Hub](https://www.tasktop.com/hub).\n\n*Is this integration the answer to your context-switching troubles? What will you use it for? Let us know in the comments!*\n",[9,851],{"slug":3251,"featured":6,"template":696},"tasktop-gitlab-integration","content:en-us:blog:tasktop-gitlab-integration.yml","Tasktop Gitlab Integration","en-us/blog/tasktop-gitlab-integration.yml","en-us/blog/tasktop-gitlab-integration",{"_path":3257,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3258,"content":3263,"config":3269,"_id":3271,"_type":13,"title":3272,"_source":15,"_file":3273,"_stem":3274,"_extension":18},"/en-us/blog/tasktop-webcast-recap",{"title":3259,"description":3260,"ogTitle":3259,"ogDescription":3260,"noIndex":6,"ogImage":3242,"ogUrl":3261,"ogSiteName":683,"ogType":684,"canonicalUrls":3261,"schema":3262},"Cross-functional ≠ dysfunctional","Don't let process hold you back – here are our best practices for working cross-functionally.","https://about.gitlab.com/blog/tasktop-webcast-recap","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Cross-functional ≠ dysfunctional\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Rebecca Dodd\"}],\n        \"datePublished\": \"2017-11-08\",\n      }",{"title":3259,"description":3260,"authors":3264,"heroImage":3242,"date":3265,"body":3266,"category":3267,"tags":3268},[1790],"2017-11-08","\n\nWe recently teamed up with [Tasktop](https://www.tasktop.com/integrations/gitlab-issues) to talk about processes and how to make sure\nthey work for you instead of against you. Check out the highlights below.\n\n\u003C!-- more -->\n\nCreating great software involves a number of different disciplines, each of\nwhich may use their own tool for managing work. Chaos might seem inevitable, but\nwe've learned that a few guiding principles can help to connect people and keep\nchannels of communication open.\n\n## 1. Goals first, process second\n\nProcess exists to serve goals. Before you put processes in place or continue with existing ones, take a step back to establish what you're trying to achieve. Getting input from all stakeholders to determine goals will help to set clear expectations up front and allow everyone to voice their concerns about the scope of the project. Armed with this information, you can then decide on the best process (including timelines, review cycles and communication vehicles) to achieve the desired outcome.\n\n## 2. Establish a single source of truth\n\nWith so many stages and so much activity involved in creating a product or feature, it can be hard to keep track of what's going on. This potential for chaos is quelled by establishing a single source of truth. So when you've outlined your goals and settled on a process for achieving them, write it all down so that everyone has something to refer to and there's no confusion about what was decided or what stage something is at. This is especially helpful for distributed teams, as it means people in other locations and time zones can get up to speed quickly and collaborators can work asynchronously.  \n\n## 3. Clear, visible outcomes\n\nWhat exactly does success mean for your project? What metrics will you use? You want clear, measurable outcomes for what you're working on, so that everyone can see what's expected of them and others. At GitLab, we use [issue trackers](https://docs.gitlab.com/ee/user/project/issues/) to follow the progress of a new feature or project. Individual issues can be customized to reflect the problem you're trying to solve, how you're going to go about it, and what the outcome should be. Issues can be connected to related [merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/) so that all involved stakeholders can view new developments or changes right away, in a production-like environment. This way concerns or problems can be flagged at any stage along the way.\n\n## 4. Work cross-functionally from start to finish\n\nThe above guidelines only work if all your different functions are in communication. Instead of locking communication per-stage, per team, or per-specialty principle, leave the doors as open as possible. This minimizes risk, as GitLab Product Manager [Victor Wu](/company/team/#victorwu416) explains:\n\n> When you're creating software, and you're creating a feature, you probably want a security stakeholder involved. Security is often something that's tacked on at the end, but if it's baked directly into the design of the software it will be accounted for, and you can estimate the cost or effort required to design and implement something that accounts for security instead of backtracking later.\n\nCross-functional working also encourages a diversity of ideas from different teams contributing to a feature, which can result in a better outcome. You can foster open communication by working more transparently: make your goals, processes and metrics for success visible to your whole organization, if possible, and invite feedback. Use real-time editing tools (such as Google docs) for meetings and allow everyone to add to the agenda, take notes or suggest follow-up items.\n\n## 5. Improve the process in iterations\n\nFeeling inspired? Before you throw out all your existing processes, think about whether you can [iterate](https://handbook.gitlab.com/handbook/values/#iteration) on them instead. Radical change can be difficult for people to embrace, so you may have more success with gradual adjustments. Identify something that's not working well, and a small change you can make to improve on it.\n\n> Try to win those small battles, solve those small problems, week by week and month to month, and over time your process will improve.\n\n## Recording\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/8X6x54gaYRo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n## Slides\n\n\n\u003Cfigure class=\"video_container\">\n\u003Ciframe src=\"https://docs.google.com/presentation/d/e/2PACX-1vRcQw1XTuEk12ALqnrjMSTPLQ9OAm6Mmzn-eIoUOCJgUdX8dVDejdmN_HaK2AW1lVq1iDG7VxmzaXcD/embed?start=false&loop=false&delayms=3000\" frameborder=\"0\" width=\"960\" height=\"569\" allowfullscreen=\"true\" mozallowfullscreen=\"true\" webkitallowfullscreen=\"true\">\u003C/iframe>\n\u003C/figure>\n\nYou can read more about [Tasktop's GitLab integration here](/blog/tasktop-gitlab-integration/).\n","culture",[3192,9,717,872],{"slug":3270,"featured":6,"template":696},"tasktop-webcast-recap","content:en-us:blog:tasktop-webcast-recap.yml","Tasktop Webcast Recap","en-us/blog/tasktop-webcast-recap.yml","en-us/blog/tasktop-webcast-recap",{"_path":3276,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3277,"content":3283,"config":3289,"_id":3291,"_type":13,"title":3292,"_source":15,"_file":3293,"_stem":3294,"_extension":18},"/en-us/blog/teams-gitpod-integration-gitlab-speed-up-development",{"title":3278,"description":3279,"ogTitle":3278,"ogDescription":3279,"noIndex":6,"ogImage":3280,"ogUrl":3281,"ogSiteName":683,"ogType":684,"canonicalUrls":3281,"schema":3282},"Teams speed up development with GitLab's Gitpod integration","Learn about Gitpod as cloud development environment, and how its integration into Gitpod helps teams to get more efficient in their DevOps lifecycle.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667482/Blog/Hero%20Images/cover-image-unsplash.jpg","https://about.gitlab.com/blog/teams-gitpod-integration-gitlab-speed-up-development","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How teams can use the Gitpod integration in GitLab to speed up their development process\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Michael Friedrich\"}],\n        \"datePublished\": \"2021-07-19\",\n      }",{"title":3284,"description":3279,"authors":3285,"heroImage":3280,"date":3286,"body":3287,"category":739,"tags":3288},"How teams can use the Gitpod integration in GitLab to speed up their development process",[1117],"2021-07-19","\n\nTurn back time a bit and try to remember the first project you started or joined, and the onboarding experience. How long did it take to install the development environment on your local machine?\n\nWe talked about our own onboarding experiences into software development, and thought about sharing our favorite tips with GitLab users.\n\n## A developer's tale\n\nEveryone starts fresh, and often best practices are just \"learning by doing,\" requiring documentation in the same moment. Programming languages and application architectures are also different - a C++ backend environment has different requirements than a Ruby on Rails web application.\n\nStart with defining the requirements and stages. Oftentimes they are equivalent to CI/CD pipeline stages but executed in your own environment.\n\n* Compile/build the application and verify that the source code is valid (\"build\")\n* Run linting, unit tests, code quality checks (\"test\")\n* Run the application in a dev environment (\"runtime test\")\n* Package the application, run installation tests (\"staging installation\")\n* Run the installed application (\"staging deployment\")\n* Tag, release, and deploy the application (\"release production deployment\")\n\nYou want to run the application in a development environment quickly, everything else with staging and deployments continues to run in your CI/CD pipelines. Their implementation and availability should be on your to-do list.\n\nSoftware applications can depend on existing libraries which are used by many other developers, and help speed up the development process. These dependencies need to be installed into the development environment - if that is your local macOS, Windows or Linux desktop, methods and requirements will differ.\n\n### Provision development environments\n\nCreating a development environment for many different operating systems has its disadvantages: Error messages can differ and implementation specific details do not produce the same results and require back-and-forth communication on the team. This often leads to friction and slowed down development processes.\n\nOne key learning over the past decade has been to use CI/CD extensively to test different environments and operating systems, and rely on fast feedback in Merge Requests. Developers should be able to focus on their development environment without having to worry about the many production use cases and support.\n\nVirtual machines in Vagrant, and Docker containers made the generic development environment creation easier and efficient. The documentation instructed everyone to either execute `vagrant up` or `docker-compose up -d` and have the development stack ready. The road to creating Vagrant and Docker base images, including the provisioning scripts with Bash, Ansible, Puppet, etc., was and still is a huge learning process. Opinions on \"good\" best practices differ, and adding your preferred IDE on top of a CLI only VM or container often is an adventure on its own.\n\nBandwidth and traffic can also come into play - each provision and software installation run may consume gigabytes of data. If the workloads and provisioning would run in the cloud, your local connection is not affected.\n\nOne customer mentioned a while ago that their company policy forbids installing a local IDE without a license. The Web IDE in GitLab solves this problem for them throughout the onboarding month.\n\n### Development environment in the browser\n\nThe Web IDE helps with basic programming tasks, editing the documentation or setting up the CI/CD configuration. It does not provide a fully fledged server runtime, as cloud IDE with a programming environment capable of understanding the language you are programming in would. Our vision is to explore ways to [add integrated development environments into the Web IDE](/handbook/engineering/incubation/server-runtime/).\n\nThere are a variety of tools and environments following remote collaboration ideas and the cloud IDE approach. You can learn more in [this Twitter thread](https://twitter.com/sytses/status/1400134840754733059) from [GitLab co-founder and CEO, Sid Sijbrandij](/company/team/#sytses). One approach is [Gitpod](https://gitpod.io/), allowing you to spin a fresh environment in the cloud in seconds.\n\nGitpod uses Visual Studio Code (VS Code) as cloud IDE, and integrates with their marketplace to install the same extensions as you would install locally in VS Code. One of the coolest things about Gitpod is that it not only spins up a fresh environment, but also allows you to install additional software or bring your own workspace container image. That way everyone uses the same pre-provisioned environment, and pair programming and debugging becomes a breeze.\n\nNext time, the same state is booted up, secured by single sign-on.\n\n## First steps with Gitpod\n\nNavigate to [gitpod.io](https://gitpod.io) and choose to `continue with GitLab` as login.\n\nIf you are running a self-managed GitLab setup, ask your administrator to [enable the Gitpod integration](https://docs.gitlab.com/ee/integration/gitpod.html).\n\nLet's start with creating a VueJS application. Fork the [learn-vuejs-gitpod](https://gitlab.com/gitlab-de/playground/learn-vuejs-gitpod) project on GitLab.com.\n\n### Alternative: Start on your CLI\n\nAlternatively to forking the project, install NodeJS, npm and the `vue-cli` package, and run `vue create learn-vuejs-gitpod`. The vue command already initializes and commits based on your local Git configuration. Add the remote origin and push to a new repository on the remote GitLab server.\n\n```shell\n$ brew install node\n$ yarn add @vue/cli\n$ vue create learn-vuejs-gitpod\n\n$ cd learn-vuejs-gitpod\n$ git remote add origin https://gitlab.com/\u003Cyourusername>/learn-vuejs-gitpod.git\n$ git push -u origin main\n```\n\nGitLab will [create a private project from the git push command](https://docs.gitlab.com/ee/user/project/working_with_projects.html#create-a-new-project-with-git-push).\n\n### Start Gitpod\n\nStart Gitpod from the repository overview by selecting the dropdown switch from the Web IDE.\n\n![Gitpod VueJS Start](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_gitlab_start_vuejs.png)\n\nSign into your GitLab account with SSO once asked. Accept the required permissions, and wait until the Gitpod environment is booted up.\n\n![Gitpod VueJS Overview](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_vuejs_overview.png)\n\nChange to the terminal and run yarn to install the dependencies and start the development server. No worries, we'll show you how to automate this in a second!\n\n```shell\nyarn install\nyarn serve\n```\n\nGitpod detects the server listening on port 8080 and offers to make it public. Open the browser instead - it works but says `Invalid host header` because the dev server checks the host name. For running inside Gitpod containers, you need to [disable the host checks](https://github.com/gitpod-io/gitpod/issues/26#issuecomment-554058232).\n\nLet's fix this inside Gitpod in the project. Navigate into the left file tree, and add a new file called `vue.config.js` in the top level.\n\n![Gitpod VueJS Overview](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_vuejs_config_disable_host_checks_devserver.png)\n\nCopy the following code snippet into it\n\n```js\n// vue.config.js\nmodule.exports = {\n    // Rationale: https://github.com/gitpod-io/gitpod/issues/26#issuecomment-554058232\n    devServer: {\n        disableHostCheck: true\n    }\n}\n```\n\nAnd stop the running `yarn serve` command in the terminal by pressing `crtl+c`. Press `cursor up` to select the previous command, or type `!!` to repeat the last command followed by `enter` to start the devserver again. Voilà!\n\n![VueJs running app in Gitpod](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_vuejs_web_app.png)\n\nDon't forget to add and commit the new configuration file to persist the changes. Navigate into the `Source Control` section highlighting one pending change. Enter a commit message, click the check mark and approve all pending changes into the commit.\n\n![Gitpod Source Control](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_source_control_add_vuejs_config.png)\n\nSelect the `...` menu to `push` the Git history. Gitpod will ask you for `repository read/write` permissions, walk through the forms and edit them on Gitpod itself. Navigate back to the Gitpod project interface and re-do the push.\n\nFrom the first success, it is not far to your first customized VueJS application. But wait, there is more to learn about Gitpod and efficient workflows!\n\n### VS Code Extensions\n\nNavigate into the `Extensions` menu and search for `gitlab workflow`. Install the extension. We recommend installing it globally for your account and all future workspaces.\n\n![Gitpod extension: GitLab workflow for VS Code](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_extension_gitlab_workflow.png)\n\nNext, navigate into the new GitLab menu item on the left, and configure the extension. It needs a personal access token, similar to the process with a local VS Code extension configuration. Follow the steps in the [Gitlab documentation to create a personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token).\n\n![Gitpod: GitLab workflow extension config](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_gitlab_workflow_extension_config.png)\n\n## Speed up your own projects\n\nUsing Gitpod and GitLab to develop GitLab makes it easy to contribute, but what about your own DevOps lifecycle and projects? Below are a few more examples to speed up your development with Gitpod and GitLab.\n\nRemember: You can start Gitpod without any configuration, directly from a GitLab repository. If there are additional settings needed, you can develop them while learning from the examples and documentation best practices.\n\n### Hugo Pages website live review\n\nYou can use Hugo with GitLab pages to host your own private blog, for example. Hugo is a static site generator written in Go, with public Docker images already available. The deployment of [everyonecancontribute.com](https://everyonecancontribute.com/) uses the following configuration in the [.gitlab-ci.yml](https://gitlab.com/everyonecancontribute/web/everyonecancontribute.gitlab.io/-/blob/main/.gitlab-ci.yml) configuration:\n\n```yaml\n.publish: &publish\n  image: registry.gitlab.com/pages/hugo:latest\n  script:\n    - hugo\n  artifacts:\n    paths:\n    - public\n\npages:\n  stage: publish\n  \u003C\u003C: *publish\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH\n      when: always\n  environment:\n    name: $CI_PROJECT_NAME\n    url: https://$CI_PROJECT_NAME/\n```\n\nA local development environment to preview the website needs the Hugo binary installed. Doing the same in the browser, running the Hugo CLI command and previewing the blog post? We've found a way to provision Gitpod in the same way, using [this .gitpod.yml configuration](https://gitlab.com/everyonecancontribute/web/everyonecancontribute.gitlab.io/-/blob/main/.gitpod.yml):\n\n```yaml\nimage: klakegg/hugo:debian\n\nports:\n  - port: 1313\n\ntasks:\n  - command: hugo server -D -b $(gp url 1313) --appendPort=false\n```\n\nThe Hugo container image gets pulled and the Gitpod workspace builder prepares the environment. Note that [Alpine based images do not work](https://github.com/gitpod-io/gitpod/issues/3356#issuecomment-877604994), use Debian variants instead. After starting the workspace, the tasks run the command, and expose a port. The port binding needs to be the external URL of the pod, not localhost. `gp url 1313` builds the exact URL, and binds the socket to the Hugo server, making the pod URL publicly accessible for reviews.\n\n![Gitpod: Hugo website](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_hugo_everyonecancontribute_com.png)\n\nFrom there, you can switch branches in Gitpod, and immediately verify the changes.\n\n### VueJS with custom container image\n\nGetting started with VueJS in a new project with the `vue-cli` package is very convenient and the Gitpod docs have a [guide](https://www.gitpod.io/docs/languages/vue/#vue-cli) ready. The default `gitpod/workspace-full` image does not provide the `vue cli` package. You can extend the container image by using your [custom .gitpod.Dockerfile](https://www.gitpod.io/docs/config-docker#configure-a-custom-dockerfile) - Gitpod takes care of building the image first, and later starts the workspace based on it.\n\n```yaml\nFROM gitpod/workspace-full\n\nRUN yarn add @vue/cli\n```\n\nThe `.gitpod.yml` configuration file needs to be instructed to build and use a custom image. On startup, the `tasks` section runs the initial dependency installation, and starts the development environment with `yarn serve`. The server listens on port 5000 by default, this is what gets [exposed](https://www.gitpod.io/docs/config-ports), and instructed to open as call-to-action in the browser.\n\n\n```yaml\nimage:\n  file: .gitpod.Dockerfile\n\ntasks:\n  - init: yarn install\n    command: yarn serve\n\nports:\n  - port: 5000\n    onOpen: open-browser\n```\n\nYou can combine Gitpod for previewing the website with the production deployment using the [five minute production app deployment template](https://gitlab.com/gitlab-org/5-minute-production-app/deploy-template) shown in [this project](https://gitlab.com/gitlab-de/playground/5-min-prod-app-vuejs). GitLab takes care of provisioning a free AWS EC2 instance, TLS certificates and domain handling.\n\n### More Gitpod workspace images\n\nGitpod provides many [ready-to-use workspace images](https://github.com/gitpod-io/workspace-images). In order to use them, create the `.gitpod.yml` file with this content:\n\n```yaml\nimage:\n  file: .gitpod.Dockerfile\n```\n\nCreate a new `.gitpod.Dockerfile` file and add the import from the desired workspace image.\n\n```yaml\nFROM gitpod/workspace-mysql\n```\n\nIf you need to install additional software, note that the full workspace image is based on Debian and therefore you'll need to use the `apt` package manager. The following command updates the package index, and clears the cache after installation to keep the image clean.\n\n```\nRUN sudo apt update && sudo apt install -y PACKAGENAME && sudo rm -rf /var/lib/apt/lists/*\n```\n\nIf you are not sure about the package name, run Docker locally and search for the package name. Fair warning: The `gitpod/workspace-full` image is huge, use the base image `debian:latest` instead.\n\n```shell\n$ docker run -ti debian:latest bash\n$ apt search POSSIBLENAME\n```\n\nYou can learn more  the [workspace image repository](https://github.com/gitpod-io/workspace-images) to learn more about the Dockerfile configuration used by the builder.\n\n## Do more with Gitpod\n\n### Merge request code reviews\n\nThe GitLab workflow extension comes with more super powers:\n\n* Access the project and Merge Requests\n* Check the CI/CD pipeline status directly in Gitpod\n* Perform MR code reviews in Gitpod and take advantage of [VS Code workflows](/blog/mr-reviews-with-vs-code/)\n\n![Gitpod: MR Code Reviews with the GitLab Workflow extension website](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_vs_code_gitlab_workflow_extension_mr_code_reviews.png)\n\n### Pre-install VS Code Extensions\n\nIn order to ensure specific [VS Code extensions](https://www.gitpod.io/docs/vscode-extensions/) are installed, you can define them in the `.gitpod.yml` configuration file in the repository. Example from the [GitLab project](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitpod.yml#L79):\n\n```yaml\nvscode:\n  extensions:\n    - rebornix.ruby@0.28.0\n    - wingrunr21.vscode-ruby@0.27.0\n    - karunamurti.haml@1.3.1\n    - octref.vetur@0.34.1\n    - dbaeumer.vscode-eslint@2.1.8\n    - gitlab.gitlab-workflow@3.24.0\n```\n\n### Learn new programming languages: Rust\n\nGitpod allows you to start a fresh pod environment, pause on idle, and continue at a later point. The default workspace environment image already includes the [Rust compiler](https://www.gitpod.io/docs/languages/rust), which means that you can immediately [start learning Rust](https://doc.rust-lang.org/rust-by-example/).\n\nCreate a new project called `learn-rust` and open Gitpod from the repository view. Add a new file on the left tree view called `hello.rs` and add the following content:\n\n```rust\nfn main() {\n\tprintln!(\"Hello from GitLab! 🦊\");\n}\n```\n\nChange into the terminal and run the following command:\n\n```shell\n$ rustc hello.rs\n```\n\nWe started learning Rust together in an [#EveryoneCanContribute cafe](https://everyonecancontribute.com/post/2020-10-07-cafe-3-gitpod-gitlab-rust/) in October 2020 including [workshop slides with exercises](https://docs.google.com/presentation/d/1t1FdHh04TAOg9WITqRFJHz1YFxMbsQeekN8th1UfFcI/edit). We continued with [Rocket.rs](https://everyonecancontribute.com/post/2021-06-30-cafe-36-rust-rocket-prometheus/) as web app and additional Prometheus monitoring metrics in June 2021. You can watch the recordings to follow the learning process, the mistakes we made on the way, and the first success.\n\n### How to contribute to GitLab with Gitpod\n\nA more complex development environment is GitLab itself. The [architecture](https://docs.gitlab.com/ee/development/architecture.html) involves many different components, and the development environment requires you to install several dependencies in Ruby, NodeJS, Go, and backend applications. The GitLab Development Kit (GDK) describes the steps in detail - in order to get everything up and running, you need to plan for a 30 minutes to three hour process, depending on the compute power and bandwidth.\n\nEarly in the process of adopting Gitpod for GitLab team members, the groundwork with the base image and bootstrap script took the majority of the preparation time. You can learn more about the integration process in [this issue request](https://gitlab.com/gitlab-org/gitlab-development-kit/-/issues/1076).\n\n> It's already possible to try out how the setup works by opening Gitpod, which after waiting for the setup to finish (six to eight minutes) will bring you the Gitpod UI with the GDK fully running and ready for you to make changes and commit. As soon as that setup is finished, you can switch to whatever branch you want, either from the Gitpod UI or via the terminal.\n\nThe [GDK documentation for Gitpod](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/gitpod.md) guides you through the required steps. **Important**: You need to start Gitpod from the [gitlab-org/gitlab](https://gitlab.com/gitlab-org/gitlab/) project (as team member, as contributor, please fork the repository). Additional features, such as a local GitLab runner, feature flags, Advanced search, etc., must be [enabled manually](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/howto/gitpod.md#configure-additional-features).\n\n![GitLab Development Kit running in Gitpod](https://about.gitlab.com/images/blogimages/gitlab-gitpod-teams-development/gitpod_gitlab_gdk_running.png)\n\n### Everyone can contribute\n\nReady? Start contributing to your favorite OSS project, and connect with your teams for an all-remote pair programming session using Gitpod! :-)\n\nCover image by [Thomas Lipke](https://unsplash.com/photos/oIuDXlOJSiE) on [Unsplash](https://unsplash.com)\n{: .note}\n",[9,717,872],{"slug":3290,"featured":6,"template":696},"teams-gitpod-integration-gitlab-speed-up-development","content:en-us:blog:teams-gitpod-integration-gitlab-speed-up-development.yml","Teams Gitpod Integration Gitlab Speed Up Development","en-us/blog/teams-gitpod-integration-gitlab-speed-up-development.yml","en-us/blog/teams-gitpod-integration-gitlab-speed-up-development",{"_path":3296,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3297,"content":3303,"config":3309,"_id":3311,"_type":13,"title":3312,"_source":15,"_file":3313,"_stem":3314,"_extension":18},"/en-us/blog/the-road-to-smarter-code-reviewer-recommendations",{"title":3298,"description":3299,"ogTitle":3298,"ogDescription":3299,"noIndex":6,"ogImage":3300,"ogUrl":3301,"ogSiteName":683,"ogType":684,"canonicalUrls":3301,"schema":3302},"The road to smarter code reviewer recommendations","Machine learning is coming to GitLab's code review process. Here's what you need to know, and how you can help!","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668426/Blog/Hero%20Images/retrospectivesgitlabpost.jpg","https://about.gitlab.com/blog/the-road-to-smarter-code-reviewer-recommendations","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"The road to smarter code reviewer recommendations\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Taylor McCaslin\"}],\n        \"datePublished\": \"2022-01-04\",\n      }",{"title":3298,"description":3299,"authors":3304,"heroImage":3300,"date":3306,"body":3307,"category":1244,"tags":3308},[3305],"Taylor McCaslin","2022-01-04","\nYou may recall back in June 2021, we [announced the acquisition of UnReview](/press/releases/2021-06-02-gitlab-acquires-unreview-machine-learning-capabilities/), a machine learning (ML) based solution for automatically identifying appropriate expert [code reviewers](/stages-devops-lifecycle/create/) and controlling review workloads and distribution of knowledge.\n\nAt the start of the new year we wanted to provide an update on our integration progress and our wider vision of leveraging machine learning to make GitLab's [DevOps Platform](/solutions/devops-platform/) smarter. You see, the acquisition of UnReview also was the initial staffing of [our new ModelOps stage](/direction/modelops/).\n\n### Our Newest DevOps Stage\n\nThis new stage, which we’ve named ModelOps, is focused on enabling and empowering data science workloads on GitLab. GitLab ModelOps aims to bring data science into GitLab both within existing features to make them smarter and more intelligent, but also empowering GitLab customers to build and integrate data science workloads within GitLab.\n\nSo what is ModelOps you may wonder? We view ModelOps as an all encompassing term to cover the entire end to end lifecycle of artificial intelligence models. We wanted to set our vision wide to fully cover everything needed to power data science workloads. DataOps is the processing of data workloads (think traditional ELT: extract, load, transform) and MLOps is the building, training, and deployment of machine learning models. If you’re confused don’t worry, it’s a lot to wrap your head around.\n\n![a look at the stages of MLOps](https://about.gitlab.com/images/blogimages/MLops.png){: .shadow.small.center}\n\nToday our DevOps Platform helps plan, build, test, secure, deploy, and monitor traditional software. Now we want to extend our DevOps Platform to include AI and ML workloads. If this is interesting to you, be sure to check out our recent Contribute talk where we dive deeper into plans for our ModelOps stage.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/C08QVI99JLo\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n### UnReview as our first feature\n\nSo what does this have to do with UnReview? Our acquisition of UnReview is going to be our first [AI Assisted](/direction/ai-powered/) group’s feature: suggested reviewers within [GitLab’s existing reviewers experience](/blog/merge-request-reviewers/). Today, a developer in a merge request has to manually choose a reviewer to look at their code. With UnReview we can leverage the contribution history for a project and recommend someone well-suited for code review of your specific changes.\n\nHere’s an early mockup (and it may differ from our final UI) of how we’re thinking about this integration:\n\n![an early mockup of our UI](https://about.gitlab.com/images/blogimages/codereviewmockup.png){: .shadow.small.left}\n\nThe UnReview algorithm looks at a variety of data points from your project’s contribution history to suggest an appropriate reviewer. We’re still in the early days of this integration but our initial internal testing shows great suggestions.\n\n### Customer beta coming soon!\n\nThis leads me to a final question, might you want to be one of our first customers to try this new code review experience? In early 2022, we’ll begin a private customer beta of this new functionality. If interested, [fill out this form to express interest](https://docs.google.com/forms/d/e/1FAIpQLScpmCwpwyBr0GrXxBQ6vE02eokclFAs9lFk_g5dcyuGaHqFuQ/viewform). Do note that we can’t accept everyone and we’ll focus initially on customer profiles that are well suited for the initial version of the suggestion algorithm. Our only ask is we’d like to find customers with active projects that have a healthy number of contributors. The model currently works best on larger repositories with lots of contributors where it may not immediately be clear who is an ideal code reviewer.\n\nWe can’t wait for customers to begin using this new reviewer suggestion experience and will be providing more updates in early 2022.\n",[851,9,872,934],{"slug":3310,"featured":6,"template":696},"the-road-to-smarter-code-reviewer-recommendations","content:en-us:blog:the-road-to-smarter-code-reviewer-recommendations.yml","The Road To Smarter Code Reviewer Recommendations","en-us/blog/the-road-to-smarter-code-reviewer-recommendations.yml","en-us/blog/the-road-to-smarter-code-reviewer-recommendations",{"_path":3316,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3317,"content":3323,"config":3329,"_id":3331,"_type":13,"title":3332,"_source":15,"_file":3333,"_stem":3334,"_extension":18},"/en-us/blog/top-engineering-stories-gitlab",{"title":3318,"description":3319,"ogTitle":3318,"ogDescription":3319,"noIndex":6,"ogImage":3320,"ogUrl":3321,"ogSiteName":683,"ogType":684,"canonicalUrls":3321,"schema":3322},"These are your favorite GitLab engineering stories","From building a Web IDE, to our migration to GCP, to tracking down a bug in NFS – these are some of our most popular engineering blog posts.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681835/Blog/Hero%20Images/stairs_iteration.jpg","https://about.gitlab.com/blog/top-engineering-stories-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"These are your favorite GitLab engineering stories\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sara Kassabian\"}],\n        \"datePublished\": \"2021-01-07\",\n      }",{"title":3318,"description":3319,"authors":3324,"heroImage":3320,"date":3326,"body":3327,"category":739,"tags":3328},[3325],"Sara Kassabian","2021-01-07","\n\nSome of our most popular and enduring engineering stories show how we use GitLab technology to take small steps to achieve major upgrades, fixes, and integrations to improve upon GitLab features. These stories demonstrate one of our core values at GitLab, [iteration](https://handbook.gitlab.com/handbook/values/#iteration) – meaning we ship the smallest changes first. When it comes to building new features or introducing fixes at GitLab, our engineering team operates under the principle that incremental change drives the greatest value.\n\n## How we executed on milestone migrations\n\n### Azure to GCP\n\nAzure simply was not cutting it for hosting GitLab.com, and we decided it was time to migrate GitLab over to Google Cloud Platform (GCP). This was no small decision or endeavor, and we documented our end-to-end process publicly in the hopes that other companies might learn from our experience. [Read the blog post describing the migration to GCP](/blog/gitlab-journey-from-azure-to-gcp/), or watch the video below to learn more about this major migration.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/Ve_9mbJHPXQ\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nNext, we explain how we analyzed data to see [how GitLab.com was performing on GCP after this major migration](/blog/gitlab-com-stability-post-gcp-migration/). Turns out, GitLab.com availability improved by 61% post-migration.\n\n### Upgrading PostgreSQL\n\nIn another blog post, one of GitLab.com’s main PostgreSQL clusters needed a major version upgrade. We knew it wouldn’t be easy, but in May 2020, we pulled off a [near-perfect execution of this substantial upgrade](/blog/gitlab-pg-upgrade/). We explain how the process unfolded, from planning to testing to full automation.\n\n### Moving to Kubernetes\n\n[Migrating GitLab.com over to Kubernetes](/blog/year-of-kubernetes/) was a painstaking and complex process. In one of our most popular blog posts last year, we share the trials and triumphs from the year after the migration.\n\n## Code detectives show their debugging work\n\nGitLab engineering fellow [Stan Hu](/company/team/#stanhu) explains [how debugging a bug in the Docker client library](/blog/tracking-down-missing-tcp-keepalives/) that was used in the GitLab runner taught him more about Docker, Golang, and even GitLab.\n\nBack in 2018, a customer flagged a bug in the NFS that the Support team escalated to Stan and his fellow engineers. It took _two weeks_ to hunt down the NFS bug that was disrupting the Linux kernel, and [Stan chronicles the intricacies of his investigation in this blog post](/blog/how-we-spent-two-weeks-hunting-an-nfs-bug/).\n\nAfter GitLab.com users reported getting the same, mysterious error message, our Scalability team rolled up their sleeves to figure out the origins of the message – and uncovered a complex problem.\n\n![Graph showing connection errors is part of the GitLab Scalability team's troubleshooting efforts](https://about.gitlab.com/images/blogimages/connectionerrorsgraph.png){: .shadow}\nGraph showing connection errors, grouped by second-of-the-minute, indicates a lot of clustering going on in the time dimension.\n{: .note .text-center}\n\nThere were [six key lessons we learned while debugging this scaling problem on GitLab.com](/blog/tyranny-of-the-clock/).\n\n## Using data for anomaly detection\n\nTwo years ago we switched over from our legacy NFS file-sharing service to Gitaly, and soon we noticed that our Gitaly service was lagging.\n\n![Graph showing lagging problems with Gitaly service](https://about.gitlab.com/images/blogimages/graph-01.png){: .shadow}\nWe noticed that the 99th percentile performance of the gRPC endpoint for Gitaly service had dropped from 400ms down to 100ms for an unknown reason.\n{: .note .text-center}\n\nThrough solid application monitoring, we were able to identify the problem and quickly fix it. [Unpack the process behind the Gitaly fix in this popular blog post](/blog/how-a-fix-in-go-19-sped-up-our-gitaly-service-by-30x/).\n\nPrometheus reports on time-series data, which can be used for anomaly detection and alerting. [Learn how you can use this data to set up analysis and alerting with Prometheus](/blog/anomaly-detection-using-prometheus/) and use the code snippets to try it out in your own system.\n\n## Inside GitLab\n\nWhen GitLab co-founder Dmitriy Zaporozhets built GitLab on Ruby on Rails, despite working mostly in PHP at the time. In this foundational blog post, our GitLab CEO, [Sid Sijbrandij](/company/team/#sytses), explains [why building on rails was the best decision for GitLab](/blog/why-we-use-rails-to-build-gitlab/).\n\nWe built our Web IDE to make it easier to edit code using GitLab. Explore [how we took the GitLab Web IDE from an experiment to working feature](/blog/introducing-gitlab-s-integrated-development-environment/).\n\n## The extensions and integrations that power us\n\n### How we built a VS Code extension\n\nAfter a survey revealed that VS Code was the most-used tool by our Frontend team, we decided to build a VS Code extension that works with GitLab. Learn [how we built the VS Code extension](/blog/gitlab-vscode-extension/) in a series of iterations.\n\nSoon, we found out our VS Code extension was very popular. So we wrote a blog post explaining [how users can develop their own extensions with VS Code and GitLab](/blog/vscode-extension-development-with-gitlab/).\n\n### Challenges with Elasticsearch\n\nElasticsearch enables global code search on GitLab.com and would allow us to run advanced syntax search and advanced global search of our codebase. But we ran into trouble with GitLab’s integration with Elasticsearch and [hit some dead ends on our first attempt to initiate the integration](/blog/enabling-global-search-elasticsearch-gitlab-com/). We recalibrated, learned from our mistakes, and [made a second attempt at the integration](/blog/elasticsearch-update/) a few months later.\n\n### Dogfooding at GitLab\n\nThe engineering productivity team at GitLab built Insights to examine trends in the GitLab.com issue tracker at a high-level, but soon realized Insights could be useful to our GitLab Ultimate users. Watch the video below or [read the blog post to explore the origins of Insights](/blog/insights/).\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/kKnQzS9qorc\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n### How we reimagined the technical interview\n\nThe trouble with technical interviews is that they rarely reflect the job you’re interviewing for. Learn how former GitLab team member, Clement Ho, [reimagined the technical interview for Frontend engineers](/blog/the-trouble-with-technical-interviews/).\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube-nocookie.com/embed/dNABW84sTzs\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\n\n## How troubleshooting and security modeling can prevent disaster\n\nIn a major feat of coordination, our globally distributed engineering team managed to work synchronously to troubleshoot an issue with our Hashicorp Consul, successfully avoiding any significant problems, including the outage we anticipated. Read \"[The consul outage that never happened](/blog/the-consul-outage-that-never-happened/)\" to learn how they did it.\n\nOur Red team at GitLab is continually searching for vulnerabilities, big and small, and introduces patches to make it function. In one of our most popular 2020 posts, [our security team explains how an attacker who already gained unauthorized access to the cloud platform might be able to take advantage of GCP privileges](/blog/plundering-gcp-escalating-privileges-in-google-cloud-platform/), and how replicating this breach scenario could help you prevent this from happening on your GCP instance.\n\n**Did we miss something?** Share a link to your favorite GitLab engineering story below and [check out our round-up of some of our top stories about how to apply GitLab technology](/blog/gitlab-for-cicd-agile-gitops-cloudnative/).\n\nCover image by [Jamie Saw](https://unsplash.com/@jsclick?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/series-of-stairs?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n{: .note}\n",[1161,9],{"slug":3330,"featured":6,"template":696},"top-engineering-stories-gitlab","content:en-us:blog:top-engineering-stories-gitlab.yml","Top Engineering Stories Gitlab","en-us/blog/top-engineering-stories-gitlab.yml","en-us/blog/top-engineering-stories-gitlab",{"_path":3336,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3337,"content":3343,"config":3349,"_id":3351,"_type":13,"title":3352,"_source":15,"_file":3353,"_stem":3354,"_extension":18},"/en-us/blog/track-machine-learning-model-experiments",{"title":3338,"description":3339,"ogTitle":3338,"ogDescription":3339,"noIndex":6,"ogImage":3340,"ogUrl":3341,"ogSiteName":683,"ogType":684,"canonicalUrls":3341,"schema":3342},"Track ML model experiments with new GitLab MLFlow integration","Track the many versions of your machine learning models on GitLab using the MLFlow client.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749662840/Blog/Hero%20Images/ai-experiment-stars.png","https://about.gitlab.com/blog/track-machine-learning-model-experiments","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Track ML model experiments with new GitLab MLFlow integration\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Eduardo Bonet\"}],\n        \"datePublished\": \"2023-05-11\",\n      }",{"title":3338,"description":3339,"authors":3344,"heroImage":3340,"date":3346,"body":3347,"category":1568,"tags":3348},[3345],"Eduardo Bonet","2023-05-11","\n\n\u003Ci>This blog is the latest post in an ongoing series about GitLab’s journey to \u003Ca href=\"/blog/ai-ml-in-devsecops-series/\">build and integrate AI/ML into our DevSecOps platform\u003C/a>. The first blog post can be found \u003Ca href=\"/blog/what-the-ml-ai/\">here\u003C/a>. Throughout the series, we’ll feature blogs from our product, engineering, and UX teams to showcase how we’re infusing AI/ML into GitLab.\u003C/i>\n\nThe GitLab DevSecOps platform now features [Machine Learning Model Experiments](https://docs.gitlab.com/ee/user/project/ml/experiment_tracking/), which is avaliable to all GitLab users, making GitLab a powerful tool for creating ML models. Organizations can now track the many versions of their ML models within the GitLab user interface, using the open source [MLFlow](https://github.com/mlflow/mlflow).\n\n\u003Cimg src=\"/images/blogimages/2023-05-11-gitlab-model-experiments/experiment.png\" alt=\"Model experiment\" style=\"border: 1px solid gray;\">\n\n## What is an ML model?\n\nAn ML model is the result of three components: code to extract the patterns from the data, the data where the \npatterns are extracted from, and the configuration used for both, often called \"hyperparameters\". Any change to any of these components can \nlead to changes in the model performance, and keeping track of all of these parts and the results can be challenging. \nExperiment tracking aims to make sense of this confusion by keeping a record of all of the variations created, \nalong with the artifacts and results of each trial.\n\n[MLFlow](https://github.com/mlflow/mlflow) is a popular open source solution for ML experiment tracking, \nproviding a client to log different model versions and their metadata. However, it puts the cost of deployment and managing \nits server onto the users.\n\nGitLab makes the tracking process easier not by deploying a managed MLFlow backend, but by \u003Ci>being an MLFlow backend itself\u003C/i>. This marries the best of both worlds: Data scientists don't need to learn yet another client as their code requires minimal to no changes, while GitLab provides everything else. There is no need to manage a server or to implement user management, so there is no need to configure your artifact storage –  this is all provided by the GitLab DevSecOps platform.\n\n## ML model experiment features in GitLab 16.0\n\nWatch this overview of the available features in 16.0:\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/uxweU4zT40c\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n- **Create experiments and candidates using the MLFlow client**: Simply point the MLFlow client to your GitLab project and experiments and runs will be recorded on GitLab, with no additional setup necessary and no need to create a server. Note that MLFlow runs are called \"candidates\" in GitLab, as each of them is a candidate to become a version of a model.\n\n- **User access management**: Experiments are tied to a GitLab project, making it easy to control which users have access to which models. \n\n- **Manage candidates directly on the GitLab UI**: Search and explore your logged experiments on GitLab, using the UI you already know.\n\n- **Download candidate data as a CSV**: Data scientists that want to explore or create reports on an experiment can download the necessary data as a CSV file.\n\nTo get started, refer to the [documentation](https://docs.gitlab.com/ee/user/project/ml/experiment_tracking/#machine-learning-model-experiments).\n\n### More to come\n\nGitLab wants to help you manage the entire lifecycle of your machine learning model from creation to packaging, deployment, and monitoring. \nFor more information on what we are working on, keep an eye on the MLOps Incubation Engineering [handbook page](/handbook/engineering/incubation/mlops/) and on our [YouTube playlist](https://www.youtube.com/playlist?list=PL05JrBw4t0KpC6-JQy8lY4tNAZKXBaM_-).\n\nMachine Learning Model Experiments is an experimental feature available to all GitLab tiers, and we are looking for feedback so please [comment in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/381660).\n\nContinue reading our \"[AI/ML in DevSecOps](/blog/ai-ml-in-devsecops-series/)\" series.\n\n_Disclaimer: This blog contains information related to upcoming products, features, and functionality. It is important to note that the information in this blog post is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. As with all projects, the items mentioned in this blog and linked pages are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab._\n",[934,493,9,742],{"slug":3350,"featured":6,"template":696},"track-machine-learning-model-experiments","content:en-us:blog:track-machine-learning-model-experiments.yml","Track Machine Learning Model Experiments","en-us/blog/track-machine-learning-model-experiments.yml","en-us/blog/track-machine-learning-model-experiments",{"_path":3356,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3357,"content":3363,"config":3370,"_id":3372,"_type":13,"title":3373,"_source":15,"_file":3374,"_stem":3375,"_extension":18},"/en-us/blog/triage-issues-gitmate",{"title":3358,"description":3359,"ogTitle":3358,"ogDescription":3359,"noIndex":6,"ogImage":3360,"ogUrl":3361,"ogSiteName":683,"ogType":684,"canonicalUrls":3361,"schema":3362},"Triage issues in 7 simple steps","Guest authors Lasse Shuirmann and Sebastian Latacz walk us through how to work through your issue backlog and triage effectively.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670529/Blog/Hero%20Images/automate-retrospectives.jpg","https://about.gitlab.com/blog/triage-issues-gitmate","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Triage issues in 7 simple steps\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sebastian Latacz\"},{\"@type\":\"Person\",\"name\":\"Lasse Schuirmann\"}],\n        \"datePublished\": \"2017-10-26\",\n      }",{"title":3358,"description":3359,"authors":3364,"heroImage":3360,"date":3367,"body":3368,"category":3267,"tags":3369},[3365,3366],"Sebastian Latacz","Lasse Schuirmann","2017-10-26","\n\nActively triaging issues is crucial for keeping an overview on your repository, yet it’s tedious and takes up valuable developer hours. That’s why we summarized seven simple steps to help you triage efficiently.\n\n\u003C!-- more -->\n\n## Preparation\n\nThere are three types of issues: questions, bug reports, and feature requests. Define which you want to tackle in your tracker and which you handle elsewhere (you can use different [GitLab Issue Boards](/stages-devops-lifecycle/issueboard/) to help keep different types of issues together). Once this has been done, check each issue with the following scheme:\n\n## 1. Filter noise\n\nCheck whether the issue is the type you want in your tracker (as defined in the preparation phase). If not, point the user to the right place or move it to the relevant [issue board](/stages-devops-lifecycle/issueboard/) yourself. For example, indicate that questions will be answered on Stack Overflow or feature requests are best being posted for discussion in the Slack channel. Be friendly; remember the user just provided valuable feedback. Close the issue once you’ve pointed the user to the right place.\n\n## 2. Look for similars\n\nOftentimes work related to existing issues already exists. Searching your issue tracker for related keywords can bring up a lot of similar issues that can be helpful. Reference the existing issues in the new one.\n\n## 3. Look for duplicates\n\nWhile you are researching similar topics you might find or remember duplicate issues as well – in that case simply close those (or the new issue) and streamline your efforts in one place.\n\n## 4. Retrieve missing information\n\nIssues are often reported incomplete; critical information like a version number is not given and it turns out that a bug occurred in an unsupported version – ask people for missing information and close issues if that is not provided.\n\n## 5. Label\n\nLabel issues so you can find those which are relevant for a particular topic with a filter. Also set labels for states of an issue. For example, putting a `needs-info` label on an issue prevents other people from wasting their time on it.\n\n## 6. Ping related devs\n\nEspecially for bigger changes or if it's not obvious how to tackle an issue, you will want to cc developers who are knowledgeable in the area. This can prevent you from running against three walls after each other and make sure all related efforts are coordinated properly.\n\n## 7. Handle stale issues\n\nEvery issue has to die. If you're thinking about closing an issue you should probably close it. Also close issues where you have been waiting for an answer for more than 30 days. Be friendly while doing so. The user can always reopen it if needed. This will prevent your tracker from cluttering.\n\nUpdate 2020-06-29: This post originally included information about automating issue triage using GitMate.io. Please note that GitMate.io was deprecated in January 2019 and references to the project have therefore been removed.\n{: .alert .alert-info}\n\nPhoto by [Daniele Levis Pelusi](https://unsplash.com/photos/Pp9qkEV_xPk?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/automation?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n{: .note}\n",[872,9],{"slug":3371,"featured":6,"template":696},"triage-issues-gitmate","content:en-us:blog:triage-issues-gitmate.yml","Triage Issues Gitmate","en-us/blog/triage-issues-gitmate.yml","en-us/blog/triage-issues-gitmate",{"_path":3377,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3378,"content":3384,"config":3389,"_id":3391,"_type":13,"title":3392,"_source":15,"_file":3393,"_stem":3394,"_extension":18},"/en-us/blog/tutorial-secure-bigquery-data-publishing-with-gitlab",{"title":3379,"description":3380,"ogTitle":3379,"ogDescription":3380,"noIndex":6,"ogImage":3381,"ogUrl":3382,"ogSiteName":683,"ogType":684,"canonicalUrls":3382,"schema":3383},"Tutorial: Secure BigQuery data publishing with GitLab ","Learn how to create repeatable, auditable, and efficient processes for automating and securing BigQuery data exports.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659756/Blog/Hero%20Images/REFERENCE_-_display_preview_for_blog_images.png","https://about.gitlab.com/blog/tutorial-secure-bigquery-data-publishing-with-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Tutorial: Secure BigQuery data publishing with GitLab \",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Regnard Raquedan\"}],\n        \"datePublished\": \"2025-03-25\",\n      }",{"title":3379,"description":3380,"authors":3385,"heroImage":3381,"date":3386,"body":3387,"category":739,"tags":3388},[1365],"2025-03-25","GitLab offers a powerful solution for automating and securing\n[BigQuery](https://cloud.google.com/bigquery) data exports. This integration\ntransforms manual exports into repeatable, auditable processes that can\neliminate security vulnerabilities while saving valuable time. This tutorial\nexplains how to implement this solution so you can quickly reduce manual\noperations, permission issues, and security concerns with just a few lines\nof GitLab YAML code.\n\n\nFollow along with this step-by-step video:\n\n\n\u003C!-- blank line -->\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/gxXX-ItAreo?si=FijY9wMVppCW-18q\" frameborder=\"0\" allowfullscreen=\"true\">\u003C/iframe>\n\u003C/figure>\n\n\u003C!-- blank line -->\n\n\n## The solution architecture\n\n\nOur solution leverages GitLab CI/CD pipelines to automate the secure export\nof data from BigQuery to Google Cloud Storage. Here's the high-level\narchitecture:\n\n\n1. SQL code is stored and version-controlled in GitLab.  \n\n2. After code review and approval, GitLab CI/CD pipeline executes the\ncode.  \n\n3. The pipeline authenticates with Google Cloud.  \n\n4. SQL queries are executed against BigQuery.  \n\n5. Results are exported as CSV files to Google Cloud Storage.  \n\n6. Secure links to these files are provided for authorized consumption.\n\n\n## Prerequisites\n\n\nBefore we begin, ensure you have:\n\n\n* **Google Cloud APIs enabled:** BigQuery API and Cloud Storage API  \n\n* **Service account** with appropriate permissions:  \n  * BigQuery Job User  \n  * Storage Admin  \n  * **Note:** For this demo, we're using the service account approach for authentication, which is simpler to set up. For production environments, you might consider using GitLab's identity and access management integration with Google Cloud. This integration leverages Workload Identity Federation, which provides enhanced security and is more suitable for enterprise customers and organizations.  \n* **GitLab project** ready to store your SQL code and pipeline configuration\n\n\n## Step-by-step implementation\n\n\n**1. Configure Google Cloud credentials.**\n\n\nFirst, set up the necessary environment variables in your GitLab project:\n\n\n- Go to your **GitLab project > Settings > CI/CD**.  \n\n- Expand the **Variables** section.  \n\n- Add the following variables:  \n   * `GCS_BUCKET`: Your Google Cloud Storage bucket name  \n   * `GCP_PROJECT_ID`: Your Google Cloud project ID  \n   * `GCP_SA_KEY`: Base64-encoded service account key (mark as masked)\n\n**2. Create your SQL query.**\n\n\nCreate a file named `query.sql` in your GitLab repository with your BigQuery\nSQL query. The query looks like this:\n\n\n```\n\n-- This query shows a list of the daily top Google Search terms.\n\nSELECT\n   refresh_date AS Day,\n   term AS Top_Term,\n       -- These search terms are in the top 25 in the US each day.\n   rank,\nFROM `bigquery-public-data.google_trends.top_terms`\n\nWHERE\n   rank = 1\n       -- Choose only the top term each day.\n   AND refresh_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 2 WEEK)\n       -- Filter to the last 2 weeks.\nGROUP BY Day, Top_Term, rank\n\nORDER BY Day DESC\n   -- Show the days in reverse chronological order.\n\n```\n\n\nThis query gets the top 25 search terms from Google Trends for the current\nday.\n\n\n**3. Configure the GitLab CI/CD pipeline.**\n\n\nCreate a `.gitlab-ci.yml` file in your repository root:\n\n\n```\n\nimage: google/cloud-sdk:alpine\n\n\ninclude:\n  - template: Jobs/Secret-Detection.gitlab-ci.yml  # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Secret-Detection.gitlab-ci.yml\n\nexecute:\n  stage: deploy\n  script: \n    # Set up Google Cloud authentication and install necessary components\n    - export GOOGLE_CLOUD_CREDENTIALS=$(echo $SERVICE_ACCOUNT_KEY | base64 -d)\n    - echo $GOOGLE_CLOUD_CREDENTIALS > service-account-key.json \n    - gcloud auth activate-service-account --key-file service-account-key.json \n    - gcloud components install gsutil\n    # Set the active Google Cloud project\n    - gcloud config set project $PROJECT_ID\n    # Run the BigQuery query and export the results to a CSV file\n    - bq query --format=csv --use_legacy_sql=false \u003C test.sql > results.csv\n    # Create a Google Cloud Storage bucket if it doesn't exist\n    - gsutil ls gs://${CLOUD_STORAGE_BUCKET} || gsutil mb gs://${CLOUD_STORAGE_BUCKET}\n    # Upload the CSV file to the storage bucket\n    - gsutil cp results.csv gs://${CLOUD_STORAGE_BUCKET}/results.csv\n    # Set the access control list (ACL) to make the CSV file publicly readable\n    - gsutil acl ch -u AllUsers:R gs://${CLOUD_STORAGE_BUCKET}/results.csv\n    # Define the static URL for the CSV file\n    - export STATIC_URL=\"https://storage.googleapis.com/${CLOUD_STORAGE_BUCKET}/results.csv\"\n    # Display the static URL for the CSV file\n    - echo \"File URL = $STATIC_URL\"\n\n```\n\n\n**4. Run the pipeline.**\n\n\nNow, whenever changes are merged to your main branch, the pipeline will\nprovide a link to the CSV file stored on the Google Cloud Storage bucket.\nThis file contains the result of the executed SQL query that GitLab subjects\nto security checks.\n\n\n## Benefits of this approach\n\n\n* **Security:** Authentication is handled automatically via service accounts\n(or Workload Identity Federation for enhanced security in production\nenvironments).  \n\n* **Auditability:** All data exports are tracked through GitLab commits and\npipeline logs.  \n\n* **Repeatability:** Consistent, predictable export process on every run,\nand can be scheduled.  \n\n* **Version control:** SQL queries are properly versioned and reviewed.  \n\n* **Automation:** Significantly fewer manual exports, reducing human error.\n\n\n## Try it today\n\n\nBy combining GitLab's DevSecOps capabilities with Google Cloud's BigQuery\nand Cloud Storage, you've now automated and secured your data publishing\nworkflow. This approach reduces manual operations, resolves permission\nheadaches, and addresses security concerns – all achieved with just a few\nlines of GitLab CI code.\n\n\n> Use this tutorial's [complete code\nexample](https://gitlab.com/gitlab-partners-public/google-cloud/demos/big-query-data-publishing)\nto get started now.\n",[976,493,807,872,9,741],{"slug":3390,"featured":90,"template":696},"tutorial-secure-bigquery-data-publishing-with-gitlab","content:en-us:blog:tutorial-secure-bigquery-data-publishing-with-gitlab.yml","Tutorial Secure Bigquery Data Publishing With Gitlab","en-us/blog/tutorial-secure-bigquery-data-publishing-with-gitlab.yml","en-us/blog/tutorial-secure-bigquery-data-publishing-with-gitlab",{"_path":3396,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3397,"content":3403,"config":3411,"_id":3413,"_type":13,"title":3414,"_source":15,"_file":3415,"_stem":3416,"_extension":18},"/en-us/blog/ultimate-guide-to-migrating-from-aws-codecommit-to-gitlab",{"title":3398,"description":3399,"ogTitle":3398,"ogDescription":3399,"noIndex":6,"ogImage":3400,"ogUrl":3401,"ogSiteName":683,"ogType":684,"canonicalUrls":3401,"schema":3402},"Ultimate guide to migrating from AWS CodeCommit to GitLab","Learn how to migrate from AWS Services to GitLab and seamlessly integrate with the DevSecOps platform in this comprehensive tutorial.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097810/Blog/Hero%20Images/Blog/Hero%20Images/blog-image-template-1800x945%20%2828%29_4mi0l4wzUa5VI4wtf8gInx_1750097810027.png","https://about.gitlab.com/blog/ultimate-guide-to-migrating-from-aws-codecommit-to-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Ultimate guide to migrating from AWS CodeCommit to GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tsukasa Komatsubara\"},{\"@type\":\"Person\",\"name\":\"Darwin Sanoy\"},{\"@type\":\"Person\",\"name\":\"Samer Akkoub\"},{\"@type\":\"Person\",\"name\":\"Bart Zhang\"}],\n        \"datePublished\": \"2024-08-26\",\n      }",{"title":3398,"description":3399,"authors":3404,"heroImage":3400,"date":3408,"body":3409,"category":1019,"tags":3410},[3405,1465,3406,3407],"Tsukasa Komatsubara","Samer Akkoub","Bart Zhang","2024-08-26","On July 25, 2024, AWS made a significant announcement regarding its CodeCommit service. As detailed in their [official blog post](https://aws.amazon.com/blogs/devops/how-to-migrate-your-aws-codecommit-repository-to-another-git-provider/), AWS has decided to close new customer access to CodeCommit. While existing customers can continue using the service, AWS will not introduce new features, focusing only on security, availability, and performance improvements.\n\nThis announcement has prompted development teams to consider migrating their repositories to alternative Git providers. In light of these changes, we've prepared this comprehensive guide to assist teams in migrating to GitLab and integrating with other AWS services.\n\n**Note:** For more details on AWS's official migration recommendations, please refer to [their blog post](https://aws.amazon.com/blogs/devops/how-to-migrate-your-aws-codecommit-repository-to-another-git-provider/).\n\n## About this guide\n\nThis guide provides comprehensive information for development teams using GitLab who are considering integration with AWS services or planning to migrate from AWS-hosted Git repositories to GitLab.com. The guide is structured into three main sections:\n\n- [Parallel migration to GitLab](#section-1-parallel-migration-to-gitlab): Explains how to gradually migrate from existing AWS-hosted repositories to GitLab.com while minimizing risks.\n\n- [Integration with AWS CodeBuild](#section-2-integrating-gitlab-with-aws-codebuild): Provides steps to integrate GitLab repositories with AWS CodeBuild, setting up a powerful continuous integration (CI) environment.\n\n- [Integration with AWS CodePipeline](#section-3-integrating-gitlab-with-aws-codepipeline): Details how to connect GitLab repositories with AWS CodePipeline to build efficient continuous delivery (CD) pipelines.\n\n- [Downstream integrations for CodePipeline and CodeStar Connections](#section-4-migrating-to-gitlab): Explains how to leverage GitLab-AWS connections for widespread service access, unlocking a cascade of integration possibilities across the AWS ecosystem.\n\nThrough this guide, you'll learn how to combine the powerful features of GitLab and AWS to create an efficient and flexible development workflow.\n\n## Section 1: Parallel migration to GitLab \n\nFor those considering migrating Git repositories hosted on AWS to GitLab.com, this section, which is a phased approach, introduces methods to achieve migration while minimizing risks. By leveraging GitLab's mirroring capabilities, you can maintain existing development flows while testing the new environment.\n\n### Why is parallel migration important?\n\nLarge-scale system migrations always involve risks, particularly potential impacts on ongoing development work, existing integrations, and automated processes. Adopting a parallel migration approach offers the following benefits:\n\n1. Risk minimization: Test the new environment while keeping existing systems operational.\n2. Seamless transition: Development teams can gradually acclimate to the new system.\n3. Integration testing: Thoroughly test all integrations and automation in the new environment.\n4. Future-proofing: Enable teams to gradually migrate to GitLab CI/CD in parallel to existing CI.\n\nParallel migration is not required if it is already known that you want to cut over directly to GitLab.\n\n### Steps for migrating to GitLab.com\n\n#### Step 1: Get set up on GitLab.com\n\n- Check if your company already has a group in use on GitLab.com and whether they have single sign-on (SSO) set up – if they do, then you will want to use both.\n\n- If your company does not have a presence on GitLab.com, visit [GitLab.com](www.gitlab.com) and create a new account or log in to an existing one.\n- Create a new company namespace (a group at the root level of gitlab.com).\n- Pick a name that reflects your entire company (and is not already taken).\n\n#### Step 2: Import repository\nFor parallel migration: Use GitLab's pull mirroring feature to automatically sync changes from AWS-hosted repositories to GitLab.com.\n\n1. Navigate to the target group GitLab.com.\n2. In the upper right, click \"New project.\"\n3. On the \"Create new project\" page, click \"Import project.\"\n4. On the \"Import project\" page, click \"Repository by URL.\"\n5. Enter the URL of your AWS-hosted repository in the \"Git repository URL\" field.\n6. Underneath the Git repository URL field, check \"Mirror repository.\"\n7. Set up authentication: in the AWS CodeCommit console, select the clone URL for the repository you will migrate. If you plan on importing CodeCommit repositories into GitLab, you can use the HTTPS CodeCommit URL to clone the repository via GitLab Repository Mirroring. You will need to also provide your Git credentials from AWS for your identity and access management (IAM) user within GitLab. You can create Git credentials for AWS CodeCommit by following this [AWS guide](https://docs.aws.amazon.com/codecommit/latest/userguide/setting-up-gc.html).\n\n![Clone URL](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/clone-url-screenshot__1__aHR0cHM6_1750097822121.png)\n\nThis setup will automatically pull changes from the AWS-hosted repository to GitLab.com every five minutes by default.\n\nFor more information, read our [repository mirroring documentation](https://docs.gitlab.com/ee/user/project/repository/mirror/).\n\n#### Step 3: Test and validate integrations\n\n1. CI/CD pipelines: Set up the `.gitlab-ci.yml` file in GitLab CI to replicate existing pipelines. You can read more about [planning a migration from other CI tools into GitLab CI/CD](https://docs.gitlab.com/ee/ci/migration/plan_a_migration.html).\n2. Issue tracking: Import project issues and test workflows.\n3. Code review: Set up the merge request process and test review workflows.\n\n#### Step 4: Gradual migration\n\n1. Start with small or non-critical projects to familiarize yourself with working on GitLab.com.\n2. Provide training for team members and allow time to adapt to new workflows.\n3. Gradually migrate more projects while ensuring integrations and workflows are problem-free.\n\nFor more information, see [Automating Migrations from CodeCommit to GitLab](https://gitlab.com/guided-explorations/aws/migrating-from-codecommit-to-gitlab/-/blob/main/migrating_codecommit_to_gitlab.md).\n\n#### Step 5: Complete migration\nOnce all tests and validations are complete and the team is comfortable with the new environment, plan for full migration. For each project:\n\n1. Set a migration date and notify all stakeholders.\n2. Perform final data synchronization.\n3. Remove mirroring settings from the GitLab project.\n4. Set AWS-hosted repositories to read-only and transition all development work to GitLab.com.\n\n#### Step 6: Assess adoption of new capabilities\n\nGitLab collaboration and workflow automation for developers is far richer than CodeCommit. It merits some time to learn what these capabilities are. The merge request process is especially rich compared to CodeCommit.\n\nAfter repositories are stable on GitLab, it is very easy to experiment with GitLab CI/CD in parallel to an existing solution. Teams can take time to perfect their GitLab CI/CD automation while production workflows remain unaffected.\n\nGitLab artifact management is also very capable with the Releases feature and many package registries.\n\n### Section 1: Summary\nBy adopting a parallel migration approach to GitLab, you can achieve a smooth transition while minimizing risks. This process allows teams to gradually adapt to the new environment and ensure all integrations and automations function correctly. Cutover migrations only omit a single setting checkbox if it is known that a parallel migration is not necessary.\n\n## Section 2: Integrating GitLab with AWS CodeBuild\n\nFor those wanting to build and test code from GitLab repositories using AWS CodeBuild, this comprehensive guide will help you set up an efficient CI pipeline.\n\n### Prerequisites\n\n- GitLab.com account\n- AWS account\n- AWS CLI (configured)\n\n### Step 1: Create GitLab connection in AWS CodeStar Connections\n\n1. Log in to the AWS Management Console and navigate to the CodeBuild service.\n2. Select \"Settings\" > \"Connections\" from the left navigation panel.\n3. Click the \"Create connection\" button.\n4. Choose \"GitLab\" as the provider.\n5. Enter a connection name and click \"Connect to GitLab.\"\n6. You'll be redirected to the GitLab authentication page.\n7. Approve the necessary permissions.\n8. Once successful, the connection status will change to \"Available.\"\n\n![CodeStar Connect setup](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/codestar-connections-setup_aHR0cHM6_1750097822122.png)\n\n### Step 2: Create AWS CodeBuild project\n\n1. Click \"Create build project\" on the CodeBuild dashboard.\n2. Enter a project name and description.\n3. For source settings, select \"GitLab\" as the provider.\n4. Choose the connection you just created and specify the GitLab repository and branch.\n\n![Add CodeBuild project](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/codepipeline_step_3_add_codebuild_aHR0cHM6_1750097822123.png)\n\n**Note: From Step 3 forward, please configure the settings according to your specific environment and needs.**\n\n### Summary of Section 2\nThis section explained in detail how to integrate GitLab repositories with AWS CodeBuild. This setup enables a continuous integration pipeline where code changes in GitLab are automatically built and tested using AWS CodeBuild.\n\n## Section 3: Integrating GitLab with AWS CodePipeline\n\nFor those looking to implement continuous delivery from GitLab repositories using AWS CodePipeline, this detailed guide will be helpful. The integration has become even easier now that GitLab is available as an AWS CodeStar Connections provider.\n\n### Prerequisites\n\n- GitLab.com account\n- AWS account\n- AWS CLI (configured)\n\n### Step 1: Create GitLab connection in AWS CodeStar Connections\n\n1. Log in to the AWS Management Console and navigate to the CodePipeline service.\n2. Select \"Settings\" > \"Connections\" from the left navigation panel.\n3. Click the \"Create connection\" button.\n4. Choose \"GitLab\" as the provider.\n5. Enter a connection name and click \"Connect to GitLab.\"\n6. You'll be redirected to the GitLab authentication page.\n7. Approve the necessary permissions.\n8. Once successful, the connection status will change to \"Available.\"\n\n![CodeStar Connections setup](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/codestar-connections-setup_aHR0cHM6_1750097822125.png)\n\n### Step 2: Create AWS CodePipeline\n\n1. Click \"Create pipeline\" on the CodePipeline dashboard.\n2. Enter a pipeline name and click \"Next.\"\n3. Select \"GitLab\" as the source provider.\n4. Choose the connection you just created and specify the GitLab repository and branch.\n5. Select the Trigger type: You can trigger CodePipeline pipeline execution based on either pull or push events against specific branches and file types within your repository.\n\n![Add source provider](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/codepipeline_step_2_source_provider_aHR0cHM6_1750097822127.png)\n\n![Add source configuration](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/codepipeline_step_2_source_configured_aHR0cHM6_1750097822129.png)\n\n**Note: From Step 3 forward, please configure the settings according to your specific environment and needs.**\n\n### Summary of Section 3\nThis section detailed how to integrate GitLab repositories with AWS CodePipeline. This setup enables a continuous delivery pipeline where code changes in GitLab are automatically deployed to your AWS environment.\n\n## Section 4: Migrating to GitLab\n\nIntegrating GitLab with AWS unlocks powerful capabilities for streamlining your development and deployment workflows and helps to solve your source code management woes. This integration can be achieved in several ways, each offering unique benefits:\n\n- Using AWS CodeStar Connections to link GitLab with AWS services enables a more cohesive workflow by allowing external Git repositories, like GitLab, to connect with various AWS services. This setup supports automated builds, deployments, and other essential actions directly from your GitLab repository, making your development process more integrated and streamlined.\n\n- Connecting GitLab with AWS CodePipeline via AWS CodeStar Connections takes automation to the next level by allowing you to create a full CI/CD pipeline. This approach integrates GitLab with AWS CodePipeline, enabling you to automate the entire process – from source control and builds to testing and deployment – using AWS services like CodeBuild and CodeDeploy. This ensures a robust, scalable, and efficient delivery process.\n\n![Chart of new technology and solutions for using GitLab and AWS together](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097822/Blog/Content%20Images/Blog/Content%20Images/Announcing_New_Technology_and_Solutions_for_using_GitLab_and_AWS_Together_aHR0cHM6_1750097822130.png)\n\n1\\. Connecting GitLab with AWS services using AWS CodeStar Connections\n\nAWS CodeStar Connections is a service that allows you to connect external Git repositories (such as GitHub or Bitbucket) to AWS services. You can also connect GitLab to AWS services via CodeStar Connections. When using GitLab, you may need to set up a custom connection as an HTTP Git server.\nThe following AWS services can be connected to GitLab using this method:\n\n- **AWS Service Catalog**\n\nAWS Service Catalog helps organizations standardize and manage AWS resources. Integrating it with GitLab improves transparency in resource management and simplifies change tracking. Specifically, you can automate catalog updates based on GitLab commits, enhancing operational efficiency.\n\n- __AWS CodeBuild__\n\nAWS CodeBuild is a managed build service that compiles source code, runs tests, and produces deployable software packages. Integrating GitLab with CodeBuild allows automated build processes to start whenever code changes are pushed to GitLab. This ensures consistency in builds and facilitates easier collaboration and version control.\n\n- __AWS Glue Notebook Jobs__\n\nAWS Glue Notebook Jobs is a service that allows you to interactively develop and run data preparation and ETL (Extract, Transform, Load) tasks. Integrating GitLab with Glue Notebook Jobs enables version control for notebooks and ETL scripts, promotes collaboration among team members, and improves the quality management of data processing pipelines.\n\n- __AWS Proton__\n\nAWS Proton is a service that automates the development and deployment of microservices and serverless applications. By integrating GitLab with AWS Proton, you can manage infrastructure as code, automate deployments, and ensure consistent environment management, leading to more efficient development processes.\n\nAs AWS CodeStar Connections supports more services, connecting GitLab with additional AWS services will become easier. It's advisable to regularly check for new services that support CodeStar Connections.\n\n2. Connecting CodePipeline with GitLab via AWS CodeStar Connections (including CodeDeploy)\n\nAWS CodePipeline is a continuous delivery service that automates the release process for software. To connect GitLab with CodePipeline, you need to use AWS CodeStar Connections. This setup allows you to designate a GitLab repository as the source and automate the entire CI/CD pipeline.\nThe primary actions supported by CodePipeline include:\n- **Source control:** AWS CodeCommit, GitHub, Bitbucket, GitLab\n- **Build and test:** AWS CodeBuild, Jenkins\n- **Deploy:** AWS CodeDeploy, Elastic Beanstalk, ECS, S3\n- **Approval:** Manual approval\n- **Infrastructure management:** AWS CloudFormation\n- **Serverless:** AWS Lambda\n- **Testing:** AWS Device Farm\n- **Custom Actions:** AWS Step Functions\n\nBy integrating GitLab with CodePipeline, you can automatically trigger the pipeline whenever code changes are pushed to GitLab, allowing a consistent process from build to deployment. Additionally, combining this with GitLab's version control capabilities makes it easier to track deployment history and states, leading to more flexible and reliable software delivery.\n\n## What you've learned\nThis guide has provided comprehensive information on migrating to and integrating GitLab with AWS. Through the four main topics, we've covered:\n- Parallel migration to GitLab: How to gradually migrate from existing AWS-hosted repositories to GitLab.com while minimizing risks.\n- Integration with AWS CodeBuild: Steps to set up a powerful CI environment integrated with GitLab repositories.\n- Integration with AWS CodePipeline: How to build efficient continuous delivery pipelines using GitLab repositories.\n- Downstream integrations for CodePipeline and CodeStar Connections: Leveraging GitLab-AWS connections for widespread service access, unlocking a cascade of integration possibilities across the AWS ecosystem.\n\nAs every organization's code hosting and integration implementation strategy is unique, this tutorial may be used as a starting point for your own GitLab + AWS integration and implementation strategy.\n\n## Additional resources\n\nFor more detailed information and advanced configurations, refer to the following resources:\n\n- [GitLab documentation](https://docs.gitlab.com/)\n- [AWS CodeBuild User Guide](https://docs.aws.amazon.com/codebuild/latest/userguide/welcome.html)\n- [AWS CodePipeline User Guide](https://docs.aws.amazon.com/codepipeline/latest/userguide/welcome.html)\n- [GitLab CI/CD documentation](https://docs.gitlab.com/ee/ci/)\n- [Integrate with AWS](https://docs.gitlab.com/ee/solutions/cloud/aws/gitlab_aws_integration.html)\n\nIf you have questions or need support, please contact [GitLab Support](https://about.gitlab.com/support/) or AWS Support. We hope this comprehensive guide helps you in your AWS-GitLab integration journey.",[108,1469,493,807,998,1019,9],{"slug":3412,"featured":90,"template":696},"ultimate-guide-to-migrating-from-aws-codecommit-to-gitlab","content:en-us:blog:ultimate-guide-to-migrating-from-aws-codecommit-to-gitlab.yml","Ultimate Guide To Migrating From Aws Codecommit To Gitlab","en-us/blog/ultimate-guide-to-migrating-from-aws-codecommit-to-gitlab.yml","en-us/blog/ultimate-guide-to-migrating-from-aws-codecommit-to-gitlab",{"_path":3418,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3419,"content":3425,"config":3431,"_id":3433,"_type":13,"title":3434,"_source":15,"_file":3435,"_stem":3436,"_extension":18},"/en-us/blog/unreview-a-year-later-how-gitlab-is-being-transformed-by-ml-powered-code-review",{"title":3420,"description":3421,"ogTitle":3420,"ogDescription":3421,"noIndex":6,"ogImage":3422,"ogUrl":3423,"ogSiteName":683,"ogType":684,"canonicalUrls":3423,"schema":3424},"GitLab transforms code review with machine learning tools","Learn how last year's acquisition has resulted in impactful features for the One DevOps Platform.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668002/Blog/Hero%20Images/pg-gear.jpg","https://about.gitlab.com/blog/unreview-a-year-later-how-gitlab-is-being-transformed-by-ml-powered-code-review","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"UnReview a year later: How GitLab is transforming DevOps code review with ML-powered functionality\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Taylor McCaslin\"}],\n        \"datePublished\": \"2022-06-02\",\n      }",{"title":3426,"description":3421,"authors":3427,"heroImage":3422,"date":3428,"body":3429,"category":1244,"tags":3430},"UnReview a year later: How GitLab is transforming DevOps code review with ML-powered functionality",[3305],"2022-06-02","\n\nA little over a year ago, [GitLab acquired UnReview](/press/releases/2021-06-02-gitlab-acquires-unreview-machine-learning-capabilities.html), a machine learning-based solution for automatically identifying [relevant code reviewers](/stages-devops-lifecycle/create/) and distributing review workloads and knowledge. Our goal is to integrate UnReview’s ML-powered code review features throughout GitLab, the One DevOps Platform. We checked in with Taylor McCaslin, principal product manager, ModelOps, at GitLab, to find out the impact UnReview has had so far and what comes next.\n\n**The idea of applying machine learning to code review was already underway at GitLab before the UnReview acquisition. What was it about ML/AI and automation that seemed a good fit for the code review process? How did the UnReview acquisition affect that strategy?**\n\nThe acquisition of UnReview gave GitLab a practical way to get started with a really focused value proposition that was obvious to the platform. ML/AI is a lot more than just having a useful algorithm. UnReview and its team gave GitLab talent with experience building MLOps pipelines and working with production DataOps workflows. As a source code management ([SCM](/solutions/source-code-management/)) and continuous integration ([CI](/topics/ci-cd/)) platform, MLOps and DataOps are key ambitions for our ModelOps stage. UnReview is the foundational anchor of our AI Assisted group, and we anticipate developing more ML-powered features with the base that we’ve built integrating UnReview into our One DevOps platform. If it’s something you manually set today within GitLab, we’ll consider suggestions and automations: suggested labels, assignees, issue relationships, etc. You can learn more about our plans on our [AI Assisted direction page](/direction/modelops/ai_assisted/).\n\n> You’re invited! Join us on June 23rd for the [GitLab 15 launch event](https://page.gitlab.com/fifteen) with DevOps guru Gene Kim and several GitLab leaders. They’ll show you what they see for the future of DevOps and The One DevOps Platform.\n\n**There were [three specific objectives with the UnReview project](/handbook/engineering/development/data-science/ai-assisted/projects/unreview/#overview) when you first started:**\n- **Eliminate the time wasted manually searching for an appropriate code reviewer to review code changes.**\n- **Make optimum recommendations that consider the reviewers’ experience and optimize the review load across the team, which additionally facilitates knowledge sharing.**\n- **Provide analytics on the state of code review in the project, explaining why a particular code reviewer is recommended.**\n\n**Have you had to change or add to these in any way?**\n\nWe now have Suggested Reviewers running for external beta customers as well as dogfooding it internally. We’ve learned a lot about what makes a good code reviewer. Some of the obvious things like context with the changed files and history of committing to that area of code are obvious. But there are less obvious things like what type of code someone has experience with (front-end or back-end).\n\nWe’re finding the concept of recency interesting: the idea that people who more recently interacted with files and functions may be better suited to review the code. Also, people leave companies, and that’s usually not something that can be inferred by the source graph, so we’re working on merging additional GitLab activity data with the recommendation engine.\n\nIn addition, we’re thinking a lot about bias in our recommendations. For example, a senior engineer likely has the most commits across a project, but we don’t always want to recommend a senior engineer. The more we work with the algorithm and recommendations, the more nuanced we find it.\n\nNot every organization does code review the same way, so we’re considering building different models for those that have no process versus organizations that have very rigid and hierarchical reviewer requirements. We also have to consider how recommendations interact with other features of the platform like code owners, maintainer roles, and commit access.\n\nWe’ve never been more excited about the potential of machine learning within GitLab. Some of the feedback we’ve had from beta customers are “this feels like magic” and that honestly encapsulates what we’re going for. Sometimes the right code reviewer is just a feeling that you can’t quite put your finger on. Through data and a little bit of magic, we may see Suggested Reviewers help speed up workflows, and cut down on back and forth and wasted time trying to find someone to do a great review of your code.\n\n**Introducing ML-powered features can come with challenges, especially being GitLab’s first data science feature. Can you speak to some of those challenges and how the team overcame them?**\n\nIt has been about a year since we closed the transaction. During that time period we’ve introduced a lot of new concepts to GitLab. Access to real-time data within the feature with DataOps extraction and cleaning of platform activity data. We have an end-to-end MLOps pipeline running 100% within GitLab CI that extracts, builds, trains, and deploys the UnReview model, and new observability metrics to know if the whole system is working. These are all foundational concepts that we’ve had to build from the ground up.\n\nAlso, we’ve introduced Python to the GitLab tech stack and have to develop new engineering standards and hiring interview practices to find the right talent for this team. We’re now turning the corner of this foundational work and I anticipate that relatively soon we’ll release Suggested Reviewers fully integrated with the platform and UI.\n\nMilestones have been part of the way we’ve sliced up the integration work. We have a variety of internal milestones we’ve been tracking against, including porting the model into GitLab SCM and CI, building the Dataops and MLOps pipelines, and internal and external customer betas. It’s helpful to have these milestones to know what’s most important at any given time and not to get overwhelmed with all the moving pieces. We’re paving a new path with ML-powered features at GitLab, and once we’re done we’ll have a repeatable process and template to replicate over and over with new data science-powered features.\n\n**What has been the most surprising thing you’ve encountered or learned since UnReview first debuted?**\n\nCode Reviewers are foundational to the software development lifecycle. We thought this would be a really straightforward feature, but it turns out people REALLY care about recommendations. People hate bad suggestions so when the recommendations are wrong, the feedback is fast and furious. But when it’s right, it feels like magic. That really surprised me how positively people respond to a great suggestion.\n\nA lot of GitLab users have asked me what our success metric is for Suggested Reviewers. It should just feel like magic. Maybe you don’t know why someone was chosen, but you just feel they were the right person to review the change. And hopefully that leads to a more thoughtful code review, reduces the back and forth of trying to find someone to review your code, and ultimately creates a better experience end-to-end. A lot of engineers dread code reviews; we want to change that. I hope Suggested Reviewers can take the pain out of the experience and make it something engineers look forward to. That’s the feeling we’re trying to create with our recommendations. Obvious but magic.\n\n**What’s next for UnReview specifically and DevOps code review more generally? Where do you see the next big advances happening?**\n\nWe’re just scratching the surface. There are so many opportunities for recommendations and automations across the platform. We have a lot of data at GitLab, from the source graph, contribution history, CI builds, test logs, security scans, and deployment data. We believe all of this can be integrated together. I’m particularly excited about what we’re calling [Intelligent Code Security](/direction/modelops/ai_assisted/#categories). The idea is that we will be able to look at your source code as you’re writing it, analyze it for security vulnerabilities, and not only suggest fixes to common security flaws, but also apply that change, run your CI, confirm the build succeeds, confirm the vulnerability was resolved, and possibly even deploy that change, all automatically.\n\nImagine the future where your code gets more secure automatically while you sleep. That sounds wild, but we have the data to power [a feature like this in the future](/direction/modelops/ai_assisted/#categories). Suggested Reviewers is just the beginning. We haven’t seen many DevOps platforms fully embrace the data, code, and activity data that they have in a material way. I think we’ll see a lot more in this space moving forward as development platforms identify the massive opportunities to drive efficiencies and remove the frustrating parts of software development from the process.\n",[851,975,785,9,934],{"slug":3432,"featured":6,"template":696},"unreview-a-year-later-how-gitlab-is-being-transformed-by-ml-powered-code-review","content:en-us:blog:unreview-a-year-later-how-gitlab-is-being-transformed-by-ml-powered-code-review.yml","Unreview A Year Later How Gitlab Is Being Transformed By Ml Powered Code Review","en-us/blog/unreview-a-year-later-how-gitlab-is-being-transformed-by-ml-powered-code-review.yml","en-us/blog/unreview-a-year-later-how-gitlab-is-being-transformed-by-ml-powered-code-review",{"_path":3438,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3439,"content":3445,"config":3451,"_id":3453,"_type":13,"title":3454,"_source":15,"_file":3455,"_stem":3456,"_extension":18},"/en-us/blog/use-gitlab-ai-features-out-of-the-box-in-a-gitlab-workspace",{"title":3440,"description":3441,"ogTitle":3440,"ogDescription":3441,"noIndex":6,"ogImage":3442,"ogUrl":3443,"ogSiteName":683,"ogType":684,"canonicalUrls":3443,"schema":3444},"Use GitLab AI features out-of-the-box in a GitLab Workspace","GitLab Workspaces now ships with the GitLab workflow extension preinstalled, providing access to powerful AI features like GitLab Duo Chat and Code Suggestions for increased productivity.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098843/Blog/Hero%20Images/Blog/Hero%20Images/securitylifecycle-light_securitylifecycle-light.png_1750098843047.png","https://about.gitlab.com/blog/use-gitlab-ai-features-out-of-the-box-in-a-gitlab-workspace","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Use GitLab AI features out-of-the-box in a GitLab Workspace\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Safwan Ahmed\"}],\n        \"datePublished\": \"2024-07-24\",\n      }",{"title":3440,"description":3441,"authors":3446,"heroImage":3442,"date":3448,"body":3449,"category":1568,"tags":3450},[3447],"Safwan Ahmed","2024-07-24","AI is transforming the way we get work done, from helping automate mundane tasks to optimizing aspects of our day-to-day workflow. Of particular relevance has been [generative AI’s ability](https://about.gitlab.com/the-source/ai/how-to-put-generative-ai-to-work-in-your-devsecops-environment/) to support developers in getting the job done, from code snippet suggestions to concise summaries of technical questions. These AI tools have been embedded in the development lifecycle through integrations with existing software like code editors and CI/CD platforms. Thanks to these integrations, particularly in the case of code editors, developers can have an AI assistant that complements their skills within their development environment.\n\nWhile these AI tools can help boost productivity, setting them up in an existing development environment may not be preferable. For example, you may not want to install a new dependency on your local workstation that could affect your setup, you may have security or privacy concerns about running AI tools on your computer, or you may find it hard to give the tooling context on your existing workflow. GitLab resolves these issues by providing a suite of tools that allow you to leverage the power of AI in [a remote development workspace](https://about.gitlab.com/blog/quick-start-guide-for-gitlab-workspaces/) right out of the box. In this blog, you'll learn about the GitLab features that make this possible and how to set up your [workspace environment](https://docs.gitlab.com/ee/user/workspace/) to get started.\n\n## GitLab workflow extension for VS Code\n\nGitLab workflow extension for VS Code integrates GitLab into the VS Code editor. It brings into scope key elements of your GitLab workflow such as issues, merge requests, and pipeline status. For more information, visit [the GitLab workflow extension documentation](https://docs.gitlab.com/ee/editor_extensions/visual_studio_code/).\n\n## GitLab Workspaces\n\nGitLab Workspaces provide an isolated development environment to make changes to your GitLab projects. Workspaces offer a platform to work on your projects without the complexity of setting up local dependencies. Workspaces also provide reproducible development setups, as a workspace environment configuration created by one developer can be shared with others. GitLab Workspaces are configured to use the VS Code editor and ship with the workflow extension preinstalled. To learn more, visit the [GitLab Workspaces documentation](https://docs.gitlab.com/ee/user/workspace/).\n\n## GitLab Duo Chat and Code Suggestions\n\n[GitLab Duo Chat](https://about.gitlab.com/blog/gitlab-duo-chat-now-generally-available) and [GitLab Duo Code Suggestions](https://about.gitlab.com/blog/gitlab-duo-code-suggestions-is-generally-available/) are part of the GitLab Duo suite of AI features enhancing developer productivity. Chat and Code Suggestions are integrated into the workflow extension and are GitLab context-aware. This allows you to ask GitLab Duo questions about items like issues and merge requests and to automatically have access to code suggestions and code completion. This integration requires [a GitLab Duo license](https://about.gitlab.com/gitlab-duo/). See the [GitLab Duo Chat documentation](https://docs.gitlab.com/ee/user/gitlab_duo_chat/) and [GitLab Duo Code Suggestions documentation](https://docs.gitlab.com/ee/user/project/repository/code_suggestions/) for more information.\n\n## How to set up the Workflow extension, Workspaces, and GitLab Duo to work together\n\nWhile these features are impressive on their own, when combined they deliver on the promise of an easy-to-spin-up, isolated, AI-driven development environment. Here are the steps to get this powerhouse up and running.\n\n## Create a workspace\n\nFollow this [comprehensive but easy-to-follow tutorial](https://about.gitlab.com/blog/quick-start-guide-for-gitlab-workspaces/) to create a remote development workspace.\n\n## Validate GitLab Workflow is active\n\nAfter your workspace is up and running, you should see a GitLab icon on the side of your editor like the following:\n\n![Arrow pointing to GitLab tanuki icon](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098853/Blog/Content%20Images/Blog/Content%20Images/image6_aHR0cHM6_1750098853108.png)\n\nYou can then use the workflow extension to bring up merge requests assigned to you in the current project in GitLab. To do this, access the command palette by hitting `command + shift + P` and entering `GitLab: Show Merge Requests Assigned to Me`. This will redirect you to GitLab and show your assigned MRs.\n\n![Arrow pointing to 'GitLab: Show Merge Requests Assigned to Me'](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098853/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750098853109.png)\n\nFor more tips and tricks, read [Visual Studio code editor: Eight tips for using GitLab VS Code](https://about.gitlab.com/blog/vscode-workflows-for-working-with-gitlab/).\n\n## Use GitLab Duo Chat\n\nYou should also see a second, smaller GitLab icon on your sidebar. This gives you access to GitLab Duo Chat. Feel free to ask it a question.\n\n![Arrow pointing to GitLab tanuki icon with sparkles around it](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098853/Blog/Content%20Images/Blog/Content%20Images/image5_aHR0cHM6_1750098853111.png)\n\n## Use GitLab Duo Code Suggestions\n\nOpen up any source file in your directory. You can begin typing code and have predictive suggestions, powered by GitLab Duo Code Suggestions, pop up –  you can insert them by hitting the tab key. The example below shows my attempt to write a string processing function. Code Suggestions has inferred I would want to split the passed string into spaces, which is indeed my intention.\n\n![Code Suggestions suggesting that the passed string into spaces](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098853/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750098853112.png)\n\nSuppose I have completed my string processing function above and would like to generate unit tests for it but want to avoid the chore of writing boilerplate code. You can provide a comment in your editor and have Code Suggestions generate code for you like the following:\n\n![Shows boilerplate code for generating unit tests](https://res.cloudinary.com/about-gitlab-com/image/upload/v1750098853/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750098853115.png)\n\nCode Suggestions implements a whole unit test for my function, covering happy and sad paths.\n\nFor more exciting uses of the GitLab Duo suite, check out these articles:\n* [10 best practices for using AI-powered GitLab Duo Chat](https://about.gitlab.com/blog/10-best-practices-for-using-ai-powered-gitlab-duo-chat/)\n* [Top tips for efficient AI-powered Code Suggestions with GitLab Duo](https://about.gitlab.com/blog/top-tips-for-efficient-ai-powered-code-suggestions-with-gitlab-duo/)\n* [\"Developing GitLab Duo\" blog series](https://about.gitlab.com/blog/developing-gitlab-duo-series/)\n\n# Next steps\n\nGitLab Workspaces is coming up with more exciting integrations and features that will enhance your remote development experience, be sure to check out the [category epic](https://gitlab.com/groups/gitlab-org/-/epics/7419) to know what’s coming next!\n\n> Sign up for [a free trial of GitLab Duo](https://about.gitlab.com/gitlab-duo/) today!\n",[934,872,9,742],{"slug":3452,"featured":90,"template":696},"use-gitlab-ai-features-out-of-the-box-in-a-gitlab-workspace","content:en-us:blog:use-gitlab-ai-features-out-of-the-box-in-a-gitlab-workspace.yml","Use Gitlab Ai Features Out Of The Box In A Gitlab Workspace","en-us/blog/use-gitlab-ai-features-out-of-the-box-in-a-gitlab-workspace.yml","en-us/blog/use-gitlab-ai-features-out-of-the-box-in-a-gitlab-workspace",{"_path":3458,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3459,"content":3465,"config":3472,"_id":3474,"_type":13,"title":3475,"_source":15,"_file":3476,"_stem":3477,"_extension":18},"/en-us/blog/use-streaming-audit-events-to-connect-your-technology-stack-with-gitlab-and-pipedream",{"title":3460,"description":3461,"ogTitle":3460,"ogDescription":3461,"noIndex":6,"ogImage":3462,"ogUrl":3463,"ogSiteName":683,"ogType":684,"canonicalUrls":3463,"schema":3464},"Streaming audit events: Connect GitLab to your tech stack","Automation lets your DevSecOps teams have logic in place for how to handle events as they come in.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749667845/Blog/Hero%20Images/gl15.jpg","https://about.gitlab.com/blog/use-streaming-audit-events-to-connect-your-technology-stack-with-gitlab-and-pipedream","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Use Streaming Audit Events to connect your technology stack with GitLab and Pipedream\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sam Kerr\"}],\n        \"datePublished\": \"2022-06-27\",\n      }",{"title":3466,"description":3461,"authors":3467,"heroImage":3462,"date":3469,"body":3470,"category":716,"tags":3471},"Use Streaming Audit Events to connect your technology stack with GitLab and Pipedream",[3468],"Sam Kerr","2022-06-27","\n\nGitlab recently released [Streaming Audit Events](https://docs.gitlab.com/ee/administration/audit_event_streaming.html) to provide you real-time visibility into what happens inside your GitLab groups and projects. Whenever something happens, an event will be sent to the HTTPS destination of your choice. This is a great way to understand immediately when something has changed and if there is an action that needs to be taken.\n\nThese events are often used to drive automation to update GitLab in response to certain actions, such as creating a new issue to onboard a team member when an account is added to a group, or to restore the correct value of a [merge request approval setting](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/settings.html) if it is changed. We know that many users want to combine the streaming audit events with other data sets and tools they already work with. Taking automatic action in response to audit events happening can help ensure your GitLab groups and projects are always in the correct, compliant state.\n\n## Pipedream simplifies the streaming audit event process\n\nDriving automation off of these events or combining the events with other data sets means the destination which will receive the events needs to be running and have logic in place for how to handle the events as they come in. This normally would require setting up and maintaining a server with high availability to receive events as they happen, run any automation scripts, and then process the events if they needed to be sent to another tool or combined with another data set. This is tricky to do right and an extra step that takes time. \n\nEnter our partner, [Pipedream](https://pipedream.com/). \n\nPipedream lets you connect APIs, remarkably fast. This includes the new streaming audit events from GitLab. When you select the GitLab New Audit Events trigger in a Pipedream workflow, Pipedream will automatically register an HTTPS endpoint for audit events in your GitLab group:\n\n![Pipedream registration process](https://about.gitlab.com/images/blogimages/pipedreamscreenshot.png){: .shadow}\n\nFrom there, Pipedream allows you to transform the data, forward it to any other tools using Pipedream’s [prebuilt actions](https://pipedream.com/docs/workflows/steps/actions/), or write any custom automation [with code](https://pipedream.com/docs/code/) (i.e., Node.js, Python, Go, or Bash).\n\n## Getting started with Pipedream and GitLab\n\nThe video below shows an example of how to use GitLab streaming audit events and Pipedream together to automatically alert your security team if a sensitive project setting is changed. This is powerful because it ensures that your security teams can immediately take action when a change occurs and understand why it happened.\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/ggzoUMEsjjU\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nThis is just one example of what you can do with Pipedream and GitLab together. Pipedream allows you to use any [GitLab API](https://docs.gitlab.com/ee/api/) in response to an audit event: You can change the setting to its original value, add comments to issues, kick off pipelines, and more. You can also trigger any action in any of the [700+ other apps](https://pipedream.com/apps) that it has built-in integrations with.\n\n## Open source integration means everyone can contribute\n\nPipedream and GitLab are both strong believers in open source. The integration is publicly available at the Pipedream [repository](https://github.com/PipedreamHQ/pipedream), and contributions are welcome! We are excited to see what sort of workflows you create with Pipedream and GitLab together.\n\n## Final thoughts\n\nIn this post, we talked about the power of GitLab’s [Streaming Audit Events](https://docs.gitlab.com/ee/administration/audit_event_streaming.html) to give you immediate visibility into your groups and projects and how Pipedream makes it easy to build and automate workflows based on those audit events. This was just a preview of what is possible though, as you can use the entire GitLab API within Pipedream in response to audit events or interact with other tools supported by Pipedream.\n\nWe are excited to see the workflows you build with GitLab and Pipedream together. We showed how you can create a GitLab issue to alert the security team when settings are changed, but the sky is the limit - you might also create issues when new user accounts are created to onboard new team members, automatically restore changed settings, or forward data to a security information and event management, a.k.a. SIEM, system. With Pipedream and Gitlab, you can automatically take the actions necessary when things change to ensure you remain secure and compliant.\n",[851,9,716],{"slug":3473,"featured":6,"template":696},"use-streaming-audit-events-to-connect-your-technology-stack-with-gitlab-and-pipedream","content:en-us:blog:use-streaming-audit-events-to-connect-your-technology-stack-with-gitlab-and-pipedream.yml","Use Streaming Audit Events To Connect Your Technology Stack With Gitlab And Pipedream","en-us/blog/use-streaming-audit-events-to-connect-your-technology-stack-with-gitlab-and-pipedream.yml","en-us/blog/use-streaming-audit-events-to-connect-your-technology-stack-with-gitlab-and-pipedream",{"_path":3479,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3480,"content":3485,"config":3490,"_id":3492,"_type":13,"title":3493,"_source":15,"_file":3494,"_stem":3495,"_extension":18},"/en-us/blog/using-bazel-to-speed-up-gitlab-ci-builds",{"title":3481,"description":3482,"ogTitle":3481,"ogDescription":3482,"noIndex":6,"ogImage":797,"ogUrl":3483,"ogSiteName":683,"ogType":684,"canonicalUrls":3483,"schema":3484},"How to use Bazel with GitLab to speed up your builds","We explain why Bazel and GitLab CI are a great match to speed up your build times.","https://about.gitlab.com/blog/using-bazel-to-speed-up-gitlab-ci-builds","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to use Bazel with GitLab to speed up your builds\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Jason Yavorska\"}],\n        \"datePublished\": \"2020-09-01\",\n      }",{"title":3481,"description":3482,"authors":3486,"heroImage":797,"date":3487,"body":3488,"category":739,"tags":3489},[736],"2020-09-01","[Bazel](https://bazel.build/) is a useful tool that can be used with GitLab\nCI to push your build pipelines into overdrive.\n\n\nFor maximum correctness, [CI/CD](/topics/ci-cd/) systems will usually\nrebuild all of the artifacts from scratch on every run. This method is\nconsidered safer since artifacts from one pipeline won't negatively impact\nsubsequent pipelines, and is a lesson learned from older CI tools where the\nagent state was persistent over time – so you never really knew if you could\ndo a build from scratch. The problem with redoing everything every time\nthough, is that it's slow. GitLab improves upon this by using caches and\nshared artifacts, but there's only so far that approach can take you.\n\n\nBazel is a good example of tackling things in a different way – it speeds up\nbuilds by only rebuilding what is necessary. On the surface, this might\nsound a lot like just having a cache and doing an incremental build. But the\nmain difference is that Bazel is really good at not only being fast, but\nalso\n[correct](https://docs.bazel.build/versions/3.4.0/guide.html#correct-incremental-rebuilds).\nBazel is much more reliable than traditional `Makefiles` or build scripts,\nwhich are notorious for occasionally forcing you to `make clean` because\nthey get into some inconsistent state they can't recover from.\n\n\nAs of now, Bazel supports building Java, C, C++, Python, and Objective-C,\nand can also produce packages for deployment on Android or iOS. More\ncapabilities are being added all the time, as well as open source rule sets\nfor other languages like Go, Scala and many more, so be sure to check their\nlatest [product\noverview](https://docs.bazel.build/versions/3.4.0/bazel-overview.html) for\nupdates.\n\n\n## Setting up Bazel builds in GitLab CI\n\n\nSetting up Bazel for builds is very straightforward. A job like the\nfollowing does everything you need:\n\n\n```yaml\n\nvariables:\n  BAZEL_DIGEST_VERSION: \"f670e9aec235aa23a5f068566352c5850a67eb93de8d7a2350240c68fcec3b25\" # Bazel 3.4.1\n\nbuild:\n  image:\n    name: gcr.io/cloud-marketplace-containers/google/bazel@sha256:$BAZEL_DIGEST_VERSION\n    entrypoint: [\"\"]\n  stage: build\n  script:\n    - bazel --output_base output build //main/...\n  artifacts:\n    paths:\n      - bazel-bin/main/hello-world\n  cache:\n    key: $BAZEL_DIGEST_VERSION\n    paths:\n      - output\n```\n\n\nWhat this script does is define a job called `build` which uses the official\nGoogle Bazel image. We track the digest version for two reasons: First, to\nensure immutability (tags can be updated), and second to use it as a cache\nkey so that the cache is invalidated whenever we upgrade the Bazel version.\nWe also override the entry point because we want to pass our own parameters\nto our `bazel` invocation. The second parameter is the\n[label](https://docs.bazel.build/versions/master/glossary.html#label) of the\n[target](https://docs.bazel.build/versions/master/glossary.html#target) we\nwant to build. A [target\npattern](https://docs.bazel.build/versions/master/glossary.html#target-pattern)\ncan also be used here to tell Bazel to build multiple things (and what they\ndepend on), rather than one thing (and what it depends on).\n\n\nThe first parameter (`--output_base output`) is to help Bazel work with a\nsecurity feature of the GitLab runner. By default, the runner will [not\naccess files outside of the build\ndir](https://docs.gitlab.com/ee/ci/yaml/#artifactspaths), but Bazel places\nits own cache outside by default. This parameter tells Bazel to place it\ninside, where the runner can access it. The next two sections (`artifacts`\nand `cache`), tell the runner where the output file you want to keep is, and\nimportantly for Bazel, where the cache is that you want to persist. Note\nthat until [this issue to allow for traversing\nsymlinks](https://gitlab.com/gitlab-org/gitlab/-/issues/19746) is resolved,\nyou must give the full path to the specific outputs you want to keep within\nthe `bazel-bin` folder.\n\n\nWhen this job runs, it places the current cache (if it exists, and only for\nthe current `BAZEL_DIGEST_VERSION`) in the `output` folder, and then runs\n`bazel` to build the `main:hello-world` target. It saves the artifact from\n`bazel-bin/main/hello-world`, and then caches everything in `output` for the\nnext run.\n\n\n### Bazel: notes on caching\n\n\nIn this example we've set up Bazel to work with GitLab caching, and this is\nhow we currently use it internally. If you already have Bazel remote cache\n(or even better, Bazel remote execution), there is no need to set up GitLab\nCI cache: It actually would likely make things slower since in that case\nthere is no need to download and unpack the cache at all. Setting up remote\ncaching or remote execution are more advanced and outside of the scope of\nthis article, but are even better ways to speed up the build. Until then,\nusing a GitLab cache can be a good interim step. If you're interested in\nlearning more about remote cache/remote execution, this [BazelCon\nvideo](https://www.youtube.com/watch?v=MyuJRUwT5LI&t=1017s) or Bazel's\nofficial [documentation on remote\ncaching](https://docs.bazel.build/versions/master/remote-caching.html) may\nbe helpful.\n\n\n## Building and testing with Bazel\n\n\nUsing Bazel to run your tests is just as easy, and there are nice benefits\nto doing so. If you can rely on accurately knowing what has changed, you can\nbe more selective in doing incremental tests and have the confidence that\ntests that were skipped were truly unnecessary. This is also quite easy to\nset up using Bazel, but one thing to consider is that running builds and\ntests all at once (rather than splitting build and test into different jobs)\nis going to be more efficient. You can do that by using a build job that\nlooks like this:\n\n\n```yaml\n\nvariables:\n  BAZEL_DIGEST_VERSION: \"f670e9aec235aa23a5f068566352c5850a67eb93de8d7a2350240c68fcec3b25\" # 3.4.1\n\nbuild:\n  image:\n    name: gcr.io/cloud-marketplace-containers/google/bazel@sha256:$BAZEL_DIGEST_VERSION\n    entrypoint: [\"\"]\n  stage: build\n  script:\n    - bazel --output_base output test //main/...\n  artifacts:\n    paths:\n      - bazel-bin/main/hello-world\n  cache:\n    key: $BAZEL_DIGEST_VERSION\n    paths:\n      - output\n```\n\n\nIn a build that includes all tests, you typically want to run everything\nthat changed. That's usually done using an invocation like `bazel test\n//main/...` which:\n\n\n1. Finds all targets (referred to as `...`) in the workspace location (`//`\ndenotes the root of the\n[workspace](https://docs.bazel.build/versions/master/glossary.html#workspace)),\nso we are referring to `main` relative to the root.) Note that you probably\ndon't want to include a bare `//` (without `main`), since that will include\nthe custom `output` folder and that is probably not what you intended.\n\n1. Builds usual targets.\n\n1. Builds test targets.\n\n1. Runs test targets.\n\n\nOnly using the `test` parameter works because `bazel test` not only runs\ntests, but also builds everything that matched the target pattern by\ndefault. Individual targets can be excluded from being matched by `...` by\napplying a `manual` tag to them ([see `tags` in the Bazel glossary\ntable](https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes)).\nOne callout - in the example project we're building ([details\nbelow](#examples)), there actually aren't any tests, so this fails because\nwe requested a test pass and there weren't any. If your project has tests in\nit, it will work fine.\n\n\n## Examples using Bazel\n\n\nWe're actually using Bazel here at GitLab to build our [GitLab Agent for\nKubernetes](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent).\nIf you're interested in seeing a more complex, complete implementation using\nBazel then that's a great one to explore. The simple example from this blog\ncan be found live in [my own personal\nproject](https://gitlab.com/jyavorska/testbazel), and it is based on the\n[stage three build\ntutorial](https://docs.bazel.build/versions/3.4.0/tutorial/cpp.html) from\nBazel's own documentation.\n\n\nBazel itself is also highly configurable through its own `.bazelrc`, `BUILD`\nfiles, and more. The [user documentation for\nBazel](https://docs.bazel.build/versions/master/guide.html) contains several\nexamples along with an exhaustive configuration reference.\n\n\n## What's next with Bazel?\n\n\nWe are considering using Bazel in few more areas within GitLab:\n\n\n- In an ideal world, after a minor change, the build and test should only\ntake a few seconds to complete. When the jobs are fast enough, it could even\nbe triggered via an editor on every change before being committed to git at\nall. This kind of capability could be integrated with the Web IDE, giving\nyou immediate insight into the results of your change. We have an issue\nrelated to [making it easier to run pipelines from the Web\nIDE](https://gitlab.com/gitlab-org/gitlab/-/issues/213604) that could take\nadvantage of this.\n\n- By default, GitLab uses [a gem we\ncreated](https://gitlab.com/gitlab-org/ci-cd/test_file_finder/) (which is\navailable in this\n[template](https://docs.gitlab.com/ee/ci/testing/fail_fast_testing.html) for\ntest execution optimization, but all we're doing so far is running the\nriskiest tests first. As Bazel grows and adds support for more languages, it\ncould potentially become a standard for this purpose, allowing you to run\neven fewer tests (and among those, the riskiest ones first). We have an\n[epic](https://gitlab.com/groups/gitlab-org/-/epics/4121) where you can\ntrack progress toward this idea.\n\n- Finally, Bazel also supports distributed builds and caching, opening the\ndoor to autoscaling compilation and test capacity alongside runner capacity,\nor even sharing the same capacity for whatever jobs are needed at a given\nmoment. This function would require managing your own capacity for this\npurpose, but in the future we could imagine this being added to GitLab. We\nhave an [issue for exploring different ways Bazel could support distributed\njobs](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26663) using the\nGitLab Runner.\n\n\n## Tell us your Bazel success stories\n\n\nAre you using Bazel with GitLab CI? We'd love your feedback on what features\nwe could add to make things work better and hear about the performance gains\nyou've found from the combo. Please let us know in the Meta issue below, or\ncontact [Jason Yavorska](https://twitter.com/j4yav) on Twitter.\n\n\n## Related content\n\n\n- [Bazel website](https://bazel.build/)\n\n- [Meta issue for deeper integration in\nGitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/201484)\n\n- [Bazel blog on integrating it with CI\nsystems](https://blog.bazel.build/2016/01/27/continuous-integration.html)\n\n- [GitLab CI quick start](https://docs.gitlab.com/ee/ci/quick_start/)\n\n\nCover image by [Lucas van Oort](https://unsplash.com/@switch_dtp_fotografie)\non [Unsplash](https://unsplash.com)\n\n{: .note}\n",[108,9,807],{"slug":3491,"featured":6,"template":696},"using-bazel-to-speed-up-gitlab-ci-builds","content:en-us:blog:using-bazel-to-speed-up-gitlab-ci-builds.yml","Using Bazel To Speed Up Gitlab Ci Builds","en-us/blog/using-bazel-to-speed-up-gitlab-ci-builds.yml","en-us/blog/using-bazel-to-speed-up-gitlab-ci-builds",{"_path":3497,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3498,"content":3504,"config":3509,"_id":3511,"_type":13,"title":3512,"_source":15,"_file":3513,"_stem":3514,"_extension":18},"/en-us/blog/vault-integration-process",{"title":3499,"description":3500,"ogTitle":3499,"ogDescription":3500,"noIndex":6,"ogImage":3501,"ogUrl":3502,"ogSiteName":683,"ogType":684,"canonicalUrls":3502,"schema":3503},"How we’ll simplify Vault access for GitLab CI/CD users","CEO Sid Sijbrandij and senior product manager Thao Yeager discuss the easiest way to bring Vault access to GitLab customers. Hint: it involves a minimum viable change.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681067/Blog/Hero%20Images/vaultintegration.jpg","https://about.gitlab.com/blog/vault-integration-process","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How we’ll simplify Vault access for GitLab CI/CD users\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Valerie Silverthorne\"}],\n        \"datePublished\": \"2020-02-13\",\n      }",{"title":3499,"description":3500,"authors":3505,"heroImage":3501,"date":3506,"body":3507,"category":763,"tags":3508},[1097],"2020-02-13","\n\nIn the increasingly complex and secret-filled world of software development, companies must decide how to simplify access to the secure data necessary to [run CI/CD](/topics/ci-cd/) jobs. [HashiCorp’s Vault](https://www.vaultproject.io/docs/what-is-vault/) is a solution many organizations have chosen to manage their secret storage, but what’s the best way to request Vault tokens without slowing down software development?\n\nGitLab CEO [Sid Sijbrandij](/company/team/#sytses) recently sat down to speak with [Thao Yeager](/company/team/#thaoyeager), senior product manager, Verify: Templates and [Jackie Meshell](/company/team/#jmeshell), senior product manager,  to discuss how our customers using Vault could best get access to their stored variables within GitLab. On the table were two options that would provide a [“minimum viable change” or MVC](https://handbook.gitlab.com/handbook/values/#minimal-viable-change-mvc) – a key part of our [core value of iteration](/blog/power-of-iteration/) and a strategy we believe enables us to move more quickly.\n\nThe two options on the table were to either use [GitLab Runner](https://docs.gitlab.com/runner/) to fetch tokens that are stored in Vault or to do a [Rails integration](/blog/why-we-use-rails-to-build-gitlab/) with Vault. \n\n## Rotate if you can't hide\n\nIn earlier days, Sid recalls “secrets management” used to be about making sure people simply didn’t find them out. That’s not practical any longer. “It’s super hard never to push a secret in your repository and have it end up somewhere,” he says. “It’s almost impossible. It ends up in the logs. They radiate everywhere.”\n\nToday’s secret management involves rotating and updating secrets as often as necessary. It can be tricky to put all the pieces together.\n\nIt starts with Vault, which Sid sees as just another data store, like a database but one just focused on secrets. “We should use Vault for secrets because it’s starting to become the standard for that,” he says. But we can also no longer assume that secrets will always remain safe, and thus it’s key to be able to rotate them. “At some point you’re going to have a breach and they’re going to find out all your secrets,” he says. Rotation is a way “secrets can get back to a state where they’re secrets again,” Sid says, adding that Vault is very good for rotation and access control.\n\n> Secrets management used to be about making sure people simply didn’t find them out. That’s not practical any longer.\n\nIt’s clear to Sid that GitLab’s super sensitive data should be separated into Vault. “We can better secure (Vault). For example, we can [rate limit](https://docs.gitlab.com/ee/security/rate_limits.html). If we’re going to rate limit our Rails app calls to the database that would involve dealing with an enormous amount of traffic. If we just have the secrets in Vault, it’s a much more limited set of traffic.” One other advantage: Vault has way less surface area than our Rails app or our database, Sid explains. “(Vault) is complex to run but the surface area is smaller.”\n\n## A simpler solution\n\nWith Vault on the backend holding the secrets, Sid thinks a simple runner – instructed by Rails – is the right MVC to move this project forward. It was not necessary to do the more complicated Rails integration. “All of the logic is in the Rails app and then it sends it off to the runner with ‘Ok, run the script.’” This solution keeps the complexity in the Rails app, which works because “Ruby is great for all that complexity,” Sid says. The runner can be something simple that lives on multiple platforms. “The last thing we want is the runner to have more dependencies and more complexity.”\n\nUltimately Sid expects customers will want to use their own Vault installations, but for now that reality is complicated. Integrating GitLab with Vault is the more straightforward solution for the time being. And it’s certainly the safest: Vault won’t give out the same credential twice and the credentials have a very short life span, two things that will make a breach less dangerous, Sid says. “You will never have another secret that can’t be rotated,” Sid says. “Every secret is able to be rotated so you can always push that button. That's the future we're working towards and we should make that future easier for our users to adopt.”\n\nWatch the entire video:\n\n\u003C!-- blank line -->\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/9kD3geEmSJ8\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\u003C!-- blank line -->\n\nCover image by [Chris Barbalis](https://unsplash.com/@cbarbalis) on [Unsplash](https://www.unsplash.com)\n{: .note}\n",[108,716,9],{"slug":3510,"featured":6,"template":696},"vault-integration-process","content:en-us:blog:vault-integration-process.yml","Vault Integration Process","en-us/blog/vault-integration-process.yml","en-us/blog/vault-integration-process",{"_path":3516,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3517,"content":3522,"config":3527,"_id":3529,"_type":13,"title":3530,"_source":15,"_file":3531,"_stem":3532,"_extension":18},"/en-us/blog/vscode-extension-development-with-gitlab",{"title":3518,"description":3519,"ogTitle":3518,"ogDescription":3519,"noIndex":6,"ogImage":2757,"ogUrl":3520,"ogSiteName":683,"ogType":684,"canonicalUrls":3520,"schema":3521},"VS Code extension development with GitLab","As VS Code editor increases in popularity, find out how GitLab + VS Code can be used for extension development and how we develop the official GitLab VS Code extension.","https://about.gitlab.com/blog/vscode-extension-development-with-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"VS Code extension development with GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tomas Vik\"}],\n        \"datePublished\": \"2020-11-30\",\n      }",{"title":3518,"description":3519,"authors":3523,"heroImage":2757,"date":3524,"body":3525,"category":739,"tags":3526},[2762],"2020-11-30","\n## What is Visual Studio Code (VSC)?\n\nMicrosoft Visual Studio Code (VS Code) is an extensible text editor. It's implemented in TypeScript and runs on Node 12 and Electron. It was [first released in 2015](https://github.com/microsoft/vscode/releases/tag/0.10.1), and since then, become widely popular[^2]. This post explains the basics about the development of VS Code extensions, shows how you can use GitLab for extension development, and shares how we build the official [GitLab VS Code extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).\n\n## VS Code editor key features\n\nFor me, the key feature of the VS Code editor is that it created a platform for extensions. That means not just providing an API for extensions (which editors have done since the '90s [^3]) but also providing a marketplace and seamless way of publishing and updating extensions.\n\nThere is also a fully open source version of the VS Code called [VSCodium](https://vscodium.com/). This version removes some proprietary Microsoft code from the distribution and is analogous to the Google Chrome and Chromium projects.\n\n## VS Code extension\n\nVS Code extension is a JavaScript or TypeScript app that runs in node and has access to the [VS Code Extension API](https://code.visualstudio.com/api). The convenient thing about this architecture is that the extension is like any other node app and has full access to the host machine and network. It can choose its own library for network connection, manipulating file systems, and also for rendering web UI.\n\n## Extension API\n\nThe extension API is implemented in TypeScript; it allows users to manipulate almost every aspect of the editor. After months of using it, I find the design elegant (with the exception of testing, which seems to be an afterthought in many areas of the API).\n\nThe main features of the API are manipulating and searching the files, editing text, creating custom left panels and status bars, debuggers, custom webview tabs, (Jupyter) notebook providers, and more. The API also provides a simple way to communicate with the user via input fields and quick-pick panels, as well as showing output with info, warning, or error messages.\n\n## Extension Marketplace\n\nIf you are familiar with either AppStore or PlayStore, you'll find VS Code has an equivalent store called [Visual Studio Marketplace](https://marketplace.visualstudio.com/search?target=VSCode), and unlike on its older siblings, everything[^4] is for free. Both the easy browsing experience for the user and the ease of use for a developer are differentiators for VS Code.\n\nAs a developer, you set up your [Azure Cloud token](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token) and then run `vsce publish` in your extension folder. That's it, within a few minutes, most of your users[^5] are running the latest and greatest version of your extension. This process greatly reduces the pressure on developers to get everything right before releasing, enabling faster iteration.\n\nThere is also an independent marketplace called [open-vsx](https://open-vsx.org/) used mainly by VSCodium but also by [GitPod](https://docs.gitlab.com/ee/integration/gitpod.html) and others.\n\n## Developing extensions in GitLab\n\nIf you'd like to try and develop your own extension, you can fork the [`gitlab-example-extension`](https://gitlab.com/viktomas/gitlab-example-extension) project. It contains a complete setup for linting, unit and integration testing, and publishing the extension to both [Visual Studio Marketplace](https://marketplace.visualstudio.com/search?target=VSCode) and [open-vsx](https://open-vsx.org/). Thanks to GitLab being a single platform for the whole [DevOps lifecycle](/topics/devops/), you can just push your code changes to GitLab, and CI/CD takes care of everything else. As always, if you find any useful tweaks, please submit an MR because [everyone can contribute](/company/mission/#mission).\n\nYou can see what the VS Code extension API offers in the [official documentation](https://code.visualstudio.com/api). You can then have a look at [extension examples](https://code.visualstudio.com/api/extension-guides/overview) and extend them to make the VS Code editor do almost anything you want.\n\n## Our extension: GitLab Workflow\n\nIn June the [GitLab Workflow extension became officially supported by GitLab](/blog/use-gitlab-with-vscode/). Since then we've done a lot of cleanup work and bug fixes. Recently, we released our first larger feature: [Inserting GitLab project snippets](https://about.gitlab.com/releases/2020/11/22/gitlab-13-6-released/#insert-gitlab-snippets-directly-in-vs-code).\n\nThe primary purpose of the extension is to integrate GitLab features into the editor, so users don't have to leave the editor to perform basic tasks such as read an issue description or create a snippet from the code. The extension is trying to plug in the GitLab features into an existing VS Code Extension API to both minimise the need for custom code and to make the experience as VS Code-like as possible.\n\nThere are several main areas of the VS Code Extension API that we take advantage of:\n\n### Commands\n\n[Commands](https://code.visualstudio.com/api/extension-guides/command) are a versatile concept for triggering actions. The most common way to trigger commands is to use the \u003Ckbd>Cmd\u003C/kbd>+\u003Ckbd>Shift\u003C/kbd>+\u003Ckbd>P\u003C/kbd> Command Palette. But commands can also be triggered from context menus, clicks on buttons, or even programmatically by other code in the extension. The most common example of triggering commands programatically is to call the `vscode.open` command with a URL as a parameter. GitLab workflow does that every time we open the GitLab web page[^6].\n\n![Command Palette](https://about.gitlab.com/images/blogimages/vscode-extension-development-with-gitlab/commands.png){: .shadow.medium.center}\nCommand Palette in GitLab Workflow\n{: .note .text-center}\n\n### Tree View\n\nVS Code uses the [Tree View](https://code.visualstudio.com/api/extension-guides/tree-view) for displaying the left panel. The panel shows the file tree for the project, changed Git files, an outline of the open file, full-text search results, and more. We use this Tree View panel to show lists of issues and merge requests.\n\n![Tree View](https://about.gitlab.com/images/blogimages/vscode-extension-development-with-gitlab/tree-view.png){: .shadow.medium.center}\nTree View in GitLab Workflow\n{: .note .text-center}\n\n### Status bar\n\n[Status bar](https://code.visualstudio.com/api/extension-capabilities/extending-workbench#status-bar-item) is the slim panel at the bottom of the editor. Any extension can add items to it. Extensions such as Git, spell checks, linters, and formatters all add items to the status bar to provide the user with quick feedback.\n\nThe GitLab Workflow extension shows the MR, issue, and pipeline for the current branch. It, for example, allows you to see if your pipeline failed after the last push.\n\n![Status bar](https://about.gitlab.com/images/blogimages/vscode-extension-development-with-gitlab/status-bar.png){: .shadow.medium.center}\nStatus bar in GitLab Workflow\n{: .note .text-center}\n\nAltogether the VS Code API provides a great foundation for bringing GitLab features closer to the editor. The GitLab VS Code extension is an exciting project that **you too can contribute to**. The best place to start is the [GitLab project page](https://gitlab.com/gitlab-org/gitlab-vscode-extension).\n\n[^2]: [17th most popular project on GitHub](https://github.com/search?p=2&q=stars%3A%3E100&s=stars&type=Repositories) at the time of writing (2020-11-20)\n[^3]: GNU Emacs supported Lisp extensions in [1985](https://en.wikipedia.org/wiki/Emacs#GNU_Emacs)\n[^4]: I haven't been able to find a paid extension in the store.\n[^5]: The auto-update feature is on by default in VS Code, but it can be turned off in which case your users are not going to auto-update.\n[^6]: [Using `vscode.open` in the GitLab Workflow](https://gitlab.com/search?utf8=%E2%9C%93&search=vscode.open&group_id=9970&project_id=5261717&scope=&search_code=true&snippets=false&repository_ref=main&nav_source=navbar)\n\n[Cover image](https://art.ljubicapetkovic.com/cc-licensed/) by [Ljubica Petkovic](https://art.ljubicapetkovic.com), licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\n{: .note}\n",[9,807,108],{"slug":3528,"featured":6,"template":696},"vscode-extension-development-with-gitlab","content:en-us:blog:vscode-extension-development-with-gitlab.yml","Vscode Extension Development With Gitlab","en-us/blog/vscode-extension-development-with-gitlab.yml","en-us/blog/vscode-extension-development-with-gitlab",{"_path":3534,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3535,"content":3540,"config":3545,"_id":3547,"_type":13,"title":3548,"_source":15,"_file":3549,"_stem":3550,"_extension":18},"/en-us/blog/vscode-workflow-new-features",{"title":3536,"description":3537,"ogTitle":3536,"ogDescription":3537,"noIndex":6,"ogImage":2757,"ogUrl":3538,"ogSiteName":683,"ogType":684,"canonicalUrls":3538,"schema":3539},"Four new tools for your Visual Studio Code and GitLab tool belt","Learn about new features that can help you review MRs and interact with GitLab","https://about.gitlab.com/blog/vscode-workflow-new-features","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Four new tools for your Visual Studio Code and GitLab tool belt\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tomas Vik\"}],\n        \"datePublished\": \"2021-11-17\",\n      }",{"title":3536,"description":3537,"authors":3541,"heroImage":2757,"date":3542,"body":3543,"category":739,"tags":3544},[2762],"2021-11-17","\n\nIn our [previous post](/blog/mr-reviews-with-vs-code/), we talked about merge request (MR) Reviews. We explained how the GitLab Workflow extension helps you review MRs without leaving VS Code. Since releasing and polishing the MR reviews, we've been working on improvements to the extension. In this post, we will show you how the latest features fit into your workflow.\n\n### Do you have a lot to say? Use a snippet patch!\n\nOn GitLab's web UI there's the \"suggestions\" feature. It's handy for suggesting small changes in the MR review. The VS Code platform doesn't let us recreate the same experience, but the extension offers an alternative: Snippet patches.\n\nSnippet patches are code changes (git patches) of arbitrary size shared as GitLab snippets. Because they don't have a size limit, they are perfect for suggesting changes to multiple files during the MR review.\n\nThe extension has two commands, `Create snippet patch` and `Apply snippet patch`. These commands use `git diff` and `git apply`, respectively, which means people can still apply the snippet patch even if they don't use the GitLab Workflow extension.\n\nIf a suggestion in the comment is a hammer, then a snippet patch is a pneumatic tamping machine. Next time you'll review an MR, and you see a lot of space for improvement, remember the adage: \"A patch is worth a thousand words\".\n\n\u003Ciframe width=\"560\" height=\"315\" src=\"https://www.youtube-nocookie.com/embed/QQxpLoKJULQ\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen>\u003C/iframe>\n\n### What's going on with my pipeline? - Improved CI status display\n\nThe extension always showed the latest CI pipeline status in both the status bar and the sidebar. However, if you tried to gauge your pipeline status, you probably run into one or more surprises. The status was hard to understand. Sometimes it related to a different branch, or it was out of date.\n\nWe've made the pipeline status much more reliable and readable. For starters, you can now see individual jobs and their status in the sidebar. Click on any job, and the extension opens a browser window with the GitLab job page.\n\nWe also improved the consistency of showing the pipeline status. The status bar and sidebar are now in sync and always showing pipeline for the current branch.\n\nWe are excited about the cleaner code. It makes it easier for anyone to contribute functionality. If you'd be interested in giving it a shot, we recommend starting with the [Download artifacts from the latest pipeline](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/106) feature request. \n\n\n![VS Code status bar](https://about.gitlab.com/images/blogimages/2021-11-05-vscode-workflow-new-features/ci-pipeline-panel.png){: .shadow.medium.center}\nVS Code CI Pipeline status overview from GitLab extension.\n{: .note .text-center}\n\n### Make the MR your own - Working with checked out code\n\nTwo recent improvements play well together to make your review more interactive. They help you spend less time on actions that don't directly relate to reviewing code. These improvements let you check out the MR branch and open a local file during a review.\n\n#### Check out the MR branch\n\nYou can checkout any MR locally, as long as it is not coming from a forked project. Right-click the MR in the side tree and select \"Checkout MR Branch\". After the command finishes, you'll have the MR branch checked out in your project. Now you can review and run the code.\n\n\u003Cfigure class=\"video_container\">\n  \u003Cvideo src=\"https://gitlab.com/gitlab-org/gitlab-vscode-extension/uploads/db804234ed4d338dea31a27778dba72e/checkout-mr-branch.mp4\" controls=\"true\" data-setup=\"{}\" data-title=\"checkout-mr-branch\" preload=\"metadata\" width=\"560\">\u003C/video>\n\u003C/figure>\n{: .shadow.medium.center}\n\n#### Open a local file during a review\n\nWhen you look at a changed file in an MR, you can click on a small \"file\" icon in the top-right corner. The extension will open the same file in your local repository.\n\nIf your local branch is different from the MR branch, the local file might not be the same as the MR file.\n\nOpening the local file is useful when you want to explore the surroundings of the file quickly. The VS Code automatically focuses the file in the file tree, which lets you see all the neighbouring files.\n\n\u003Cfigure class=\"video_container\">\n  \u003Cvideo src=\"https://gitlab.com/gitlab-org/gitlab-vscode-extension/uploads/de2839b1ceb1be6c33cd80d7fe72bc6d/open-mr-file.mp4\" controls=\"true\" data-setup=\"{}\" data-title=\"open-mr-file\" preload=\"metadata\" width=\"560\">\u003C/video>\n\u003C/figure>\n{: .shadow.medium.center}\n\n### Commitment problems? Browse repositories without checking them out\n\nAt GitLab, we've got some large repositories. The largest, which all GitLabbers use daily, is [www-gitlab-com](https://gitlab.com/gitlab-com/www-gitlab-com), the website you see when you visit `about.gitlab.com`. This 6 GB colossus takes several minutes to check out.\n\nExploring this repository is a perfect use case for our latest feature: Remote Repositories, [contributed by Ethan Reesor](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/321), a community member.\n\nRun the `GitLab: Open Remote Repository` command, pick which project and branch you want to use, and _voilà_.  The extension opens the repository in your local workspace, but it doesn't store data on your local machine.\n\nRemote repositories are useful when you want to browse a repository for a reference but don't plan to change the code.\n\nThis is the first iteration, and it's got some limitations - you can't use full-text search, fuzzy file navigation, and the files are read-only. It's useful nonetheless.\n\n\u003Ciframe width=\"560\" height=\"315\" src=\"https://www.youtube-nocookie.com/embed/p4GTVx_Nd2s\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen>\u003C/iframe>\n\n### Thank you community!\n\nMost of the features introduced in this post are either implemented or suggested by a community member. Ahmed Mohamadeen [suggested](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/390) opening local file during MR review, Musisimaru [created initial implementation](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/203) of checking out MR branch, and Ethan Reesor [implemented](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/321) remote repositories.\n\n\nIf you'd like to shape the future of the GitLab Workflow VS Code extension, you can create issues in [our issue tracker](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues), or look for [issues where we accept MRs](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues?label_name%5B%5D=Accepting+merge+requests). Our [CONTRIBUTING](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/CONTRIBUTING.md) guide is an excellent place to start.\n\nCover image by [Ljubica Petkovic](https://ljubicapetkovic.com), licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)\n{: .note}\n",[9,807,851],{"slug":3546,"featured":6,"template":696},"vscode-workflow-new-features","content:en-us:blog:vscode-workflow-new-features.yml","Vscode Workflow New Features","en-us/blog/vscode-workflow-new-features.yml","en-us/blog/vscode-workflow-new-features",{"_path":3552,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3553,"content":3558,"config":3563,"_id":3565,"_type":13,"title":3566,"_source":15,"_file":3567,"_stem":3568,"_extension":18},"/en-us/blog/vscode-workflows-for-working-with-gitlab",{"title":3554,"description":3555,"ogTitle":3554,"ogDescription":3555,"noIndex":6,"ogImage":2757,"ogUrl":3556,"ogSiteName":683,"ogType":684,"canonicalUrls":3556,"schema":3557},"Visual Studio code editor: Eight tips for using GitLab VS Code","Learn how to use the Visual Studio code editor more efficiently and meet some of the GitLab contributors that made these new features happen.","https://about.gitlab.com/blog/vscode-workflows-for-working-with-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Visual Studio code editor: Eight tips for using GitLab VS Code\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Tomas Vik\"}],\n        \"datePublished\": \"2021-05-20\",\n      }",{"title":3554,"description":3555,"authors":3559,"heroImage":2757,"date":3560,"body":3561,"category":739,"tags":3562},[2762],"2021-05-20","\n\nAs a software engineer, I spend a significant portion of my day in the Visual Studio code editor. Since I started maintaining the officially supported [GitLab VS Code extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow), I've developed a few tricks that make me a productive GitLab user. Below, I share eight tips that make my work more efficient and productive, while also introducing you to some of the GitLab contributors who made this tooling happen.\n\n## What is Visual Studio Code?\n[Visual Studio Code](https://en.wikipedia.org/wiki/Visual_Studio_Code), developed by Microsoft, lets a user debug source code in various languages from the editor. It is also used for syntax highlighting, intelligent code completion, code refactoring, embedded Git and autocomplete. VS Code, as it is commonly known, can be launched or attached to running apps.\n\nIt is designed for Windows, Linux, and MacOS. VS Code can be used with several programming languages such as Java, JavaScript, Node.js, Python, C++ and Fortran. Support for additional languages is provided by freely available extensions on the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).\n\nBelow are eight tips for using GitLab VS Code.\n\n### How to clone any GitLab project\n\nGitLab contributor [Felix Haase](https://gitlab.com/haasef) recently [implemented a feature that lets you clone any GitLab project where you are a member](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/172). To clone the project, use the official `Git: Clone` command and select your GitLab instance. Use the `Git: Clone` command by selecting the command from the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).\n\nThis feature can save you time if you already know the name of the project you want to clone.\n\n![VS Code clone dialogue](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/clone.png){: .shadow.medium.center}\nVS Code lets you filter which project to clone.\n{: .note .text-center}\n\n### How to view MRs and issues\n\nIt is easy to look through issues and MRs that you created, are assigned to, or are reviewing using GitLab. The lesser-known feature of the GitLab Workflow extension is [custom queries](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/docs/user/custom-queries.md). Custom search queries allow you to refine the search expressions for issues and MRs that appear in the VS Code side panel. You can apply all the advanced search terms you are used to from the GitLab web search: Labels, full-text search expression, milestones, authors, assignees, and more.\n\n![GitLab extension sidebar](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/issues-and-mrs.png){: .shadow.medium.center}\nSee your issues and MRs in the VS Code sidebar.\n{: .note .text-center}\n\nAnother option is [reviewing the MRs in VS Code](/blog/mr-reviews-with-vs-code/). The final functionality that is missing in MR review is [creating new comments on the MR diff](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/342), which we plan to ship by July 2021.\n\n### How to create an MR with two clicks\n\nIf you use the `git` command in a terminal, you might have noticed that pushing your branch to GitLab produces the following output:\n\n```txt\nremote: To create a merge request for my-new-branch, visit:\nremote: https://gitlab-instance.com/my-group/my-project/merge_requests/new?merge_request%5Bsource_branch%5D=my-new-branch\n```\n\nAfter clicking the link, the terminal will open your browser on a new MR page where you can create an MR from the branch you just pushed.\n\nWhen I started pushing my branches through VS Code, I missed this feature. To the point that I searched through the VS Code Git Extension logs to find the create MR link (command `Git: Show Git Output`).\n\nLuckily, GitLab contributor [Jonas Tobias Hopusch](https://gitlab.com/jotoho) implemented a [status bar button](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/155) that lets you create MRs just as easily.\n\nTo create an MR from your changes, push them to your remote repository (the cloud icon next to the branch name) and then click on the `GitLab: Create MR.` button.\n\n![VS Code status bar](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/status-bar-create-mr.png){: .shadow.medium.center}\nVS Code status bar with buttons from GitLab extension.\n{: .note .text-center}\n\n### How to configure your GitLab CI\n\nThe GitLab extension helps you edit your `.gitlab-ci.yml` configuration file in two ways: Autocompleting environment variables and validating the configuration.\n\nThanks to [Kev's](https://gitlab.com/KevSlashNull) fantastic [contribution](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/140), you can [use CI](/solutions/continuous-integration/) variable autocompletion anywhere in your `.gitlab-ci.yml`. The hints even include variable descriptions and explain supported GitLab versions.\n\n![CI variables autocomlete dialogue](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/ci-autocomplete.png){: .shadow.medium.center}\nCI variables autocomplete dialogue.\n{: .note .text-center}\n\nWhen you finish writing your `.gitlab-ci.yml` CI configuration, you can use the `GitLab: Validate GitLab CI config` command to surface any problems before committing the CI config to your repository.\n\n### How to create and paste project snippets\n\nIs there a piece of text that you and your teammates often use? Maybe it is a license header for a file or a test scenario template. You can use GitLab snippets in combination with Visual studio code editor to save you a few keystrokes.\n\nFor example, you can create a [test file snippet](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/snippets/2110322) with the `GitLab: Create snippet` command and then paste it into every new test file you create with the `GitLab: Insert snippet` command.\n\n![Paste Snippet dialogue](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/paste-snippet.png){: .shadow.medium.center}\nPaste Snippet dialogue.\n{: .note .text-center}\n\nI mostly use snippets when I want to share a big blob of text. I select the text and then create the snippet with the `GitLab: Create snippet` command.\n\n### How to copy web URL for a project file\n\nMost of the [communication at GitLab happens asynchronously](https://handbook.gitlab.com/handbook/values/#bias-towards-asynchronous-communication). So instead of being able to show your colleague an open file in your editor, you'll need to be able to create a textual pointer to the file.\n\nA straightforward way to do that is to use the `GitLab: Copy link to active file on GitLab` command, which will copy the web URL of the open file into your clipboard. It even includes the line number or a range of lines based on your cursor or selection in the Visual studio code editor.\n\nYou might also consider using the `GitLens: Copy Remote File URL`, which even includes the commit SHA in the URL, making it a permalink. The permalink will always point to the same version of the file regardless of further commits to your branch. We'll look at the GitLens extension in tip number 7 a bit later on.\n\nFor the GitLab Enterprise/Community Edition you can use:\n\"gitweblinks.gitLabEnterprise\": [\n    {\n        \"http\": \"https://local-gitlab\",\n        \"ssh\": \"git@local-gitlab\"\n    }\n]\n\n#### What to do if VS Code source control is not working\n\nA `SourceControl` is the entity responsible for populating the [Source Control model](https://code.visualstudio.com/api/extension-guides/scm-provider) with resource states, instances of `SourceControlResourceState`. Resource states are organized in groups, instances of `SourceControlResourceGroup`.\n\nLinking to issues in source code is a normal part of the VS Code workflow, especially when there's some logic that's difficult to understand or when there's a //TODO comment that needs action. [Users report experiencing issues](https://stackoverflow.com/questions/60232215/visual-studio-code-source-control-not-showing-changes) with changes in the file not appearing to the source code, unless inputted manually.\n\nOne user offered a 7-step solution that worked for them. Another said that all they had to do was disable and then reenable the build in Git extension, which fixed it. Yet another said they went to their “code” folder where they keep all their repos, right-clicked on the folder containing the repo they wanted and opening that folder with VS code.\n\nAn often-used approach to look at issues is to pick one to work on, create a branch to work in, make some commits, then merge your changes back into the main or default branch with a pull request. You can do that from the new Issues view.\n\n#### GitLab Workflow extensions for VS Code\n\nThe [GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) integrates GitLab with VS Code. You can decrease context switching and do more day-to-day tasks in VS Code, such as:\n\n- [View issues](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#browse-issues-review-mrs).\n- Run [common commands](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#commands) from the Visual Studio Code [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).\n- Create and [review](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#merge-request-reviews) merge requests directly from Visual Studio Code.\n- [Validate](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#validate-gitlab-ci-configuration) your GitLab CI configuration.\n- [View the status](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#information-about-your-branch-pipelines-mr-closing-issue) of your current pipeline.\n- [Create](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#create-snippet) and paste snippets to, and from, your editor.\n- [Browse repositories](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#browse-a-repository-without-cloning) without cloning them\n\nDownload the extension from the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow). Then you can configure:\n\n- [Features to display or hide](https://gitlab.com/gitlab-org/gitlab-vscode-extension#extension-settings).\n- [Self-signed certificate](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#self-signed-certificates) information\n\nReport any issues, bugs, or feature requests in the [gitlab-vscode-extension issue queue](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues).\n\nThis extension supports GitLab Version 13.0 and later. To find your GitLab version, visit [help](https://gitlab.com/help).\n\nYou can also see pipeline status, open MR and closing issue links in the status bar. The pipeline status is updated automatically so you don’t need to open GitLab to see your pipeline status.\n\nWithin the marketplace you can also use the command palette to run the commands and create a GitLab personal access token (required) and assign it to the extension.\n\nYou can also set set the token in an environment variable and learn how to change the VS Code settings. There are instructions for several other in-depth features as well.\n\n## How GitLens simplifies working with VS Code editor\n\nUp until now, the tips were centered around the [GitLab Workflow extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow), but there is a fantastic extension that's improving VS Code git integration regardless of where you host your repository: [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens).\n\n### Walking file history\n\nGitLens makes it easy to browse the history of changes to the current file. Each versioned file will have three new editor icons, which provides quick access to all previous revisions of the file. The middle button seen in the image below provides series of actions on the current version (e.g., opening the commit in GitLab web).\n\n![GitLens history browsing buttons](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/gitlens-history.png){: .shadow.medium.center}\nGitLens history browsing buttons\n{: .note .text-center}\n\n### How to compare current HEAD against branch or tag\n\nOne of my habits was inspecting `git diff` between my feature branch and the main branch before creating an MR. More often than not, I forgot to write a test or remove some pesky `console.log()`.\n\nGitLens adds multiple sections to your [\"Source Control\" tab](https://code.visualstudio.com/docs/editor/versioncontrol#_scm-providers). For each branch, tag, and commit, click a \"Compare\" icon which will show you changes between your current HEAD and the reference. Seeing the local diff is great for previewing changes before pushing the new branch to the remote.\n\n![GitLens - compare with branch](https://about.gitlab.com/images/blogimages/vscode-workflows-for-working-with-gitlab/gitlens-compare.png){: .shadow.medium.center}\nHow to compare with a branch using GitLens.\n{: .note .text-center}\n\n## Everyone can contribute\n\nNew features and fixes to the GitLab Visual Studio Code editor extension are added every month. If you find any issues or have a feature request, please go to our [GitLab VSCode issues tracker](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues) and if your request isn't already present in the tracker, create one. Everyone can contribute to GitLab, and we welcome your ideas on how to improve our Visual Studio Code editor.\n\n## Read more on Visual Studio and GitLab:\n\n- [Four new tools for your Visual Studio Code and GitLab tool belt](/blog/vscode-workflow-new-features/)\n\n- [VS Code extension development with GitLab](/blog/vscode-extension-development-with-gitlab/)\n\n- [How to do GitLab merge request reviews in VS Code](/blog/mr-reviews-with-vs-code/)\n\n- [How we created a GitLab Workflow Extension for VS Code](/blog/use-gitlab-with-vscode/)\n\n",[9,807],{"slug":3564,"featured":6,"template":696},"vscode-workflows-for-working-with-gitlab","content:en-us:blog:vscode-workflows-for-working-with-gitlab.yml","Vscode Workflows For Working With Gitlab","en-us/blog/vscode-workflows-for-working-with-gitlab.yml","en-us/blog/vscode-workflows-for-working-with-gitlab",{"_path":3570,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3571,"content":3577,"config":3583,"_id":3585,"_type":13,"title":3586,"_source":15,"_file":3587,"_stem":3588,"_extension":18},"/en-us/blog/what-the-solarwinds-attack-can-teach-us-about-devsecops",{"title":3572,"description":3573,"ogTitle":3572,"ogDescription":3573,"noIndex":6,"ogImage":3574,"ogUrl":3575,"ogSiteName":683,"ogType":684,"canonicalUrls":3575,"schema":3576},"How DevSecOps can protect businesses from future supply chain attacks","Learn how GitLab's all-in-one DevSecOps solution can help businesses keep their supply chains secure.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749669522/Blog/Hero%20Images/solarpanels.jpg","https://about.gitlab.com/blog/what-the-solarwinds-attack-can-teach-us-about-devsecops","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How DevSecOps can protect businesses from future supply chain attacks\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Pedro Fortuna\"},{\"@type\":\"Person\",\"name\":\"Sam Kerr\"}],\n        \"datePublished\": \"2021-08-18\",\n      }",{"title":3572,"description":3573,"authors":3578,"heroImage":3574,"date":3580,"body":3581,"category":716,"tags":3582},[3579,3468],"Pedro Fortuna","2021-08-18","\n\nOne of the cybersecurity keywords for 2021 will undoubtedly be \"software supply chain attacks\". For decades, we've seen a global move toward connected systems and highly complex supply chains. Today these supply chains are under attack, with malicious actors jeopardizing the sensitive data of millions of users through attacks on the public and private sectors.\n\nAfter public and federal entities were targeted in some high-profile supply chain attacks, the United States government released an [executive order](https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/) with plans to improve the security posture of the nation when it comes to software supply chains. The UK issued a similar [call for views on cybersecurity in supply chains](https://www.gov.uk/government/publications/call-for-views-on-supply-chain-cyber-security/call-for-views-on-cyber-security-in-supply-chains-and-managed-service-providers) around the same time.\n\nSupply chain security became a global priority after the SolarWinds attack, reminding businesses and institutions of the extensive damages caused by these vulnerabilities.\n\n## A brief summary of the SolarWinds incident\n\nBetween April and June 2020, malicious actors exploited vulnerabilities in the Solarwinds Orion Platform and inserted a backdoor – allowing attackers to deploy multiple payloads like spyware, and leak confidential data from companies that used the platform, including some U.S. federal entities.\n\n[Current estimates are 18,000 organizations](https://www.zdnet.com/article/sec-filings-solarwinds-says-18000-customers-are-impacted-by-recent-hack/) were impacted by the [SolarWinds attack](/blog/devops-platform-supply-chain-attacks/), but there's a lot we still don't know about the magnitude of the attack. One thing we know for certain is the number of successful supply chain attacks is increasing, and businesses need more effective security measures to protect their software supply chain.\n\n[Web-based supply chain attacks](https://jscrambler.com/resources/white-papers/supply-chain-attacks?utm_source=about.gitlab.com&utm_medium=referral&utm_campaign=key-lessons-solarwinds) is a particularly concerning vector of attack. The number of web-based attacks have grown over the past few years and provide attackers with a lower barrier to entry when it comes to getting their hands on valuable user data.\n\n## An emerging attack vector: Web supply chain attacks\n\nToday, the average website runs [35 distinct third-party scripts](https://www.reflectiz.com/blog/looking-at-the-figures-of-third-party-application-security-on-websites-part-1/). Plus, it's estimated that only 3% of the source code of the actual website is written by the team developing the website, while the remaining 97% comes from third-party libraries used during development. Oftentimes, several pieces of third-party code will be coming from companies or individuals with fewer resources dedicated to security, which puts the typical website on precarious footing with an extremely high level of exposure to third-party risk.\n\nThe dependence on third-party code creates a significant opportunity for attackers by allowing them to breach a third-party code supplier and inject a malicious payload into the source code of the third-party script. The compromised source code will then make its way down the web supply chain, reaching hundreds or thousands of different websites.\n\nHere's where things get even more complicated. In the context of the web, every website script has the same privileges, whether it is a first or third party. As such, a compromised third-party script will be able to harvest any user input, add extra code, hijack events, and fully modify the behavior of the web page. As a result, web supply chain attacks are now being used to leak sensitive user data, such as user credentials, credit card numbers, and other types of PII/PHI that are then sold on underground marketplaces.\n\nA prime example of a web supply chain attack occurred in April 2021, when Codecov, a popular code coverage tool, was breached. The attackers modified the source code of the tool and leaked sensitive data, including dev credentials, tokens, and keys. At the time, more than 29,000 companies were potentially exposed to the attack and some companies reported being breached by [Magecart web skimmers](https://www.bleepingcomputer.com/news/security/e-commerce-giant-suffers-major-data-breach-in-codecov-incident/) or [having their source code exposed to attackers](https://www.bleepingcomputer.com/news/security/codecov-hackers-gained-access-to-mondaycom-source-code/) in the weeks that followed.\n\n## Web supply chain security from within DevSecOps\n\n[DevSecOps](/topics/devsecops/) is a key resource in the global push toward more secure supply chains.\n\nThe whole premise of DevSecOps is to ingrain security controls throughout the entire software development lifecycle. Companies must adopt a multi-layered, defense-in-depth posture to reduce the risk of web supply chain attacks, which is ideally integrated into their DevSecOps workflow. Adopting DevSecOps practices will provide businesses with much-needed **visibility** and **control** over their website supply chain.\n\nThe [GitLab DevOps platform](/solutions/devops-platform/) provides the necessary layers of protection for improved web supply chain security in a single application.\n\nFirst, GitLab automates the process of **scanning the application** using [several tools](/stages-devops-lifecycle/secure/) and techniques, such as SAST, DAST, dependency, container scanning, secrets detection, and fuzz testing (including API fuzzing). This robust scanning increases visibility over potentially insecure third-party code, while also giving full visibility into all code changes before they are pushed to the main branch.\n\nWhile vulnerability scanning is an important step to minimize exposure to web supply chain attacks, the source code of the application is still exposed at the client-side and can be reverse-engineered or tampered with by attackers during the recon stage of the attack. To address this risk, GitLab provides **source code protection** through an [integration with Jscrambler](/blog/how-to-protect-your-source-code-with-gitlab-and-jscrambler/). [Jscrambler](https://jscrambler.com/?utm_source=about.gitlab.com&utm_medium=referral&utm_campaign=key-lessons-solarwinds) adds key security layers such as obfuscation, code locks, and runtime protection, which thwart static and dynamic code analysis and locks out attackers.\n\nGitLab's integration with Jscrambler also provides access to additional security layers that bring the required **visibility** and **control** over web supply chain attacks at runtime. One of these key layers is an [inventory of all the scripts running on the website](https://jscrambler.com/free-website-inventory-report?utm_source=about.gitlab.com&utm_medium=referral&utm_campaign=key-lessons-solarwinds) and network requests, providing real-time alerts whenever malicious behavior is detected at the client-side. When coupled with **Jscrambler's powerful rules engine**, GitLab provides a [zero-trust](/blog/tags.html#zero-trust) approach to website security, blocking any malicious behavior originating from third-party code.\n\nFinally, being a true end-to-end DevOps platform, GitLab has built-in security features that simplify the process of continuous iteration. This is key for any defense-in-depth strategy: Providing enough simplicity to enable security within any organization.\n\n## Supply chain security becomes new global priority\n\nThere is no question that the SolarWinds supply chain attack is one for the ages, prompting a necessary global push for improved supply chain cybersecurity and highlighted the importance of protecting the web supply chain.\n\nReducing exposure to web supply chain attacks requires a defense-in-depth approach that should be built into companies' DevSecOps workflows. GitLab's end-to-end DevOps platform provides multiple layers of security to address this risk, namely through integration partners such as Jscrambler.\n\nAs we see more companies try to improve their security posture by using the right tools to mitigate web supply chain attacks, I'm confident that they will soon outpace attackers and succeed in keeping billions of users safe.\n\n_Pedro Fortuna is the founder of [Jscrambler](https://jscrambler.com/?utm_source=about.gitlab.com&utm_medium=referral&utm_campaign=key-lessons-solarwinds)._\n\n[Cover image](https://unsplash.com/photos/d7FbDJkJSFw) by [Markus Spiske](https://unsplash.com/@markusspiske?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unsplash\n{: .note}\n",[851,716,9],{"slug":3584,"featured":6,"template":696},"what-the-solarwinds-attack-can-teach-us-about-devsecops","content:en-us:blog:what-the-solarwinds-attack-can-teach-us-about-devsecops.yml","What The Solarwinds Attack Can Teach Us About Devsecops","en-us/blog/what-the-solarwinds-attack-can-teach-us-about-devsecops.yml","en-us/blog/what-the-solarwinds-attack-can-teach-us-about-devsecops",{"_path":3590,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3591,"content":3597,"config":3602,"_id":3604,"_type":13,"title":3605,"_source":15,"_file":3606,"_stem":3607,"_extension":18},"/en-us/blog/whitesource-for-dependency-scanning",{"title":3592,"description":3593,"ogTitle":3592,"ogDescription":3593,"noIndex":6,"ogImage":3594,"ogUrl":3595,"ogSiteName":683,"ogType":684,"canonicalUrls":3595,"schema":3596},"How to secure your dependencies with GitLab and WhiteSource","We walk you through how to configure WhiteSource in your GitLab instance to enhance your application security.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663445/Blog/Hero%20Images/snowymtns.jpg","https://about.gitlab.com/blog/whitesource-for-dependency-scanning","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"How to secure your dependencies with GitLab and WhiteSource\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Fernando Diaz\"}],\n        \"datePublished\": \"2020-08-10\",\n      }",{"title":3592,"description":3593,"authors":3598,"heroImage":3594,"date":3599,"body":3600,"category":716,"tags":3601},[1220],"2020-08-10","GitLab's WhiteSouce integration empowers developers to enhance application\nsecurity\n\ndirectly within the GitLab UI. The integration provides dependency scanning\nwith\n\nin-depth analysis, along with actionable insights, and auto-remediation.\nWhiteSource for\n\nGitLab enhances your team's productivity, security, and compliance.\n\n\n[Rhys Arkins](https://twitter.com/rarkins?lang=en), Product Director at\nWhiteSource, and I hosted a webinar on \"[Harnessing development to scale\nAppSec](/webcast/scalable-secure-ci/)\"\n\nshowcasing the features of GitLab's WhiteSource integration for open source\ndependency scanning.\n\n\n\u003C!-- blank line -->\n\n\u003Cfigure class=\"video_container\">\n\n\u003Ciframe src=\"https://www.youtube-nocookie.com/embed/yJpE_ACt9og\"\nframeborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\n\u003C/figure>\n\n\u003C!-- blank line -->\n\n\nThis blog post will guide you through setting up WhiteSource in your private\nGitLab instance\n\nand show you how the integration with WhiteSource enhances your\napplication's security within GitLab.\n\n\n## Installing the WhiteSource integration\n\n\nFirst, let's go over how to install the WhiteSource integration. In this\nsection, I will review how to\n\nset up GitLab service credentials, generate a WhiteSource configuration,\n\nbuild WhiteSource containers, and how to run them in a Kubernetes cluster.\n\n\n### Requirements for WhiteSource integration\n\n\nBut first, the WhiteSource integration requires that you have the following\nsetup:\n\n\n- [GitLab on-prem instance](/pricing/#self-managed): The GitLab instance\nwhere the WhiteSource integration will run.\n\n- [WhiteSource\naccount](https://www.whitesourcesoftware.com/whitesource-pricing/): Provides\naccess to the WhiteSource integration.\n\n- [Kubernetes cluster](/solutions/kubernetes/): Deploys the WhiteSource\ncontainers.\n\n\n### Create GitLab service credentials\n\n\nThe next step is to create GitLab service credentials. This can be\naccomplished in three simple steps:\n\n\n- In your GitLab instance, go to `Admin Area > System Hooks` and create a\nsystem hook as follows:\n    - **URL:** `https://whitesource.INGRESS_URL.com/payload`\n    - **Secret Token:** Make up a token, you can use `openssl rand -base64 12`\n    - **Trigger:** All except `Tag push events`\n    - **Enable SSL Verification:** `Yes`\n\n  Note: Make sure you save the secret token for use in the next section.\n- Create a user named `@whitesource`, with a developer role. An email is not\nrequired.\n\n- As the `@whitesource` user, go to `Settings > Access tokens` and create a\npersonal access token:\n    - **Name:** `WhiteSourceToken`\n    - **Scopes:** `all`\n- Remember to save the access token for use in the next section.\n\n\n### Generate the WhiteSource configuration\n\n\nNext, we generate the WhiteSource configuration, which is used to configure\nthe WhiteSource integration containers.\n\nThis can be done in a few simple steps:\n\n\n- Login to\n[WhiteSource](https://saas.whitesourcesoftware.com/Wss/WSS.html#!login) and\nclick on\n\nthe `Integrate` tab.\n\n\n![whitesource webpage\nview](https://about.gitlab.com/images/whitesource-integration/whitesource_webpage_view.png)\n\nWhiteSource mainpage\n\n{: .note.text-center}\n\n\n- Expand the `WhiteSource for GitLab server` bar and fill the following:\n    - **GitLab Server API URL:** `https://GITLAB_SERVER_URL/api/v4`\n    - **GitLab Webhook URL:** `https://whitesource.INGRESS_URL.com/payload`\n    - **GitLab Webhook secret:** Use the same secret generated in GitLab credentials section\n    - **GitLab personal access token:** `@whitesource` user access token\n\n![whitesource integration\nview](https://about.gitlab.com/images/whitesource-integration/whitesource_integration_setup.png)\n\nWhiteSource integrations page\n\n{: .note.text-center}\n\n\n- Press `Get Activation Key` and copy the generated key\n\n- Open the\n[wss-configurator](https://gitlab.com/fjdiaz/whitesource-helm/-/blob/master/whitesource/wss-configuration/index.html)\nwith your browser\n\n- Select `Export` from the menu, and select the\n[prop.json](https://gitlab.com/fjdiaz/whitesource-helm/-/blob/master/whitesource/wss-configuration/config/prop.json)\n\n- Click on the `General` tab\n\n- Paste the generated key and click `Export` to save a new `prop.json` file\n\n\n### Build the WhiteSource containers\n\n\n- Move the generated prop.json from the previous section to\n[wss-gls-app](https://gitlab.com/fjdiaz/whitesource-helm/-/tree/master/whitesource/wss-gls-app/docker/conf),\n[wss-remediate](https://gitlab.com/fjdiaz/whitesource-helm/-/tree/master/whitesource/wss-remediate/docker/src),\nand\n[wss-scanner](https://gitlab.com/fjdiaz/whitesource-helm/-/tree/master/whitesource/wss-scanner/docker/conf).\n\n- Build and push the Docker containers:\n\n\n```bash\n\n$ docker build -t wss-gls-app:19.12.2 whitesource/wss-gls-app/docker\n\n$ docker push wss-gls-app:19.12.2\n\n\n$ docker build -t wss-scanner:19.12.1.2 whitesource/wss-scanner/docker\n\n$ docker push wss-scanner:19.12.1.2\n\n\n$ docker build -t wss-remediate:19.12.2 whitesource/wss-remediate/docker\n\n$ docker push wss-remediate:19.12.2\n\n```\n\n\n### Running the WhiteSource containers\n\n\nGitLab provides native Kubernetes cluster integration. This means that\nGitLab allows you\n\nto deploy software from [GitLab CI/CD](/topics/ci-cd/) pipelines directly to\nyour Kubernetes cluster.\n\n\nWhiteSource containers can be deployed and managed within the same\nKubernetes cluster\n\nused to deploy your application, all by running a simple Helm commands.\n\n\n- Download the WhiteSource [Helm\nchart](https://gitlab.com/fjdiaz/whitesource-helm)\n\n- Edit\n[values.yaml](https://gitlab.com/fjdiaz/whitesource-helm/-/blob/master/helm/whitesource/values.yaml)\n\n- In vaules.yaml set `whitesource.ingress` to\n**https://whitesource.INGRESS_URL.com**\n\n\nYou can get the INGRESS_URL from your Kubernetes cluster settings\n\n\n![ingress url\nlocation](https://about.gitlab.com/images/whitesource-integration/base_domain.png)\n\nIngress URL location\n\n{: .note.text-center}\n\n\n- Make sure Ingress is installed.\n\n\n![ingress\ninstallation](https://about.gitlab.com/images/whitesource-integration/ingress_installation.png)\n\nInstalling Ingress\n\n{: .note.text-center}\n\n\n- Install [Helm](https://helm.sh/docs/intro/install/)\n\n- Deploy WhiteSource with Helm template:\n\n\n```bash\n\nhelm upgrade -f helm/whitesource/values.yaml --install whitesource-gitlab\n./helm/whitesource\n\n```\n\n\n## Using WhiteSource\n\n\nOnce the WhiteSource plugin has been installed we can add the `@whitesource`\nuser to the repositories\n\nwe wish to scan. A merge request (MR) with the `.whitesource` file will be\ngenerated automatically.\n\n\nWhiteSource will now scan your repository and generate issues for all the\nvulnerabilities discovered on the main (master)\n\nbranch. These issues will provide detailed information on the vulnerability\nas well as how to resolve it. Some issues\n\ncan even be auto-remediated.\n\n\n![whitesource issue\nview](https://about.gitlab.com/images/whitesource-integration/whitesource_issues.png)\n\nWhiteSource vulnerability issues\n\n{: .note.text-center}\n\n\nEach time a new MR is pushed, a WhiteSource scan will run, and provide a\ndetailed output.\n\n\n![whitesource merge request\nview](https://about.gitlab.com/images/whitesource-integration/whitesource_merge_requests.png)\n\nWhiteSource MR scanning\n\n{: .note.text-center}\n\n\nEach link provided by WhiteSource shows detailed information on the\nvulnerabilities the scan detected:\n\n\n![whitesource web\nlinks](https://about.gitlab.com/images/whitesource-integration/whitesource_advanced_issues.png)\n\nWhiteSource vulnerability information\n\n{: .note.text-center}\n\n\nWhiteSource can be integrated into the [GitLab Security\nDashboard](https://docs.gitlab.com/ee/user/application_security/security_dashboard/)\nso that your security team can manage the\n\nstatus of these vulnerabilites. Access to the Security Dashboard requires a\n[GitLab Ultimate account](/pricing/ultimate/).\n\n\nFor integrating WhiteSource to the Security Dashboard, add the following to\nthe CI.yaml:\n\n\n```\n\nwhitesource-security-publisher:\n  image: openjdk:8-jdk\n  when: manual\n  script:\n    - curl \"{{WEBHOOK_URL}}/securityReport?repoId=$CI_PROJECT_ID&repoName=$CI_PROJECT_NAME&ownerName=$CI_PROJECT_NAMESPACE&branchName=$CI_COMMIT_REF_NAME&defaultBranchName=$CI_DEFAULT_BRANCH&commitId=$CI_COMMIT_SHA\" -o gl-dependency-scanning-report-ws.json\n  artifacts:\n    paths:\n      - gl-dependency-scanning-report-ws.json\n    reports:\n      dependency_scanning:\n        - gl-dependency-scanning-report-ws.json\n    expire_in: 30 days\n```\n\n\nFor more details on the integration checkout [WhiteSource for\nGitLab](https://whitesource.atlassian.net/wiki/spaces/WD/pages/806191420/WhiteSource+for+GitLab).\n\nLearn more at [DevSecOps](/solutions/security-compliance/) and checkout the [Secure\ndirection page](/direction/secure/) for more\n\ninformation on the upcoming features and integrations.\n\n\n## Learn more about application security at GitLab\n\n\n- [How application security engineers can use GitLab to secure their\nprojects](/blog/secure-stage-for-appsec/)\n\n- [Get better container security with GitLab: 4 real-world\nexamples](/blog/container-security-in-gitlab/)\n\n- [How to capitalize on GitLab Security tools with external\nCI](https://docs.gitlab.com/ee/integration/jenkins.html)\n\n\nCover image by [Alexandra\nAvelar](https://unsplash.com/@alexandramunozavelar) on\n[Unsplash](https://unsplash.com/s/photos/snow-capped-mountains)\n\n{: .note}\n",[108,716,9,1988,1040],{"slug":3603,"featured":6,"template":696},"whitesource-for-dependency-scanning","content:en-us:blog:whitesource-for-dependency-scanning.yml","Whitesource For Dependency Scanning","en-us/blog/whitesource-for-dependency-scanning.yml","en-us/blog/whitesource-for-dependency-scanning",{"_path":3609,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3610,"content":3616,"config":3621,"_id":3623,"_type":13,"title":3624,"_source":15,"_file":3625,"_stem":3626,"_extension":18},"/en-us/blog/whitesource-gitlab-security-integration",{"title":3611,"description":3612,"ogTitle":3611,"ogDescription":3612,"noIndex":6,"ogImage":3613,"ogUrl":3614,"ogSiteName":683,"ogType":684,"canonicalUrls":3614,"schema":3615},"GitLab and WhiteSource: the easy way to secure your open source code","How we integrated with GitLab's security dashboards to make it easier to secure your open source code earlier in the dev lifecycle","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681016/Blog/Hero%20Images/gitlab-whitesource.png","https://about.gitlab.com/blog/whitesource-gitlab-security-integration","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"GitLab and WhiteSource: the easy way to secure your open source code\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Guy Bar-Gil, Product Manager at WhiteSource\"}],\n        \"datePublished\": \"2020-01-14\",\n      }",{"title":3611,"description":3612,"authors":3617,"heroImage":3613,"date":3129,"body":3619,"category":691,"tags":3620},[3618],"Guy Bar-Gil, Product Manager at WhiteSource","\n\nDevelopment teams have gotten used to relying on open source components to build powerful innovative software at a neck-breaking pace. The speed is certainly accelerating, but what about the security of our applications? Unfortunately, this is often treated as an afterthought, which is not surprising since security has traditionally been seen as a tiresome and time-consuming task that comes after the development stage and slows down production.\n\nIn an attempt to keep security up to speed with the pace of development, organizations are realizing that it can no longer be introduced in the later stages of the software development lifecycle (SDLC). Instead, fusing security into the earlier stages of the SDLC can enable development teams to detect and remediate vulnerabilities when they are significantly easier, quicker and cheaper to fix.\n\nBut how can we integrate security into our development process without adding more work and slowing down our pace?\n\nWell that's where GitLab and WhiteSource come in.\n\n## Secure open source code while in your GitLab UI\n\nWhiteSource has leveraged GitLab's Open Core to empower developers with the tools needed to find and fix open source vulnerabilities. The integration provides developer-focused security tools that operate within the native coding environment and within the [GitLab CI/CD pipeline](/topics/ci-cd/), allowing them to continuously address security without having to compromise on agility.\n\nWith the newest integration to GitLab Ultimate, developers gain richer insight into vulnerable open source components discovered by WhiteSource right in the merge request pipeline. At the same time security pros can see this in the GitLab Security Dashboard alongside scan results from SAST, DAST, containers, and license compliance. WhiteSource supports many more languages and provides richer dependency insight than GitLab alone. With GitLab, both security users and developers can see new, unresolved vulnerabilities for every code commit, with actionable insights on vulnerable open source libraries as well as all of their dependencies as soon as they are added to their projects.\n\n## Ensuring a secure future, together\n\nWith our partnership, we want to ensure that developers are able to harness the power of open source to create innovative products without having to compromise on security, speed, or agility.\n\n## So, what's next?\n\nVery soon, we'll be sharing a blog post with a step-by-step guide on how to integrate WhiteSource into your native GitLab environment. The best tips and tricks will be included to ensure you'll be able to secure your open source components freely and fearlessly.\n",[9,693,716],{"slug":3622,"featured":6,"template":696},"whitesource-gitlab-security-integration","content:en-us:blog:whitesource-gitlab-security-integration.yml","Whitesource Gitlab Security Integration","en-us/blog/whitesource-gitlab-security-integration.yml","en-us/blog/whitesource-gitlab-security-integration",{"_path":3628,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3629,"content":3635,"config":3641,"_id":3643,"_type":13,"title":3644,"_source":15,"_file":3645,"_stem":3646,"_extension":18},"/en-us/blog/why-ai-in-devops-is-here-to-stay",{"title":3630,"description":3631,"ogTitle":3630,"ogDescription":3631,"noIndex":6,"ogImage":3632,"ogUrl":3633,"ogSiteName":683,"ogType":684,"canonicalUrls":3633,"schema":3634},"Why AI in DevOps is here to stay","Two years ago artificial intelligence wasn't part of mainstream software development. Now AI in DevOps is seemingly everywhere. Here's why.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749664015/Blog/Hero%20Images/laptop.jpg","https://about.gitlab.com/blog/why-ai-in-devops-is-here-to-stay","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Why AI in DevOps is here to stay\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Valerie Silverthorne\"}],\n        \"datePublished\": \"2022-09-15\",\n      }",{"title":3630,"description":3631,"authors":3636,"heroImage":3632,"date":3637,"body":3638,"category":1244,"tags":3639},[1097],"2022-09-15","\nIn 2020, respondents to our annual Global DevSecOps Survey started mentioning artificial intelligence and machine learning for the first time. In that survey, roughly 16% of respondents were using “bots” to test code, or were planning to, while 12% of devs said knowledge of AI/ML would be critical to their future.\n\nFast forward just two years and [AI in DevOps](/topics/devops/the-role-of-ai-in-devops/) is a reality in teams around the world, according to our [2022 Global DevSecOps Survey](https://about.gitlab.com/developer-survey/).\n\n- 24% of respondents said their DevOps practices include AI/ML, more than double the 2021 percentage.\n\n- 31% of teams are using AI/ML for code review, 16 points higher than last year.\n\n- Today 37% of teams use AI/ML in software testing (up from 25% in 2021), and 20% plan to introduce it this year. Another 19% plan to roll out AI/ML-powered testing in the next two to three years.\n\n- Fully 62% of survey takers are practicing ModelOps.\n\n- 51% use AI/ML to check (not test) code.\n\nAll told, only 5% of teams said they had _no plans_ to incorporate AI in DevOps.\n\nHere's a snapshot of where AI in DevOps is today and why, despite some challenges, AI will likely play an increasingly important role.\n\n## Why AI in DevOps\n\nIn many ways, [DevOps and AI/ML](/blog/ai-in-software-development/) are the perfect marriage: DevOps requires automation to reach maximum efficiency and AI/ML are obvious choices to tackle repetitive tasks. Imagine adding team members entirely focused on a single job, with incredible attention to detail and no need for vacations or even a coffee break – that’s an ML “bot” in a nutshell.\n\nWhen we asked DevOps teams what the most common reasons were for [software release delays](/blog/top-reasons-for-software-release-delays/), the answers called out steps that are critical but manual, tedious, time-consuming, and potentially rife with errors: [software testing](/blog/the-gitlab-guide-to-modern-software-testing/), code review, security testing and code development. For many teams, AI/ML could be key in streamlining these processes.\n\n## Smarter software testing\n\nNo DevOps process is perhaps in more need of streamlining than software testing, which is no doubt why teams have been adding AI/ML into the mix for several years now. Testing is that process [everyone loves to hate](/blog/the-software-testing-life-cycle-in-2021-a-more-upbeat-outlook/), but it is also the step that needs to happen more often in all the ways, or at least that’s what developers tell us year after year. But there are so many different kinds of tests, limited development time, and even more constrained QA teams. Machine learning bots can help bridge the manpower gap, freeing up resources to focus on tests best done by humans.\n\nAnd increased testing creates another issue – test data management – that could ideally be triaged and dealt with using AI.\n\n## The benefits of ModelOps\n\nAI/ML solutions have also made their way into other DevOps steps, specifically [ModelOps](/direction/modelops/). Not only is this an area GitLab is focusing on ([beginning with smarter code reviews](/blog/the-road-to-smarter-code-reviewer-recommendations/)), but more than half of DevOps teams report they’re exploring what’s involved in bringing data science and operations together.\n\n## Beware the learning curve\n\nArtificial intelligence and machine learning are not without their challenges, however. In our 2022 survey, developers expressed very real concerns about the steep learning curves involved in the technology adoption. “Technology is rapidly changing,” was a thought shared by many developers, alongside “implementing AI is an enormous challenge.”\n\nOne developer summed it up: “4G, 5G, AI, Metaverse, virtual space - developers have to support all of this.”\n\nBrendan O'Leary, [staff developer evangelist at GitLab](/company/team/#brendan), says AI naturally has a big learning curve because it requires experimentation. \"This is not just a programming language,\" he explains. \"We've got some data and a hypothesis around it and AI is what's going to help us prove it. This is a different kind of experiment than other kinds of coding... we've got to learn how to measure the impact, understand it, and iterate on it. It's a different kind of paradigm.\"\n",[851,3640,9],"developer survey",{"slug":3642,"featured":6,"template":696},"why-ai-in-devops-is-here-to-stay","content:en-us:blog:why-ai-in-devops-is-here-to-stay.yml","Why Ai In Devops Is Here To Stay","en-us/blog/why-ai-in-devops-is-here-to-stay.yml","en-us/blog/why-ai-in-devops-is-here-to-stay",{"_path":3648,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3649,"content":3655,"config":3660,"_id":3662,"_type":13,"title":3663,"_source":15,"_file":3664,"_stem":3665,"_extension":18},"/en-us/blog/why-gitops-should-be-workflow-of-choice",{"title":3650,"description":3651,"ogTitle":3650,"ogDescription":3651,"noIndex":6,"ogImage":3652,"ogUrl":3653,"ogSiteName":683,"ogType":684,"canonicalUrls":3653,"schema":3654},"Why GitOps should be the workflow of choice","What is GitOps and how do you apply it in real-world applications?","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749681239/Blog/Hero%20Images/shiro-hatori-WR-ifjFy4CI-unsplash.jpg","https://about.gitlab.com/blog/why-gitops-should-be-workflow-of-choice","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Why GitOps should be the workflow of choice\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Brendan O'Leary\"}],\n        \"datePublished\": \"2020-04-17\",\n      }",{"title":3650,"description":3651,"authors":3656,"heroImage":3652,"date":3657,"body":3658,"category":739,"tags":3659},[1424],"2020-04-17","\n\n## How did we get here?\n\nIn 2006, with the launch of AWS Elastic Compute, Amazon set off a revolution in the way we, as developers, consume and use compute and other resources required to deploy and maintain the applications we write. Not long after, infrastructure-as-code started to explode onto the scene with projects like Puppet, Ansible, and Terraform.\n\nAs these technologies matured, it became apparent that scaling applications in a modern or cloud environment required reproducible, reusable components, and infrastructure-as-code became the gold standard for ensuring the proper allocation of resources to an application. At the same time, the infrastructure space and world of software continued to evolve. The concept of [continuous delivery](/topics/ci-cd/) and release of software came into vogue and was popularized by large technology companies. The \"book\" on continuous delivery came in 2011, where it became apparent that to move fast enough to keep up with market demands, a radically [faster DevOps](/topics/devops/) cycle was required.\n\nAs continuous delivery for software becomes more commonplace, new solutions in the infrastructure space have been created to keep up. Kubernetes and the rise of [\"serverless\"](/topics/serverless/) promised to once again free developers from the need to worry about infrastructure. In a post-DevOps world - how does one think about infrastructure-as-code and applications as one cohesive unit?  Enter GitOps.\n\n## What is GitOps?\n\n[GitOps](/topics/gitops/) is conceptually not that different from either infrastructure-as-code or continuous delivery. In fact, in many ways, it is the convergence of those two concepts. Developers and operations teams alike can share a common repository of code, and GitOps allows a developer-like experience for managing applications and their underlying infrastructure. In that way, you can use GitOps as an operating model for modern infrastructures like Kubernetes, serverless, and other cloud native technologies.\n\nVersion control and [continuous integration](/solutions/continuous-integration/) are essential tools for deploying software continuously and reliably. GitOps brings both of those software best practices to operations by making the repository the central-source-of-truth for all of the infrastructure required to run applications. With GitOps, any change to infrastructure is committed to the git repository along with any application changes.\n\nThis allows developers and operators to use familiar development patterns and branching strategies. From there, a merge request provides the [central place to collaborate](/topics/gitops/gitops-gitlab-collaboration/) and suggest changes. Once merged into the mainline, CI/CD should be configured to deploy both the application and infrastructure changes automatically. The way this enables synchronization between developers and operators is what can be very appealing about GitOps as the next iteration of DevOps.\n\n## Why GitOps?\n\nWhy are so many organizations large and small considering a move to a more GitOps-focused culture?\n\nAs software has eaten the world, business operational excellence has become directly aligned with the ability to deliver quality software faster. Business survival depends on adaptive and efficient software development practices. Those practices require new processes and changes in the way we think about change management.\n\nIn many software practices, the concept of code review and approval is where most of the checks and balances for deploying production code comes into play. At GitLab, we believe that the [merge request](https://docs.gitlab.com/ee/user/project/merge_requests/) is the best place to collaborate on code and approve changes.  Processes and tools that are external to the code change only serve to increase cycle time and inhibit an organization’s ability to deploy code quickly.\n\nOnce an organization has embraced continuous integration and code review as the place for change request approval, it is a natural progression to discuss the idea of continuous delivery to production after those CI gates and human approvals are passed. As GitOps takes that concept a step further and integrates the pipeline to production directly in the git and merge request workflow, it’s become a hot topic and one that will become the normal workflow for efficient software organizations. Taking unnecessary steps and tools out of the critical path to production enables an organization to deliver better products faster, without sacrificing the governance required to deploy code.\n\n\n\nCover image by [Shiro Hatori](https://unsplash.com/@shiroscope) on [Unsplash](https://www.unsplash.com)\n{: .note}\n",[108,850,9],{"slug":3661,"featured":6,"template":696},"why-gitops-should-be-workflow-of-choice","content:en-us:blog:why-gitops-should-be-workflow-of-choice.yml","Why Gitops Should Be Workflow Of Choice","en-us/blog/why-gitops-should-be-workflow-of-choice.yml","en-us/blog/why-gitops-should-be-workflow-of-choice",{"_path":3667,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3668,"content":3674,"config":3681,"_id":3683,"_type":13,"title":3684,"_source":15,"_file":3685,"_stem":3686,"_extension":18},"/en-us/blog/zeit-launches-now-for-gitlab",{"title":3669,"description":3670,"ogTitle":3669,"ogDescription":3670,"noIndex":6,"ogImage":3671,"ogUrl":3672,"ogSiteName":683,"ogType":684,"canonicalUrls":3672,"schema":3673},"ZEIT launches Now for GitLab","This first-class integration can automatically deploy any GitLab project containing a static or dynamic website to ZEIT's global CDN.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749670498/Blog/Hero%20Images/gitlab-zeit-cover.png","https://about.gitlab.com/blog/zeit-launches-now-for-gitlab","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"ZEIT launches Now for GitLab\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"Sarup Banskota\"},{\"@type\":\"Person\",\"name\":\"Arunoda Susiripala\"}],\n        \"datePublished\": \"2019-04-01\",\n      }",{"title":3669,"description":3670,"authors":3675,"heroImage":3671,"date":3678,"body":3679,"category":298,"tags":3680},[3676,3677],"Sarup Banskota","Arunoda Susiripala","2019-04-01","\n\n**[ZEIT Now](https://zeit.co/now) is a [serverless](/topics/serverless/) deployment platform that takes the burden out of configuring the cloud**. Projects deploy to Now instantly, scale automatically, and require zero supervision.\n\n### Why we created Now\n\nWe believe that deployments should be fast, simple, reliable, and cost-effective. We want to **enable developers to focus on their core applications**, and not on configuring DNS, scalability, or other infrastructure. That's why we created Now – to allow you to just push code, while we take care of the infrastructure.\n\nGit is popular among us developers – our code is often backed by a Git repository hosted on GitLab or GitHub. For most of us, our workflow involves developing features in distinct branches, which get merged into a stable master branch (or its equivalent). For most teams, the strategy around deployments follows the same style – we first stage our work on feature-specific URLs, and then finally merge them into a production URL.\n\n**We want Now to enhance the developer workflow**. By sticking close to the source code, and integrating with code collaboration tools we love, we are helping enhance the code review and release process.\n\n### Now for GitLab\n\nIn this post, we showcase our most requested feature,  [Now for GitLab](https://zeit.co/gitlab). With this first-class GitLab integration, you can automatically deploy any GitLab project, and enjoy core Now features, including global CDN, Anycast DNS, HTTPS support, and DDOS Protection.\n\n### Benefits\n\nOnce set up, **Now builds and deploys automatically, for every commit you push to GitLab**. Each such deployment gets a unique URL and we keep all your deployments alive. Thanks to our usage-based pricing model, you only pay for actual invocations and don't have to worry about unused deployments.\n\n![GitLab commit](https://about.gitlab.com/images/blogimages/zeit-now/gitlab-commit.png){: .medium.center}\n\n*\u003Csmall>Being able to test a unique deployment for every commit allows you to merge changes to your project with confidence.\u003C/small>*\n\n**All deployments made within a merge request are listed chronologically on its page**. They can be tested at any time, allowing your team to try out changes as progress is made, and to iron out concerns before pushing a new feature to production.\n\n![track deployments on MR](https://about.gitlab.com/images/blogimages/zeit-now/deployments-mr.png){: .medium.center}\n\n*\u003Csmall>You can track all the deployments made towards a specific feature on its merge request page.\u003C/small>*\n\n**Every merge request receives a unique URL** based on its branch name. The URL points to the latest deployment made on the merge request branch. You can share the URL with your team or even publicly, for beta testing your changes.\n\n![staging](https://about.gitlab.com/images/blogimages/zeit-now/gitlab-staging.png){: .medium.center}\n\n*\u003Csmall>The unique URL for the merge request acts as a staging link that can be passed around to anybody in the team who is interested in tracking development updates on a specific feature.\u003C/small>*\n\n**Merged MRs are automatically deployed to production**. Once deployed, we automatically alias your deployment to the production domain name.\n\n![alias](https://about.gitlab.com/images/blogimages/zeit-now/gitlab-alias.png){: .medium.center}\n\n*\u003Csmall>Once a merge request lands on the [default branch](https://docs.gitlab.com/ee/user/project/repository/branches/default.html), it is automatically built, deployed, and aliased to the chosen production domain names.\u003C/small>*\n\n## Getting started with Now for GitLab\n\nWe offer a **powerful free tier** which allows you to deploy a small-scale production app without requiring a credit card. To get started, visit the [**ZEIT Sign up page**](https://zeit.co/signup) and click the `Continue with GitLab` button. When GitLab requests an authorization, click `Authorize`.\n\n![sign up for Now for GitLab](https://about.gitlab.com/images/blogimages/zeit-now/sign-up-zeit-gitlab.png){: .center}\n\n*\u003Csmall>By signing up for ZEIT with GitLab, you automatically connect Now with your GitLab account, making it easier to link to your GitLab projects.\u003C/small>*\n\nOnce you complete the authorization, you can [**link any existing GitLab project**](https://zeit.co/new) with your ZEIT account, or create a new one based on our [Quick Start templates](https://zeit.co/new).\n\n![quick start templates](https://about.gitlab.com/images/blogimages/zeit-now/templates.png){: .medium.center}\n\n*\u003Csmall>The Quick Start templates save you time from setting up boilerplate code for several popular projects, such as Next.js, Vue, or Hugo.\u003C/small>*\n\nPlease note that if you already have a ZEIT account, you can set up the connection to GitLab on your [ZEIT account page](https://zeit.co/account).\n\n## Prepare your project for Now\n\nTo be able to successfully process a GitLab project, Now needs to be provided with build and deployment information. This information can be provided via a [`now.json` configuration file](https://zeit.co/docs/v2/deployments/configuration).\n\nFor example, if you are interested in deploying Node.js serverless code, the `now.json` file could be framed as follows:\n\n    {\n      \"name\": \"GitLab Project\",\n      \"alias\": [\"gitlab-project.now.sh\"],\n      \"builds\": [{\n        \"src\": \"index.js\",\n        \"use\": \"@now/node\"\n       }]\n    }\n\n*\u003Csmall>[now.json](https://zeit.co/docs/v2/deployments/configuration) allows us to provide information about building, deploying, and aliasing a GitLab project with Now.\u003C/small>*\n\nMore information on configuring `now.json`, including all supported options, is available on its [docs page](https://zeit.co/docs/v2/deployments/configuration). We support building and deploying many popular technologies through our open-sourced official [Builders](https://zeit.co/docs/v2/deployments/builders/overview), including Python, Rust, PHP, and Go. We welcome your contributions toward new Builders to support your favorite technology. To help with that, we also have a [guide](https://zeit.co/docs/v2/deployments/builders/developer-guide/) in place that walks through the process of creating and publishing a Builder.\n\n### Custom domain names and Instant Rollbacks\n\nWhen a GitLab merge request is merged into the [default branch](https://docs.gitlab.com/ee/user/project/repository/branches/default.html), [Now for GitLab](https://zeit.co/gitlab) instantly triggers a new deployment. As soon as that deployment completes, it is **automatically aliased to the production domain names** that were specified through the `alias` property in `now.json`.\n\nWhen you deploy with Now, **we map all your code and configuration to a single, unique URL**. Now only performs a new build when the underlying code receives changes.\n\nIf you trigger a revert within GitLab on the [default branch](https://docs.gitlab.com/ee/user/project/repository/branches/default.html), the code and configuration perfectly match a deployment URL Now previously had. This allows us to perform the alias with the previous URL within milliseconds, thus providing an **Instant Rollback**.\n\n### Final words\n\nOur mission at ZEIT is to make the cloud accessible to everyone. The [Now for GitLab](https://zeit.co/gitlab) integration was one of our most requested features, and we are thrilled to make it available to you.\n\nPlease give [Now for GitLab](https://zeit.co/gitlab) a try, and let us know what you think. Our Twitter is [@zeithq](https://twitter.com/zeithq).\n",[108,9],{"slug":3682,"featured":6,"template":696},"zeit-launches-now-for-gitlab","content:en-us:blog:zeit-launches-now-for-gitlab.yml","Zeit Launches Now For Gitlab","en-us/blog/zeit-launches-now-for-gitlab.yml","en-us/blog/zeit-launches-now-for-gitlab",{"_path":3688,"_dir":243,"_draft":6,"_partial":6,"_locale":7,"seo":3689,"content":3695,"config":3700,"_id":3702,"_type":13,"title":3703,"_source":15,"_file":3704,"_stem":3705,"_extension":18},"/en-us/blog/4-must-know-devops-principles",{"title":3690,"description":3691,"ogTitle":3690,"ogDescription":3691,"noIndex":6,"ogImage":3692,"ogUrl":3693,"ogSiteName":683,"ogType":684,"canonicalUrls":3693,"schema":3694},"4 Must-know DevOps principles","Learn four key DevOps principles and why they are essential to successful development and deployment.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749665982/Blog/Hero%20Images/jpvalery-9pLx0sLli4unsplash.jpg","https://about.gitlab.com/blog/4-must-know-devops-principles","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"4 Must-know DevOps principles\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"GitLab\"}],\n        \"datePublished\": \"2022-02-11\",\n      }",{"title":3690,"description":3691,"authors":3696,"heroImage":3692,"date":3697,"body":3698,"category":848,"tags":3699},[889],"2022-02-11","The popular software development methodology [DevOps](/topics/devops/) can be a bit confusing to beginners, especially when it encompasses other areas such as security (DevSecOps), business (BizDevOps), and the like. \n\n## So what is DevOps?\n\nDevOps takes two previously separated teams – software development and IT operations – and turns them into one united front that creates secure code while speeding up the software development lifecycle. DevOps fundamentals include a collaborative and communicative culture, automated testing, releases and deployments, and frequent iteration. Another commonly used term in the DevOps space is [DevSecOps](https://about.gitlab.com/topics/devsecops/), which refers to a DevOps practice with a specific emphasis on security.\n\nWhat matters is what’s at the heart of the DevOps methodology – these four key principles that can improve your organization’s software development practice.\n\n1. Automation of the software development lifecycle\n2. Collaboration and communication\n3. Continuous improvement and minimization of waste\n4. Hyperfocus on user needs with short feedback loops\n\n## An examination of key DevOps principles\n\nRoughly 15 years ago, the idea emerged to bring development and operations together in a seamless fashion. In 2009, the term “DevOps” was coined by Patrick Debois, who is considered one of the methodology’s primary gurus. DevOps includes a lot of the principles of [Agile software development](/topics/agile-delivery/), but with a special emphasis on breaking down development and operations silos. \n\nDevOps has continued to grow in popularity since that time, from small businesses to enterprises with legacy systems and nearly every size company in between. Like almost anything else, DevOps can adapt to an organization’s unique needs and environment, adjusting to what’s most important to the business. \n\nAs such, it’s possible to find many different flavors of DevOps, though, at their core, each has the following 4 must-know principles in place:\n\n### Automation of the software development lifecycle\n\nThe North Star for all DevOps teams is automation. Before DevOps, software development was a very manual effort requiring human involvement (and physical handoffs) at every stage of the process. All of this human involvement meant companies were lucky to update or release new code once a year, and many were on an 18- or 24-month release cadence. \n\nToday so-called [“elite DevOps teams”](/blog/how-to-make-your-devops-team-elite-performers/) release code many times a day – and they’re able to do that largely because of automation. \n\nTo understand the power and importance of automation in DevOps, consider software testing, an often overlooked and unappreciated step that is regularly scapegoated for causing release delays. There’s no question software testing is critical; without testing companies risk releasing broken or actually even unsafe code. \n\nBut testing is perhaps the most hands-on of all the steps in DevOps, requiring people to write test cases, run myriad tests, analyze the results, and then circle back with developers for fixes. That’s all a long way of saying [there’s a reason teams point to testing](/blog/want-faster-releases-your-answer-lies-in-automated-software-testing/) as the number one reason code isn’t released on time.\n\nEnter automation and the idea that the most basic software tests could happen as the code is written. Test automation dramatically speeds up the entire process and frees software testers to look for potentially more damaging code quality issues. \n\nAlthough testing is one of the most dramatic automation “wins” in DevOps, it’s far from the only one. [Continuous integration](/topics/ci-cd/) automates the process of moving new code into existing code, while [continuous deployment](/blog/how-to-keep-up-with-ci-cd-best-practices/) helps automate releases. And [Infrastructure as Code](/topics/gitops/infrastructure-as-code/) makes it easy to automate the process of provisioning developer environments. \n\n### Collaboration and communication\n\nA good DevOps team has automation, but a top-notch DevOps team also has collaboration and communication. The basic idea of bringing dev and ops together (as well as sec, test, stakeholders, etc.) hinges on teams being able to collaborate. And that can’t happen if there isn’t clear and regular communication.\n\nThis sounds like a deceptively simple principle of DevOps, but, like most things, the devil is in the details. Devs want to write code and move it along into the world; ops professionals focus on tools, compliance, and the cloud; and the security team wants to ensure the code is safe. Dev, ops, and sec don’t have the same priorities, might not speak the same “language,” and are likely to approach problem-solving from very different perspectives. A case in point: [Dev and sec still don’t really get along](/blog/developer-security-divide/), in part because the communication and collaboration gap remains wide.\n\nIt takes effort to bring teams together and often [out-of-the-box thinking](/blog/want-secure-software-development-our-top-5-tips-to-bring-dev-and-sec-together/). And in one of those \"chicken and egg\" situations, teams need to communicate for successful DevOps, but DevOps itself can lead to better communication, and happier developers, according to findings in our [2021 Global DevSecOps Survey](/developer-survey/).\n\n### Continuous improvement and minimization of waste\n\nLeaning heavily on earlier software development methodologies, including [Lean](https://searchsoftwarequality.techtarget.com/definition/lean-programming) and Agile, DevOps also focuses on reducing waste and continuous improvement. Whether it’s automating repetitive tasks like testing so as not to waste time, or reducing the number of steps required to release new code, well-functioning DevOps teams continue to measure performance metrics to determine areas that need improvement. \n\nExpect teams to strive [to continuously improve release times](/blog/why-improving-continuously-speeds-up-delivery/), reduce the [mean-time-to-recovery](https://pipelinedriven.org/article/devops-metric-mean-time-to-recovery-mttr-definition-and-reasoning), and number of bugs found, in addition to a number of other metrics. \n\n### Hyperfocus on user needs with short feedback loops\n\nThe final must-know DevOps principle is the importance of bringing the actual user into every step of this process. Through automation, improved communication and collaboration, and continuous improvement, DevOps teams can take a moment and focus on what real users really want, and how to give it to them. There’s no question that finding a way into the user mind is quite tricky, and [teams can struggle to implement processes](/blog/journey-to-the-outer-loop/) to achieve this. \n\nThe other difficult piece of this is that user feedback, once gathered, must be delivered quickly so time isn’t wasted. That’s why short feedback loops are critical, and why teams need to [put energy into making them even shorter](/blog/journey-to-the-outer-loop/) as time goes on. \n\n## Benefits of a DevOps model and practices\n\nWhat happens if teams do DevOps right? In our 2021 survey, 60% of developers told us they were releasing code at least 2x faster, thanks to DevOps. Other benefits of a DevOps model include improved code quality, faster time to market, and better planning. \n\nAnd for bonus points, survey takers told us that having a successful DevOps practice also made for happier developers, and there’s [scientific data](/blog/why-software-developer-job-satisfaction-matters-and-how-to-make-it-happen/) that shows happier devs are more productive. \n\n## What are some challenges of implementing DevOps?\n\nDevOps can be challenging in the begining, particularly if it’s the first time being implemented within an organization. Here are some of the challenges of implementing DevOps. \n\n* **Breaking down the silos.** It may be difficult to break the mentality of development and operations being separate entities. Gather a basic understanding of the roles and responsibilities of a combination DevOps team.\n\n* **Understanding the jargon.** DevOps comes with a lot of shorthand, tech jargon, and SO many acronyms, like CI/CD. Take some time to study and remember that learning on the go is entirely normal and acceptable. \n\n* **Migrating from legacy software.** DevOps can be especially tricky for teams trying to migrate legacy software. Many tools designed for DevOps don’t work with mainframes (as one example) and integrations can be challenging even for experienced DevOps pros. It also doesn’t help that there’s a shortage of mainframe and other legacy programmers.\n\n* **Too many tools.** Teams spend so much time integrating and maintaining tools it’s getting in the way of actually developing, releasing and monitoring code. This is commonly known as the “toolchain tax.”\n\n* **Taming the learning curve frustration.** DevOps is complicated, and learning how it works is a marathon, not a sprint. Practice patience and grace with the team as implementation goes forward and rely on any resources available, such as help documentation and platform representatives – and sometimes plain old trial and error.\n\n## How to get started with DevOps in your organization\n\nWhen preparing to get started with DevOps, the following preperation is required:\n\n1. Map out the goals behind DevOps implementation.\n2. Clarify the roles and responsibilities of each stakeholder involved.\n3. Start basic and grow with experience.\n4. Plam to automate as much as possible.\n5. Plan your toolchain (and remember, toolchains can always be altered).\n6. Set up regular progress checkpoints.\n7. Be prepared to constantly iterate (but after giving something enough time to prove that iterating is necessary). \n\n## What is the future of DevOps?\n\nDevOps adoption and success experienced an enormous “jumpstart” thanks to the global pandemic. Teams moved past some of the cultural “how do we work together?” issues and matured into the “how do we adopt the right technologies?” mindset, based on results from our survey. Use of advanced technologies, including Kubernetes, [DevOps platforms](/topics/devops-platform/), and artificial intelligence (AI)/machine learning (ML) give hints as to what the future of DevOps looks like. \n\nIt’s safe to expect increased automation, smarter AI/ML-powered decision making (starting in places like [code review](/blog/the-road-to-smarter-code-reviewer-recommendations/) and a more thoughtful choice of tools, such as continuing adoption of DevOps platforms to streamline the process.",[851,717,9],{"slug":3701,"featured":6,"template":696},"4-must-know-devops-principles","content:en-us:blog:4-must-know-devops-principles.yml","4 Must Know Devops Principles","en-us/blog/4-must-know-devops-principles.yml","en-us/blog/4-must-know-devops-principles",17,[676,701,724,749,771,792,814,834,858],1759517427119]