 Next, we'll hear from Natalia Kodiakova from Raysono AG. She'll share how they're using CI templates to, as she says, automatically boost setup speed and consistency. Over to Natalia. Hello, everyone, and welcome to GitLab Commit 2021. My name is Natalia Kodiakova, and today I want to present you a talk using CI templates to automatically boost setup speed and consistency. A couple of words about myself. I'm a senior software engineer, back-end and DevOps at Raysono, based in Munich, Germany. I come, so to say, from the engineering trenches. My first language is Java. In my company, I adopted GitLab, and I'm a coach in CI tools and best practices when it comes to DevOps. I organize hackathons on a regular basis, and I'm a fan of algorithms and clean code. Let's look at our agenda today. The ever-increasing complexity of project setup was quite menacing, until we got a new hope, CI templates. The force awakened, and the CI template library arose company-wide. I'll show you how we created the library of CI templates and fine-tuned it, and what our automation Jedi achieved in the end. So let's jump right in. It always takes more or less same steps to set up a project. Create a repository, set up a CI pipeline with common jobs like build, test, code quality scan. Then set up a deployment, which is usually one of the standard alternatives. Copy files over SSH, push a Docker image to registry, or do some help deployment. On top, add config files for third-party tools, like Renovate. Renovate, by the way, is a tool for automated dependency update. We use it a lot, and always get a merge request when some library we use becomes outdated. We must go through all these setup steps for every project, and every time there are some tiny differences. Some one-line changes in CI jobs that are copy-pasted from project to project. Then there is a separate tool for quality scan, SonaCube, and it also needs integration in the pipeline. Patients you must have to finish the project setup. As we got a requirement to add security scans to all our projects, we came to a conclusion. As security grows exponentially, we need to change something. As we looked at CI templates, a new hope arose. We thought, what if we don't adapt our existing flow, but create something from scratch? What would our dream solution be like? It would be easy to use. Transparent and clear from the first sight. Flexible and extendable. Consistence throughout the company. Improving security of our products. Allowing every developer to contribute. Gathering all scanning tools in one place. And speeding up our setup process. Our Jedi masters used the force, evaluated the options, and decided to go with GitLab. First question, as always, is, where do we begin? Create a repository for the templates. No need to reinvent the wheel. Check out the templates from GitLab. How everything is organized and structured. We went in the same direction. We have individual folders for separate drops and for product-specific drops. For example, if we are working with some specific CMS, all jobs related to it will be separated. And we have complete pipelines that can be taken into project as is. The project visibility is internal. Every logged in user must be able to include the pipelines. And this is exactly what internal visibility does. Our repository has two branches, latest and stable. Stable being the default. The development occurs in latest branch, so the jobs there might be buggy or not yet tested. However, if someone wants to take a risk, there's always a possibility to include the job from a specific branch. When everything is tested and ready to go live, we merge the latest branch into stable and the job becomes generally available. You see two examples how we can include a job from a default stable branch or its version from latest. If we were about to test the latest changes in our build job, we would use the second one. Let's dive into some examples how to write job templates. The job you see does a build over Node.js project. It is executed in build stage, uses Docker image of Node as a base image, defines some variables and cache. The build itself is performed with yarn, which is a part of Node base image. There are some points I want to pay attention to. The customizable parts are taken out into variables. If someone includes this job into their pipeline, they will be able to set another Node version, just with a variable without the need to redefine the job. For the same reason of customization, don't use before script and after script. We leave our developers the possibility to add some behavior to this job in their projects. Use default stages where possible, build, test or deploy or document which stages need to be defined for this job to work. Here is another job that calls Semantic Release to release a new version of our application. Release means changing the version in the package JSON, committing it to the branch and creating a Git tag. So this tool needs right access to our repository and the access token is configured with a variable GitLab token. Now, we cannot provide any default value for it. So this variable must be defined by the user in their project. Our jobs check, first of all, if the user defined it. The error message should tell exactly what the job expects. Consider it a node to your future self when you're using your own template and it kindly guides you through the setup. See here in the script, if the variable is missing, the error message says, create a project access token with scope write repository and add it to a CI variable GitLab token. How can it get more specific? Now that we agreed on how to write individual jobs, let's think about what jobs to define. The easiest approach is to take a project that has a huge pipeline with a lot of jobs. Identify which jobs can be used in other projects, what is the common denominator of the projects of this kind, and then extract the jobs to the templates one by one. If we were writing the template library from scratch, we could have just imagined which jobs might be useful. But since we already have some pipelines, we take them as a guideline. What do we usually need in our projects? Another important point to agree on is a naming convention. When your library grows, you should be able to just look at the name and have the idea of what the job does. You see our job names as example. So it's pretty obvious that GitLab release creates a GitLab release and that MavenBuild does the build for Maven project. I'm not insisting this convention is a silver bullet. If you find a better approach, use it and let us know in the chat what are your thoughts on the naming. When you have your building blocks, it's time to assemble a complete pipeline. This one is a babes pipeline for our Maven projects. Include your jobs, include security scans and define the stages that your jobs need. Remember we made the jobs configurable with variables? Security scans are configurable in the same way. Add the necessary variables into your CI file and you're ready to go. The base pipeline for a different technology will look almost the same. There was a Maven pipeline on the previous slide and this one is for Node.js. The only difference are the stages. So the jobs are different and they require different stages. Cache definition and two repository versus Node modules and security scans configuration. These pipelines will be used as base for all the project. So we give them as generic as possible. They have the minimum necessary jobs to build and scan the project for the selected technology. What if I told you that a CI pipeline can have an Easter egg? That's right, Pikachu is excited that the tests passed. We output this ASCII art after the test job was successful. The picture is an instance-wide file variable and we output it with a utility that adds some colors to it. In the after-script section, a variable CI job status is available. So we check if the tests really passed and let the Pikachu out only if there were no errors. I'll show you the code quickly. We won't go through every line of it. You can check out the slides after my talk. The only thing I want to mention, we use reference tags that were introduced in GitLab 13.9. The actual code to output the picture is stored in a separate file and there are two reasons for that. First, we did that to hide the Easter egg, to make it not that obvious for those who include the test job into their pipeline. A big command in the after-script would catch the eye and a reference to some mysterious test helper would not. Second, there are different test jobs for Node, Maven, Gradle. Reference tags exclude duplication and made the code look much cleaner. The template library has already become big and powerful. Can we improve it even more? Code quality. Code quality scan in GitLab uses code climate under the hood. If you check out GitLab's template, you'll get the idea how it is working. And you will notice that GitLab defines default config for code quality scan. We wanted to build our own theme park, so we created a project with these defaults. We zip the files and upload the archive to a package registry. In our CI library, we define the template that adds some behavior to the standard code quality. The before-script section of this code quality drop is described in this template. We download the zip with defaults from the package registry and put the files where GitLab expects them to be. So this is how we override the default code quality rules. Again, some code for reference so that you could check it out later. Look at the before-script. We download the artifacts with widget and to access package registry of the project with defaults. We defined a project access token and stored it as an instance variable. The idea of this project is an instance variable as well. So the users do not even need to know we've configured something custom to get in the defaults. Another code quality perk is the visual HTML report. To get it, you need to extend the code quality drop, which in our case already uses the customized defaults. Set the report format to HTML with the environment variable and deploy it to GitLab pages. So GitLab pages deployment is another drop that has to be coupled with this visual code climate report generation. And we execute these drops only in default branch. No code snippets here because these are exactly the steps described in GitLab documentation. We just wrap these drops into our own template. And last but not least, linting. Again, we saw how GitLab are doing it. And found it an amazing idea. We just put the lint config file into the root of the repository and add the linting job to the pipeline. To the pipeline of the CI template library. Linting job fails if the formatting is not consistent throughout the template library. Everything looks clean and organized. So what have we achieved? We created project templates. And the CI file in a template contains only three lines of code. It just includes the base pipeline from the template library. And it is already a fully functioning pipeline with all necessary scans. Apart from that, we added code owners template, the configs for code climate and renovate and other project specific files like POM, XML, Gradle build or package JSON. It's not a typo in the talk title and not a typo in the slide. The setup is really done automagically. The CI file is really small and references a well-tested pipeline from the library. All scans are already configured and ready to use. Configuration files are in place. The setup is configurable and extendable and easy to contribute. And the cherry on the cake, we renounced Sonacube and other third-party scanning tools. Everything is done now with GitLab. Security scans have become a part of any small change. We achieved consistency in the processes. Without consistency, we couldn't measure deviation. Now we can track the exact changes in security score in every commit and eliminate the vulnerabilities early. Security dashboard gives a great overview of the dynamics. We can see how we're progressing with security fixes throughout the time. Since we didn't have security scans earlier, we got a full report and had to clean up some of our dependencies and Docker images to remove critical vulnerabilities. Our overall confidence in the code has increased. GitLab shows all new vulnerabilities and code smells directly in the merge request. So the reviewers can instantly see if there's more to be done before the merge. We use almost all available scans, but in this example, I'll show you the default ones that we included in our Node.js-based projects. We used SEST, static application security testing, dependency scanning, and secret detection in all Node-based projects. Here is a screenshot from our recent merge request. You see developers dismissed some detected vulnerabilities for one or another reason. But the rest needs to be dealt with and secret scanning detected. No issues. Yay. But the majority of our merge requests looks now like this. All clean, green, and ready to be merged. And all this analysis comes now out of the box from our template library. It automatically appears in every merge request in every project and helps enormously during the code review. I also want to mention Docker container scanning, even though it is not a part of the base pipelines. We use it only in the projects that are shipped as Docker images and include this scan together with a job to build the image itself. When we first scanned our Docker-based projects, we were quite surprised about the amount of its output. After we carefully analyzed what base images we use, it turned out it's quite easy to fix the half of the detected vulnerabilities by just changing the base image. I must say it's a great feeling to confirm the vulnerabilities remediated and to just dismiss it. Not only we added so many security scans, but we also decreased time to set up a new project from days to minutes. The overall quality and the confidence in our setup improved dramatically. And developers are really enjoying working with CI template library. Please do not hesitate to contact me if you have any questions or if you just want to talk about GitLab and CI templates. I'll be happy to chat. So thank you and may the force be with you.