<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris Schindlbeck</title>
    <description>The latest articles on DEV Community by Chris Schindlbeck (@cschindlbeck).</description>
    <link>https://dev.to/cschindlbeck</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1162966%2F6c7b00cb-cd8b-40c7-ac4c-802e36474736.jpeg</url>
      <title>DEV Community: Chris Schindlbeck</title>
      <link>https://dev.to/cschindlbeck</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cschindlbeck"/>
    <language>en</language>
    <item>
      <title>Automate Gitlab Repository Settings with Terraform</title>
      <dc:creator>Chris Schindlbeck</dc:creator>
      <pubDate>Sat, 13 Jul 2024 08:32:50 +0000</pubDate>
      <link>https://dev.to/cschindlbeck/gitlab-repository-manager-1056</link>
      <guid>https://dev.to/cschindlbeck/gitlab-repository-manager-1056</guid>
      <description>&lt;p&gt;This guide shows an example on how to automate GitLab settings with Terraform.&lt;/p&gt;

&lt;p&gt;Fork the &lt;a href="https://github.com/cschindlbeck/gitlab_repo_manager" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and use it as a template to start adapting it for your organization!&lt;/p&gt;

&lt;p&gt;You can extend this for various other automation tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasoning and Advantages of this Approach
&lt;/h2&gt;

&lt;p&gt;Are you responsible in your organization for a complex project with many repositories? Are you tired of going through all repositories manually and do such tasks as adding/removing users and setting merge permissions?&lt;/p&gt;

&lt;p&gt;By following this guide, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save Time: Automate repetitive tasks and focus on what truly matters.&lt;/li&gt;
&lt;li&gt;Reduce Errors: Minimize human errors with consistent automation scripts.&lt;/li&gt;
&lt;li&gt;Improve Productivity: Streamline your workflow and enhance team collaboration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide exemplifies how to leverage Terraform to automate branch protection permissions in GitLab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fictitious example
&lt;/h2&gt;

&lt;p&gt;In this example, branch protection rules for two fictitious teams (backend and frontend) with different repositories respectively, are automated.&lt;/p&gt;

&lt;p&gt;The repositories hosted on GitLab and each teams requires specific branch protection rules. The frontend team handles solely frontend repos, and the backend team handles the backend repos.&lt;/p&gt;

&lt;p&gt;To get a rough idea, this table summarizes what we want to achieve automatically&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiavaxtmo3pkxjrxamj1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiavaxtmo3pkxjrxamj1.png" alt="MergeStrategyTable" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step Explanation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initial Setup
&lt;/h3&gt;

