 Hey, welcome everyone. I want to thank you for joining us today. We are excited to have you here. So in this webcast, we're going to be talking about a really interesting topic, which is rich change controls for building workflows you can trust. My name is Joel. I lead a solutions architect team here at GitLab. I'm joining you today from Chicago, Illinois. And we'd love to learn where you're from. So please use the chat function, say hi, tell us where in the world you might be today. Before we get started, a couple of quick housekeeping items. Feel free to ask questions throughout the presentation. You can use the Q&A function at the bottom of your screen for that. We're going to have a dedicated time for questions and answers at the end of the webcast, but you can go ahead and send your questions as you think of them throughout. We'll be sure to get to those near the end of our time together. If you're experiencing any technical difficulties, you can use the chat function to get in touch with me, the moderator for assistance. Our presenter today is Darwin Sanoi, a GitLab Senior Solutions Architect located in Pennsylvania. We're going to launch a couple of polls throughout the webcast as well so we can learn more about you. And that way Darwin can also tailor the presentation accordingly. So with that, I'm going to launch our first poll and it's just gonna ask from a usability perspective what GitLab package or tier are you using today? Great, I'm gonna share this out to you so you can kind of see we've got a pretty even breakdown today across each of the tiers. And so we'll keep that in mind as we discuss our topics for the day. So at this point, thank you for your participation. Thank you for joining us. And I'm going to turn this over to Darwin. Good morning and afternoon, everyone. My name is Darwin Sanoi, Senior Solutions Architect at GitLab. It is my job and also my pleasure to help customers understand how to apply the GitLab tool set to various DevOps problems for a whole variety of customer profiles. I really enjoy automation a lot and so it's been a great opportunity as well as a great pleasure to help customers with that. So today what we want to talk about is how GitLab has rich workflow that can really help you control and manage your change management activities. Typically, GitLab and other Git collaborative systems are thought of as working with code collaboration, making sure code is good quality before it goes out. But GitLab also introduces operations as part of the mix, so it supports deployment. So a lot of these controls are also very necessary for reliable releases to production. And so that's why it's important that you kind of understand the GitLab controls that are available. The other thing you'll notice is they're kind of sprinkled all throughout the product and so we hope to try to give you kind of a global view of where these controls can be used, where they're kind of sometimes seemingly hidden behind a little piece over here, a little piece over there. So we hope to put this kind of a global picture together for you. So some of the things we'll be going through, first of all is custom user groups. You can create custom user groups in GitLab and specifically that they handle users only and so we'll be talking a little bit about how you set that up and why that's beneficial to you. We'll also be talking about gating controls for both code and deployment control. So once again, GitLab really braces GitOps and with GitOps everything needs to be in Git, the single source of truth. And because of that, our deployment information and our deployment workflows are also in there. In addition, we'll be talking about using work repos and merge requests as workflow building blocks. So we have some capabilities and some features that span repos. And so sometimes people think about the whole idea of workflows and gating within a repo. And we're gonna kind of expand that mindset out a bit that no, well, you can start breaking up your workflows across multiple repos and then associate them with certain constructs. Also enabling de facto development patterns. So we'll typically get questions about, hey, can GitLab do this kind of pattern? Like I wanna do a typical microservice, 12-factor deployment where each service is its own repo. So we'll touch briefly after we get through the broader perspective of features on how some of that then looks and some of the de facto development patterns. And then we'll also have a summary of controls by addition and by control scope. So some of you said you're in starter, someone's silver, someone premium. We'll actually give you a bit of a breakdown in terms of controlling workflow, where do those features break out? And also what's the scope of them? Some of them are per repos, some of them are multi-repos, some of them are per merge request. So we'll take a look at that. I first wanna go through custom user groups because as you'll see when we step through the rest of the content, it'll say, hey, you can do this feature with custom user groups. So it's important you understand the flexibility and the foundational control that custom user groups can be for you. So quickly a history of the group structure in these solutions, Git collaborative solutions on the web, basically repositories were the only kind of resource that existed within Git collaborative solutions. And because of that, there was no need to really have a strict separation of user groups from resource groups. And so you'll see that typically you're grouping repositories together and then you just happen to add users to those groups. And so GitLab initially followed this structure as well. And that's why we see it out there. It's not like operating system groups where there's a lot of different resource types you can assign to users and user groups. Let's keep popping up on me. I'm just gonna close it here. Also custom user groups can be used in many places for GitLab gating controls. So as we go through the presentation, you'll see that there's various places they can be inserted. We also can create dedicated group hierarchies for users. So instead of having our users just bundled in with repos and then we get confused about when we start adding those groups to other groups, what's going on. So we're gonna talk about potentially creating a dedicated group hierarchy for you. Now there's two settings that make a lot of this possible. If you go inside of a group in GitLab where you have maintainer access or hire so you can change the settings, under the group settings and then under security, you'll see that they have these two benign looking settings, one is allowed to create projects and that defaults to maintainers. So if we set this to no one, no one can create any repositories in that group. And then another one is allowed to create subgroups and this is generally defaults to maintainers as well. So if we set that to owners only, we can create a situation where we can add users to groups and we can even add maintainers to those groups and they can't create any repositories or any subgroups. So we effectively limit the capability for them to manipulate this hierarchy. You can also delegate group membership management. So if you make someone a maintainer over a group and then they can add and remove users and so that can be helpful. If you have enough trust and enough communication in your organization, you could also let maintainers add and remove subgroups. It's just important to understand how group flow works which we'll talk about here. One interesting question we've had is, hey, well, I created a group and I put users in as developers and I wanna add that group to a repository. Will they be developers in the repository? And the answer is no. So once you create a group with a bunch of users with roles in it, when you add that group to a new location in the system such as another group or a gating control, they get the assignment of whatever you give it to them in the target new system. So if I add a group called prod approvers and everyone in there is a developer but I add them to a new repo as a reporter then they're only gonna have reporter in that new repo. So just be aware that the original assignment to the group of the user does not flow through to sub assignments. And then group membership inherits down in Git collaborative systems, including GitLab. So when you add users to higher groups they automatically get inherited to all sub groups. So this is the one foundational difference from operating system groups that can make it a little more challenging to think about when you manage. So let's take a look at a couple possible structures. This structure is one that you'd probably typically go to if you're used to doing operating system groups. So you're like, okay, I'm gonna create a hierarchy that helps me organize groups so that they don't get too broad or deep or it's not completely flat. One helper that I try to use is a description no users in this group. That description helps people because it both states that there are no users in this group and states that you should not add users to this group. So hopefully as people use a system to either add groups to something or to try to add users to groups they can see that statement. However, it's just a kind of a process control or informational control. So what you should really understand is you should never be adding users to a group that's not a leaf group. So in the case of this hierarchy the end nodes of the groups is where we would add people and not to higher levels. Or if you add it into higher levels you have to just really be aware that you're adding them to every subgroup. So in this case, the SREs group we see that we try to add all SREs to a subgroup and then production approvers is a special subgroup but we would never add anyone to the SREs level. A better model, if you can afford it if it doesn't create one million groups for you in a flat hierarchy is to just leave the hierarchy flat. And then this way you don't have to communicate that because there's no way to add people to a higher level group that matters other than the root group of all users. And so this one here you can see by naming convention we kind of imply the hierarchy we're after. Do note that in both cases we've created a root group in our system that is where all users will be added. That is just a construct to help us think about it. In theory you could add these groups and make them user-only groups anywhere in your system. So you don't have to create a dedicated hierarchy. Please note prod approvers sprinkle out throughout both of these. If you have the premium product level and you have merge approval rules which we'll talk about you can pick, hey, I want two approvers from security one approver from QA and three from the specific application developers. So you can actually pick specific approvers for specific groups. And also that prod approvers group is emphasizing that this would be a deployment group. So deploying to prod versus collaborating on code. So that's kind of some of the gating controls as far as what we can do with custom groups and how we might configure them. So as we go through bear in mind that all the flexibility we've talked about in this slide applies anywhere where you see custom groups in the subsequent slides. So we're gonna try to build up the concept of the gating controls in GitLab. And we wanna start with the basic most fundamental idea that we all usually think of as SCM or source code management. We think of this concept of we've got a bunch of code people are working on and at some point they wanna integrate it all into a branch and make sure that there's no conflicts or that those are resolved that things build properly before we go to production. So your basic code review or code collaboration branch. And so that's the construct I have here on the screen. Now next thing is once again keep in mind custom groups throughout and then the first thing we wanna cover as a possible control is push rules. Push rules aren't strictly a merge control. They're actually in a way like a firewall for your repository. They basically prevent commits from getting into our repository in the first place. A good example is user credentials that are committed to code. If you commit code credentials to code and push it to your central repo you could flag it in CI and say, whoa, hey, you got some Amazon credentials here but getting those back out reliably is not very fun. It's hard and it also requires an ill-advised forced right of a branch to overwrite history. And so because that it's just better not to ever let them into the central repo. And so push rules are a way of doing this and they provide kind of some firewalling. Now at the premium level starter allows you to have push rules in the first place. And one of the actually one of the push rules you can enable is to prevent credentials from getting committed and there's a bunch of others and you can make some custom ones. But at the premium level we add two new ones that are very interesting. One is verified committers. Verified committers says, hey, if you're pushing these commits to the repo I wanna know that the user ID you're using to log into GitLab is the same one you've identified inside of your commits because in theory I could put any kind of identification into my commits and then push the code. The second one is rejecting unsigned commits or requiring signed commits. So every commit has to be signed so you can know it's never been tampered from the time the developer committed it to their local copy until the time it made it into your central repo. So if you have any security concerns that are heightened or you work in a government organization where you might have a lot of contractors or even a commercial organization with a lot of contractors and you need traceability right back to the individual level these two features are gonna be primary on your radar. Another feature that's added with premium is locked files and directories and you can think of this as a kind of a semaphore for a file in a repository. So you can put an indicator saying this file or directory I'm working on it no one else should be able to commit any commits to any branch anywhere that have to do with these files just block them because we need to work on it. It's really critical file for the next week or a day or whatever. And so that's another feature that helps with advanced scenarios where certain specific files and directories need to be highly managed. So let's talk about now our standard workflow would be developers are working on their feature builds and our feature about branches and they're gonna be bringing new code into the repository. Now when they do this in a feature branch and there could be many of these coming in bound at once they have to make it through our push rules and our pre-commit hooks. Technically I think locked files is a pre-commit hook. And so once it makes it through that then we have a new feature built. Now one of the really cool things about GitLab even at the free level is that you get enterprise capable production ready CI for free. But the other cool thing is you can build on every feature branch so that you can be sure that those feature branches actually check out long before it's time to start merging into anything that matters. An additional gating control that exists just within CI is a job that is set to when manual and basically it pauses the whole CI chain until someone comes and presses play or until you call an API to restart that stage. And so this can be kind of a gating control but we don't have any tracking of who pressed it. We know who's allowed to press it at the time that this repo, someone actually presses it. We can tell, okay, hey, you're a repo developer or maintainer who's allowed to press that button. But that's one kind of gating control that you will see used in some of the GitLab flows. We then have review apps and of course Kubernetes is really slick in this regard to set up a review app for every branch build. However, we also can do dynamic review apps for web server based builds. So Nginx or other web servers if you configure the web server correctly then you can push a dynamic review app out. And those are also dynamic review apps is what gives us some of our security scanning capabilities for DAST scanning of an existing app in its final target environment. So that's capable all through all of branch builds. And one other thing we'll just give a tip of the hat to is if you do the ultimate or gold you have a security and compliance scanning dashboard that can then be referenced and find out our new vulnerabilities coming to the software. Do we need to create issues for new vulnerabilities so that developers have to resolve them? And we'll touch on that a little bit later but in the ultimate you can also globally across your entire instance block or require a security approval for anything that introduces a vulnerability that hasn't been previously reviewed. And so those are some of the ultimate features that are kind of slick in this area. So let's talk now about merging. So a lot of the controls are gonna be around the merge timeframe because a merge timeframe is when we start getting people to come in, collaborate, sign off. And so this is a big point of workflow control. So at the repo level we have merge approvals that we set up and they apply to all branches in the repository. We also at the starter level have merge approvals just for you can pick a set of groups and users and roles in the repository and then set a total number of approvers. So you can say, include the security group, include this group and include any developer in the repo and I need five approvals. But you cannot distinguish how many approvals from any given subgroup but you can at least start getting some control that approvals are required. You can also protect custom tags. So you can protect tags if a certain commit is tagged then it requires it can be protected and only certain people in certain groups or certain individual users are allowed to actually approve those in the merge approval phase. Then in premium, we add custom multiple merge approval rules. So you have one merge approval rule when you have starter multiple merge approval rules means now I can create granularity and I can say, I want one from security, I want one from SREs and I want three from developers. And so you can really get granular on exactly what subgroups are required and what exact approvers are required within that. So this is where you can really start to get your hands around some interesting control configurations. Next comes branch protections and branch protections are per branch. So they have a little bit different granularity instead of being per repo, they're per branch. And within branch protections we can use custom groups at the starter level. So we can say an individual group and then we have our CI. So CI once again is attached to every possible branch if we want it. And so in this case, we're gonna have our integration branch go through our standard CI so that we can see that everything's building correctly. One thing that I'll mention in the table is we can do pre-merge commits and then require that those builds pass successfully. So a lot of systems say, you wanna know whether this build's gonna pass, okay, merge it, it's gonna fail and now you've already merged the code. So in GitLab at the premium level, you can say, you know what, I'd like you to run a kind of a disconnected pretend merge of all the code just in CI and run the CI and tell me what's gonna happen because even though everything passed, all the things I'm merging together past before when they get together, they may not play so nice. And so that's another cool feature that we'll touch on in that table. Another interesting thing now that we add with premium is protected environments with custom groups. And so whether you're doing web or Kubernetes environments, you can say only certain users are allowed to deploy this code to production and that's really a part of the CI phase. And we'll talk about how one way to configure this is to have a code base that goes through a build and then you redeploy only the deploy phase to 10, 15, 20 environments if you want. So those custom approvals or those protected environments are important to make sure that not just anyone can push to any environment. So this is basically our whole code cycle that we'd be used to as kind of a standard CI process. But now we can also add in branches that are purposed just for deployment. And so when we add in these additional deployment environment branches, we get all these controls applied also to these branches. And so you can see here by virtue of the big long merge approvals gate, it covers all branches in the repository. And so sometimes that's a benefit and sometimes it may not be, you may not want it that way and have to separate things into separate repositories. But if it's acceptable that merge approvals for deploy branches are the same as code reviews, then in the same repo, they would all be affected by those merge approval rules. However, the branch protections, of course, are at the branch level. So we can be more distinguished about what is allowed at that level. So we could potentially have less tight merge approvals and then as we work our way through branch merges, we have more and more tight rules. So we can see here independent branch protections by role comes for free, but when you go to the starter, we get users and custom groups within our branch protections. And then in premium, we get code owners. And code owners is the capability for the software for us to say that a given file or directory is owned by a user or a group or something else. And then we can say in branch protections, if I don't have an approval from someone in code owners because file such and such changed, then we're gonna block. And so even if someone didn't set it up in merge approvals that someone in that group gets that merge approval, we can block and make sure that, hey, these files are critical. They shouldn't be changed without someone in this team approving. So that's kind of a comprehensive view. It's a little overwhelming in total, but hopefully unpacking it slowly has allowed you to kind of get a feel for where some of these controls are enacted. So let's take this concept now and take a look at some of the meta repo or super capabilities. So one of the things we get at the repo level is an ops dashboard in premium. So that basically looks at our operations environments and tells us, hey, what is going on in each of these operations environment? So what's deployed? What version is deployed? Is it healthy? So that's ops dashboard can be helpful. We then also have something called merge trains. And merge trains are within a repository we can link together merge requests and say, these are related. And basically they must all succeed in order for me to approve all of them. The thing is with merge trains is they are not linked in any kind of sequential arrangement. And what this allows you to do is if you have five or six long running builds that are all required to be successful, you kind of say, you know what, let's pretend it's all gonna work out and run them in parallel. So you can speed up some of these dependencies. Then when you're done at the end, if one of them failed, well, then we fail everything. And yes, some work was wasted, but we also didn't wait forever to get that determination. So merge trains are part of premium and they happen within a repository. We then have the capability to start extending out to multiple repository capabilities. And one of these capabilities is environments roll up dashboards. So our ops dashboard is like per repo and environments are per group. So we can start seeing what's going on across multiple repositories. We also, that security and compliance dashboard that we talked about, it rolls up by group as well. And then we have something called merge dependencies. So we can start creating dependencies between our merges. So here you see merge request two depends on merge request one within the same repo. But this is also a cross repo capability. So we can create it across multiple repos that these dependencies are interacting. These are sequential. And so when we do this, we are saying complete all the builds make sure that merge request can be merged then merge the next one, but it depends on the first one being successful. So this is where order dependencies might be important or crossing over repos might be important to you. So that's just a couple more notes about what I just already mentioned about those. That's the concepts of kind of bringing together what can we do across repositories to start using repositories as actual building blocks of our workflow, as opposed to always thinking of within a repository. So let's take a look at a few scenarios of how you might leverage this. So the example we have here is a 12 factor microservice setup. And we're going by the 12 factor idea that we create a repo per microservice under the idea that they typically can release with independently. So if your microservices are designed on purpose so that teams can independently release but do that reliably, then you might have a repository per microservice. We're also seeing an uptick in repositories mono repos so that relationships can be identified between different code bases when multiple services need to change to implement a new piece of functionality. Notice here that GitLab through merged dependencies can allow you to still do that multi repo dependencies but within multiple repositories. So now you have a choice. You can do multiple repositories or a mono repo based on your other needs as opposed to simply the need to make sure that all the code works together. Another possible setup is you have repositories that generate artifacts and then you deploy to various environments. So in this example, we have a lot of SaaS customers that come to us and they might have several customers and they wanna deploy and update those stacks independently. We don't have to link all of those customers into the same repository that's building the code. We can use the concept of artifacts to then create deployment only repositories. In this case, we have three environments per stack or per customer. You could even have one per stack or customer if you've pre-qualified stuff before it starts going up to customers. Another possible workflow is doing advanced or doing multiple environments through just CD push. So here we see the common flow that we already talked about and we talked about being able to then push to an environment. But what we haven't indicated yet is you can actually push to multiple identical environments just through the CD push capability. So you can just keep pushing. Typically we'd use something like tags to say, go to this environment with this version, repush, go to this environment with this version. It's so it can be powerful that way and sometimes this is more what people think of as CD automation. The one downside is that those protected environments only have the one setting. So one group that can be used to prevent deployments if we don't want them or do want them. If you want more merge approval gating then you would need to make this into a merge request. And you could do that by say having a config file per customer or some other construct that would allow you to do that. So that's kind of how we do multiple environments for CD push. Let's just take a quick survey view of some of the capabilities that we have. We didn't mention some of these in specific because there's a lot of things to make it through but we did mention the when manual jobs. That's a little play pause switch. We can also prevent approvals being merged by the person who authored the code or by committers who have committed to the merge request. And in that way we're basically saying, hey, any of you guys who built the code, any of you folks that built the code, you can't approve it. We want all the approvals to be someone else. And so we can do that starter. And these are a lot of the core and starter features that you get out of the box. Also, pipelines must succeed is a core capability. However, when we combine that with pre-merge pipelines, that's when we start to get those pipelines where we can figure out what's gonna happen during a merge before ever merging. Here are a bunch of our premium features. We talked about a lot of these. I'll just highlight a few. Overriding the merge request approvals default settings. So normally the merge request approvals are required and that's it. They have to be met for the whole repo. So you set them for the repo and every merge request that goes through that repo has to meet them. What we can start to do, if we can trust those building the merge requests, we can go ahead and say, let those be defaults and they can change them. So they can change, maybe we only need one from security or none from security because we're doing doc updates. So you can turn those into defaults instead of requirements. And then merge request reviews is the ability for you to make comments. One thing that's been frustrating for me is I go into code and I make a comment and I'm like, oh, you know what? Now I see that they did that down here. Maybe I should have maybe not made that comment up there because they handled it. Now they've got an email that says, there's this critique of their code that's not valid. So merge request reviews allow you to say open a review and you can set up your 20 comments and then publish them all at once. So you can make sure they have a consistent review and that you haven't done something silly like I did there. Notice also in this table here, we have the control scope and the groups lined out for you so that you can see where these things are taking effect. And then finally, we have a final panel here. We didn't mention some of the audit capabilities but with premium, you get a lot of audit capabilities. There's a whole new user class called audit users that have read to the whole system even when people haven't added them to their repo. And this is a capability if you have GitLab as your own instance. But when you do this, then you can give that to your audit group or maybe your security group and they're able to rifle through all the code, run scans if they want on the codes with utilities or whatever without everybody having to permission them. Also audit events. So you're able to see in the graphical user interface what has been going on in the repo mainly people changing permissions and settings. So even those who have the ability to change permissions and settings are not doing that in a way that can't be seen. And then also the audit events API gives you access to a lot more audit events that aren't necessarily exposed in the GUI all the time. I should also mention that you should notice on GitLab specific merge requests, every action that's taken on the merge request goes into the discussion as a read-only comment. And it can be a little bit challenging to rifle through them, but they're all there. And this even includes check boxes. So if you have a check boxes inside of your merge request body and people are checking them off saying they've done stuff even that's auditable down in this discussion comment. Protected environments we touched on and environments dashboards, security approvals and license compliance approvals. So basically if your organization has blacklisted certain licenses, then security must approve anyone who says ignore this, I wanna go anyway, which will acquire a conversation from security or for security go, yeah, that's okay. And then also security approvals if the code being committed is ignoring a specific vulnerability, we can say security's gotta approve that on a global basis. So that's kind of an idea of the gating controls we have. So just as a matter of wrap up, what we went through today is custom user groups, the fact that they're capable in GitLab, you can build them, they can be user specific purposed and then they can be used in a vast array of places within the gating controls. We also talked about the gating controls and how because GitLab is a GitOps oriented tool in terms of working with deployments, your gating controls really apply to code collaboration and deployment control. We also talked about using repositories and merge requests as workflow building blocks. So remember you got some controls that can apply across repos. Then also some of the de facto development patterns that we enable and that's not all of them. There are others and you can pretty much craft it to do whatever you need it to. And then also just this table that shows you controls by addition and control scope and custom group support. So hopefully this sum total allows you to sit down now and look at some of the workflow requirements you have in front of you. Or maybe there's been something you've been hoping to do that you're like, oh, can GitLab even do that? Or how would we do this? Oh, there's three ways GitLab can do it rather than the one way that you just figure out on someone's video or something, you can see that there's multiple ways to do those things. So with that, I'd like to open it up for questions and answers on anyone who might have questions for anything. And just as a reminder, the Q and A panel can be used for that. I did receive a couple of questions during your conversation, but if you have additional questions, please make sure you post them in our Q and A panel. So one of the questions received actually dovetails nicely into what you just wrapped up there with. And that is the implementation scenarios that we discussed. Are those the only ones that can be accommodated by the GitLab workflow? Yeah, that's a good question. And I know too that when you approach GitLab, a lot of times it's hard to get out of the metaphors that you've been experiencing in the past. So basically code collaboration. And then also just code collaboration on the web in general has a certain flow and we kind of get stuck in those. But what we showed you is ways, the actual gating controls are very granular. And then we showed you that there are certain de facto patterns that you can accommodate. But with any of those controls and their scope and their group capabilities, you can go in and craft almost anything you like. So it could be a best practice, something like a microservice or it could be something very specific and opinionated towards how your company wants to do development and workflow. So yes, anything's possible. And if you get really deep into this and you kind of get in the muck and you're like, boy, I can't unwind what I need to do. Our sales organization is here to kind of help you with understanding if you're looking at say, hey, you know what, if we had these capabilities, could we do these kind of things? So always feel free to reach out to someone in sales and say, hey, I'm wondering if I could get a trial to figure out if with premium I can do the gating controls I need. So we can give you a hand with that. Excellent, thank you. So and to preface this next question, you touched real briefly on the concept of GitOps in this presentation. And there was just a question about a few details maybe on what GitOps entails. Sure, so GitOps is basically, for source code we've thought of Git as a single source of truth for a long time. GitOps says, let's extend that to the full DevOps cycle. So Git and source control and everything we kind of think of, we build our code, we have artifacts, now it's time for deployment. And GitOps says, you know what, we don't want just Git to be the single source of truth for the point at which we have built artifacts that are tested and ready to deploy. We want to be the single source of truth all the way through to production deployment. And so because of that, we start to roll in deployments, deployment support, some monitoring support and we start to make Git more central to all of that. And so with the possible exception of secrets which we can work in at a dynamic time in order for them to be stored appropriately we try to get everything else into Git. And by doing that, you can see in GitLab we've implemented a lot of the merge controls to allow you to then use them to also control deployment. But GitOps is basically the idea that everything including the entire DevOps cycle should be as much as possible pushed into Git as a single source of truth. Excellent, thank you. One other question here. So you mentioned code review and talked a little bit about comments and batching and things. Do you have any examples of what that might look like like in GitLab? Yes, I think we do. We have a merge request view that we want to show you here. So this is an existing merge request and the merge request ends up, GitOps says Git is a single source of truth with GitLab. The merge request is going to be your richest single source of truth as to what ought to be done in terms of code collaboration as well as environment deployments. So you can see here, as we move through a merge request we have a lot of the status information from build, from approvers. You can see here that we have a pipeline that's passed with many phases. If we want to, we can dig into this pipeline and see actual logs for each phase. We can see what results have come back. We can see that we have certain approvals that are required and view the eligible approvers within that. Then if we have ultimate in this case we have security scanning and license compliance scanning coming in. There are in these cases complete panels that allow a separate view of the individual breakdown. So some of the build feedback will come back as just text information but in some of the cases we have panels built around it so we can start to look through here, take actions, we can dismiss certain vulnerabilities. A really cool thing here is anyone can go ahead who has access to the repo and create a new issue saying I need to investigate this particular vulnerability and resolve it before we move forward. We also have the license panel which is also linked in the merge request so we can start seeing that, hey, these are the licenses that are here. It'll call out new licenses or blacklisted licenses so that we can manage that. And as we move down our merge request, you can see here's some of the audit comments that I mentioned, so these can't be edited. So as certain things happen we have an audit log going on throughout the merge request so we can see what happened when. And then this is an example of a question or a comment that someone's made that is a review request. So it's basically requiring people to make sure that someone says, hey, you know what? There's a problem with this code or I think it should be done a different way. And so these can also block the merging. So it's actually a starter capability to say all discussions must be resolved and that includes review discussions. So we can basically say, hey, if someone has an exception with the code we're not moving forward until it's resolved. And so that's kind of the global view of the merger request and how you can get in front of some of this stuff. Excellent, thanks for sharing that. And so that takes us to the end of our questions. Thank you, Darwin, for an incredibly informative session today and that's it from us. So thank you so much for joining us. We will be sharing the recording and sending it over from this webcast over the next couple of days. So look for it. Thank you very much, enjoy your day.