&lt;p&gt;Security first, so export your Gitlab PAT (private access token) via the command line, by setting an environment variable with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;$TF_VAR_gitlab_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOURTOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in order to avoid exposing sensitive information in your git repo (put it in your .bashrc/.zshrc if you do not want to do this each time you open a terminal). This environment variable is then accessible in HCL (Terraform's own programming language) via &lt;code&gt;var.gitlab_token&lt;/code&gt; (make sure you give at least repo_read, repo_write permissions for the PAT).&lt;/p&gt;

&lt;p&gt;Now we can add the &lt;a href="https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs" rel="noopener noreferrer"&gt;Gitlab provider&lt;/a&gt; to enable Terraform to communicate with Gitlab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;gitlab&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gitlabhq/gitlab"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"17.1.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"gitlab_token"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"gitlab"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://gitlab.iav.com/api/v4"&lt;/span&gt;
  &lt;span class="nx"&gt;token&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gitlab_token&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize the terraform directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which will download the necessary code for communication with the Gitlab API in a .terraform directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get a list of frontend and backend repositories
&lt;/h3&gt;

&lt;p&gt;Then, we must obtain a list of all frontend and backend repositories. For simplicity, we assume that these repositories (in Gitlab called "projects") are found in the same directory (in Gitlab called "group").&lt;/p&gt;

&lt;p&gt;Enter the path to the group in the next block and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Specify the path to your group&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"gitlab_group"&lt;/span&gt; &lt;span class="s2"&gt;"group"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;full_path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;YOUR_PATH_TO_YOUR_GROUP&amp;gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Filter repositories for the frontend&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"gitlab_projects"&lt;/span&gt; &lt;span class="s2"&gt;"frontend_projects"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;group_id&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gitlab_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;order_by&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt;
  &lt;span class="nx"&gt;include_subgroups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;search&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"frontend"&lt;/span&gt; &lt;span class="c1"&gt;# filter out repos containing the word 'frontend'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Filter repositories for the backend&lt;/span&gt;
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"gitlab_projects"&lt;/span&gt; &lt;span class="s2"&gt;"backend_projects"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;group_id&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gitlab_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;order_by&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"name"&lt;/span&gt;
  &lt;span class="nx"&gt;include_subgroups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;search&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"backend"&lt;/span&gt; &lt;span class="c1"&gt;# filter out repos containing the word 'backend'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These so-called data resources will obtain the current information of the repositories and store them in the terraform.tfstate file. By specifing a search field, we can obtain only the repos that contain a certain word, here front- and backend. This makes them accessible via &lt;code&gt;data.gitlab_projects.frontend_projects.projects&lt;/code&gt; and &lt;code&gt;data.gitlab_projects.backend_projects.projects&lt;/code&gt; so that we can change the settings there accordingly. Note that this will only work if the repos adhere to a certain naming scheme, here they must include the words frontend or backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Specify who is admin or dev
&lt;/h3&gt;

&lt;p&gt;Now, let's define who is a backend and a frontend admin or developer, starting with the frontend admins.&lt;/p&gt;

&lt;p&gt;You can get the IDs by searching for the person in Gitlab and right-clicking the three dots on the right to copy their ID.&lt;/p&gt;

&lt;p&gt;Here, we set a list of frontend admins&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"frontend_admins"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of frontend admin ids"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's repeat the same for the remaining ones with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"frontend_devs"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of frontend dev ids"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;182&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"backend_admins"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of backend admin ids"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;713&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"backend_devs"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of backend dev ids"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;767&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;152&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Protect branches
&lt;/h3&gt;

&lt;p&gt;Finally we can set our branch protection rules for all the repositories in an automated way.&lt;/p&gt;

&lt;p&gt;Let's start with protecting the master branch of the frontend repositories, by including this block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"gitlab_branch_protection"&lt;/span&gt; &lt;span class="s2"&gt;"frontend_master_protection"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gitlab_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projects&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;allow_force_push&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;code_owner_approval_required&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;branch&lt;/span&gt;                       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"master"&lt;/span&gt;
  &lt;span class="nx"&gt;push_access_level&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"no one"&lt;/span&gt; &lt;span class="c1"&gt;# do not push to master directly&lt;/span&gt;
  &lt;span class="nx"&gt;merge_access_level&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"no one"&lt;/span&gt; &lt;span class="c1"&gt;# we will specify who can push below&lt;/span&gt;
  &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"allowed_to_merge"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_admins&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allowed_to_merge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's explore this large block in more detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;for_each&lt;/code&gt;: We loop over all our frontend repositories that we gathered in the data block previously&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allow_force_push&lt;/code&gt;/&lt;code&gt;code_owner_approval_required&lt;/code&gt;: Allow force push by the admins/Require code owner approval&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;push_access_level&lt;/code&gt;/&lt;code&gt;merge_access_level&lt;/code&gt;: Set level of push/merge access (no one, developer, maintainer, owner), we allow no role here, but individual accounts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowed_to_merge&lt;/code&gt;: We loop over all frontend admins for merge rights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We set levels to &lt;code&gt;no one&lt;/code&gt; in this example because backend and frontend devs might both be classified as developer but we want only to include the ones responsible for their part.&lt;/p&gt;

&lt;p&gt;Now, we can do the same for the dev branch&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"gitlab_branch_protection"&lt;/span&gt; &lt;span class="s2"&gt;"frontend_dev_protection"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gitlab_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projects&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;allow_force_push&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;code_owner_approval_required&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;branch&lt;/span&gt;                       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="nx"&gt;push_access_level&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"developer"&lt;/span&gt; &lt;span class="c1"&gt;# here, let's allow every developer to push, regardless of front- or backend&lt;/span&gt;
  &lt;span class="nx"&gt;merge_access_level&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"no one"&lt;/span&gt;    &lt;span class="c1"&gt;# we will specify who can push below&lt;/span&gt;
  &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"allowed_to_merge"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_admins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_devs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# union over devs and admins&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allowed_to_merge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"allowed_to_push"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;distinct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_admins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frontend_devs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# union over devs and admins&lt;/span&gt;
    &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;allowed_to_push&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We follow the same approach as for the master branch with a few differences for the dev branch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allow_force_push&lt;/code&gt;/&lt;code&gt;code_owner_approval_required&lt;/code&gt;: We disallow force push for anyone here&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowed_to_push&lt;/code&gt;/&lt;code&gt;allowed_to_merge&lt;/code&gt;: We loop over the union of frontend admins and devs to let them have push/merge rights (admins should be able to merge/push too, right?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have done this for the frontend repos, we can do this in an analagous fashion for the backend repos by changing only &lt;code&gt;frontend_projects&lt;/code&gt; to &lt;code&gt;backend_projects&lt;/code&gt; and &lt;code&gt;frontend_admins&lt;/code&gt; and &lt;code&gt;frontend_devs&lt;/code&gt; to &lt;code&gt;backend_admins&lt;/code&gt; and &lt;code&gt;backend_devs&lt;/code&gt;, such as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt;                     &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gitlab_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backend_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projects&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
    &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;distinct&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backend_admins&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backend_devs&lt;/span&gt;&lt;span class="err"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# union over devs and admins&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can take a look at the entire code &lt;a href="https://github.com/cschindlbeck/gitlab_repo_manager" rel="noopener noreferrer"&gt;here&lt;/a&gt;, or adapt the settings to your preferences/organizational process.&lt;/p&gt;

&lt;p&gt;Now we have every set up to make the changes readily availabe in GitLab.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;Finally, we can apply our changes via&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Carefully look through the upcoming changes and confirm with &lt;code&gt;yes&lt;/code&gt; if you are sure everything is set correctly.&lt;/p&gt;

&lt;p&gt;Attention: if you have already set up your repos (and settings) in Gitlab, this will fail as Terraform will complain that the resources already exist. In this case, you will need to import the current state to your terraform.tfstate first, so that terraform is able to manage this.&lt;/p&gt;

&lt;p&gt;You can do this for each project you want to import via&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform import gitlab_project.gitlab_repo_manager &amp;lt;project_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or, alternatively, for more complex projects, check out &lt;a href="https://github.com/GoogleCloudPlatform/terraformer" rel="noopener noreferrer"&gt;terraformer&lt;/a&gt;, a CLI tool to import/update your tfstate from existing infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This guide walked you through an example on how to set up branch protection in multiple Gitlab repos automatically via Terraform. You can take this example as a starting point on how to automate much more settings in Gitlab repos, such as setting the preferred merge method, tag protection, branch rules and much more! &lt;/p&gt;

&lt;p&gt;If you host your repos on GitHub you can take this example as a template and take the structure and adapt it step-by-step for the &lt;a href="https://registry.terraform.io/providers/integrations/github/latest/docs" rel="noopener noreferrer"&gt;GitHub provider&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The days are numbered where you had to do this manually for (countless) repos in a complex project for every subteam. Embrace the mighty tooling capabilities of Terraform!&lt;/p&gt;

&lt;p&gt;Bonus: Check out how to set the preferred merge method (the only correct answer is fast-forward only, right?) in my &lt;a href="https://github.com/cschindlbeck/gitlab_repo_manager" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>gitlab</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>🚀 Simplify Your Linux Process Killing with a Fuzzy Process Killer 🚀</title>
      <dc:creator>Chris Schindlbeck</dc:creator>
      <pubDate>Fri, 05 Jul 2024 11:23:01 +0000</pubDate>
      <link>https://dev.to/cschindlbeck/simplify-your-linux-process-killing-with-a-fuzzy-process-killer-3icj</link>
      <guid>https://dev.to/cschindlbeck/simplify-your-linux-process-killing-with-a-fuzzy-process-killer-3icj</guid>
      <description>&lt;p&gt;Are you tired of sifting through numerous processes to identify and terminate them by looking up their PIDs?&lt;/p&gt;

&lt;p&gt;Use this lightweight script function that leverages the power of fzf (a command-line fuzzy finder) to streamline the process of identifying and killing processes. Quickly locate and kill processes without memorizing PIDs!&lt;/p&gt;

&lt;p&gt;How does it work?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Process Listing: It lists all running processes with their PIDs and command names.&lt;/li&gt;
&lt;li&gt;Fuzzy Search: You can then use fzf to quickly filter and find the process you're looking for.&lt;/li&gt;
&lt;li&gt;Kill Command: Once selected, it safely terminates the process with kill -9.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copy the code into your .bashrc/.zshrc from this github gist and give it a try (fzf must be installed of course)!&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://gist.github.com/cschindlbeck/db0ac894a46aac42861e96437d8ed763"&gt;https://gist.github.com/cschindlbeck/db0ac894a46aac42861e96437d8ed763&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terminal</category>
      <category>bash</category>
      <category>zsh</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
