<?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>Forem: Jeiman Jeya</title>
    <description>The latest articles on Forem by Jeiman Jeya (@jei).</description>
    <link>https://forem.com/jei</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%2F163735%2Fd4077ce9-d94d-4655-94d0-68503953a9ff.jpeg</url>
      <title>Forem: Jeiman Jeya</title>
      <link>https://forem.com/jei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jei"/>
    <language>en</language>
    <item>
      <title>🎯 🚀 The Ultimate Guide to Software Engineering, Zombie Apocalypse Style</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Thu, 06 Apr 2023 05:56:42 +0000</pubDate>
      <link>https://forem.com/jei/the-ultimate-guide-to-software-engineering-zombie-apocalypse-style-1o41</link>
      <guid>https://forem.com/jei/the-ultimate-guide-to-software-engineering-zombie-apocalypse-style-1o41</guid>
      <description>&lt;p&gt;This guide presents a comprehensive set of rules for software engineering inspired by the movie Zombieland. The rules are not simply a list of arbitrary guidelines, but rather a carefully crafted set of principles that are designed to promote efficiency and effectiveness in software development. By drawing inspiration from the movie, these principles are not only practical but also engaging and memorable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rules in Zombieland
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rule #1: &lt;strong&gt;Cardio&lt;/strong&gt; - Keep your code lean and agile to ensure quick and efficient processing.&lt;/li&gt;
&lt;li&gt;Rule #2: &lt;strong&gt;Double Tap&lt;/strong&gt; - Test your code thoroughly to ensure it's not just "undead" but truly dead before moving on.&lt;/li&gt;
&lt;li&gt;Rule #3: &lt;strong&gt;Beware of Bathrooms&lt;/strong&gt; - Be cautious when accessing sensitive parts of the codebase, such as login or payment processing modules.&lt;/li&gt;
&lt;li&gt;Rule #4: &lt;strong&gt;Seat belts&lt;/strong&gt; - Always use version control and back up your codebase regularly to safeguard against crashes and data loss.&lt;/li&gt;
&lt;li&gt;Rule #7: &lt;strong&gt;Travel light&lt;/strong&gt; - Avoid bloated software by minimising dependencies and optimising code for performance.&lt;/li&gt;
&lt;li&gt;Rule #8: &lt;strong&gt;Kill Efficiently&lt;/strong&gt; - Identify and fix bugs quickly and efficiently to prevent them from spreading and causing more harm.&lt;/li&gt;
&lt;li&gt;Rule 9: &lt;strong&gt;A club does not have to be reloaded&lt;/strong&gt; - Automate repetitive tasks to increase productivity and reduce errors.&lt;/li&gt;
&lt;li&gt;Rule 10: &lt;strong&gt;Don't make any noise&lt;/strong&gt; - Keep your code clean and organised to make it easier to understand and maintain.&lt;/li&gt;
&lt;li&gt;Rule 15: &lt;strong&gt;Keep an exit free&lt;/strong&gt; - Plan for scalability and flexibility in your code to allow for future changes and updates.&lt;/li&gt;
&lt;li&gt;Rule #17: &lt;strong&gt;Don't be a Hero&lt;/strong&gt; - Don't try to reinvent the wheel. Use proven software engineering patterns and best practices to avoid common pitfalls.

&lt;ul&gt;
&lt;li&gt;Rule #17: &lt;strong&gt;Be a Hero&lt;/strong&gt; - Occasionally, taking calculated risks and thinking outside the box can lead to innovative solutions and advancements.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Rule #18: &lt;strong&gt;Limber up&lt;/strong&gt; - Stay up-to-date with the latest technologies and tools to remain competitive in the industry.&lt;/li&gt;
&lt;li&gt;Rule #22: &lt;strong&gt;When in Doubt, Know Your Way Out&lt;/strong&gt; - Have a plan in place for handling unexpected errors and failures.&lt;/li&gt;
&lt;li&gt;Rule #23: &lt;strong&gt;Ziploc™ Bags&lt;/strong&gt; - Protect sensitive data and prevent breaches by implementing robust security measures.&lt;/li&gt;
&lt;li&gt;Rule #31: &lt;strong&gt;Check the Back Seat&lt;/strong&gt; - Don't forget to review and test all aspects of your code, including less frequently used features.&lt;/li&gt;
&lt;li&gt;Rule #32: &lt;strong&gt;Enjoy the little things&lt;/strong&gt; - Take time to celebrate small successes and accomplishments throughout the software development process.&lt;/li&gt;
&lt;li&gt;Rule #36: &lt;strong&gt;Sunscreen&lt;/strong&gt; - Protect your eyes and health by taking breaks and practising good ergonomics while coding.&lt;/li&gt;
&lt;li&gt;Rule #42: &lt;strong&gt;Keep your hands to yourself&lt;/strong&gt; - Follow coding standards and respect the work of your colleagues to maintain a positive and efficient work environment.&lt;/li&gt;
&lt;li&gt;Rule #52: &lt;strong&gt;Don't be afraid to ask for help&lt;/strong&gt; - Seek advice and guidance from more experienced developers to learn and grow in your career.&lt;/li&gt;
&lt;li&gt;Rule #53: &lt;strong&gt;Wet naps&lt;/strong&gt; - Clean up messy code and fix technical debt regularly to maintain a healthy and sustainable codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This guide presents a unique and engaging set of principles for software engineering inspired by the movie Zombieland. By following these rules, software developers can improve the efficiency, effectiveness, and quality of their work. The rules cover a wide range of topics, from testing and security to teamwork and innovation. Whether you're a seasoned developer or just starting out, the principles presented in this guide can help you succeed in the challenging and dynamic world of software engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zombieland.fandom.com/wiki/Zombieland_Rules"&gt;Zombieland Rules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Best Practices for Building Multi-Cloud Modules in Terraform</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Wed, 05 Apr 2023 12:32:32 +0000</pubDate>
      <link>https://forem.com/jei/best-practices-for-building-multi-cloud-modules-in-terraform-1l56</link>
      <guid>https://forem.com/jei/best-practices-for-building-multi-cloud-modules-in-terraform-1l56</guid>
      <description>&lt;p&gt;Organisations today are increasingly adopting cloud services from different providers to meet their business needs. However, managing multi-cloud infrastructure can be challenging, especially when it comes to infrastructure management, which is where Terraform comes in. With Terraform, you can utilise modules to build a comprehensive, multi-cloud configuration.&lt;/p&gt;

&lt;p&gt;In this post, we will cover the best practices for creating Terraform module configuration that is robust and reusable for large-scale, multi-cloud architecture. With this knowledge, you can confidently build and deploy infrastructure with ease.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Gold Standard - Best Practices for Building Cloud/Multi-Cloud Modules
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build modules to be extremely and easily reusable.&lt;/li&gt;
&lt;li&gt;Create cloud-agnostic modules that support AWS and Azure for multi-cloud architecture.&lt;/li&gt;
&lt;li&gt;Avoid hard-coded or semi-hard-coded values at the module level; instead, use input arguments.&lt;/li&gt;
&lt;li&gt;Use conditional expressions and feature toggles to create comprehensive and flexible modules.&lt;/li&gt;
&lt;li&gt;Group common resources into the same folders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Foundation - The Folder Structure
&lt;/h2&gt;

&lt;p&gt;It all starts with the folder structure. How we structure it will determine how we can further automate our IaC workflows.&lt;/p&gt;

&lt;p&gt;The folder structure can be broken down into 2 sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modules:&lt;/strong&gt; Allows you to create logical abstractions on top of a set of resources. In other words, it lets you group resources together and reuse this group later, possibly multiple times. Once you create these modules, they become “child modules”, which can then be referenced in configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patterns:&lt;/strong&gt; These are repeated configuration files that derive from defining child modules. They are also referred to as “root modules”.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The photo above depicts a Terraform module grouping resources together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Philosophy on grouping similar and common resources into the same folders
&lt;/h3&gt;

&lt;p&gt;It's best to store resources that share a common infrastructure resource category in the same folder. For example, consider all elements of networking, such as VPCs, subnets, security groups/firewalls, network security groups, load balancers, key vaults, and secrets. All of these either belong to the same underlying cloud category or they form the foundation of your cloud architecture. To keep things organized, it's recommended to group all of these resources in a folder labelled "foundation". As the name implies, they are the essential building blocks for any cloud architecture you set up for a company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case example:&lt;/strong&gt; Your company needs to set up the foundation for your cloud architecture and at the same time create a Kubernetes cluster with various node pools and settings that does a dependency reference of the foundation resources. This is followed by creating SQL databases, blob storages/S3 buckets, and more that will be used across the company. There are plans to introduce future projects that may not have the same folder structure as the current ones but will reside in a separate folder that uses the same Terraform modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;IaC stages&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;These folders can be called "stages" because we need to create certain resources in a specific order. Therefore, stages have sequences, which are like orchestration steps. You need to execute items 1 to 10 in a particular order. Folder prefixes can be addressed as &lt;code&gt;{sequence}_{stage}&lt;/code&gt;. They correspond to the following structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sequence&lt;/code&gt; - order of which to implement the Terraform resources - 01, 02, 03&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stage&lt;/code&gt; - corresponds to the infrastructure category - foundation, common, kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, the folders can be organised in the following manner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;01_foundation&lt;/code&gt; - contains all networking resources, followed by load balancers, CDNs, key vaults, and secrets&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;02_kubernetes&lt;/code&gt; - contains all Kubernetes-related resources that does a dependency reference to networking resources from the &lt;code&gt;01_foundation&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;03_common&lt;/code&gt; - contains all the “common” resources that are usually created in any tech company - S3 buckets, blob storages, NoSQL databases, SQL databases, and more&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;04_custom_project_name&lt;/code&gt; - contains custom resources that need to be isolated for better management on special or custom projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With stages, you can expand the folders to meet your engineering needs for provisioning new resources that are tied to a specific project. This allows teams to group resources together in the same folder, resulting in quicker execution of Terraform commands and faster results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual representation of the folder structure for AWS Cloud
&lt;/h3&gt;

&lt;p&gt;The visual representation below depicts the idea behind structuring your Terraform configuration into a "patterns" folder. As mentioned above, a "patterns" folder contains Terraform configurations that are repeated and injected into child modules for use. With this approach, you can create several of the same resources with different naming conventions and settings to meet your technical requirements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;patterns&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;iac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
     &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;          
       &lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="nx"&gt;_foundation&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
       &lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="nx"&gt;_kubernetes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;eks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="p"&gt;.....&lt;/span&gt;
       &lt;span class="mi"&gt;03&lt;/span&gt;&lt;span class="nx"&gt;_common&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;rds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
       &lt;span class="p"&gt;.....&lt;/span&gt; 
   &lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
     &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
       &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
           &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
           &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
         &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
           &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
           &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
       &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
      &lt;span class="p"&gt;....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The folder structure mentioned above is just the beginning. We will further expand on this structure later in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Modularity - Building modules to be re-usable
&lt;/h2&gt;

&lt;p&gt;To build a robust child module that can be reused multiple times without manipulation, start your design process from the root module. The role of a child module is to simply process input arguments and create the necessary resources. However, some teams have needed to create custom child modules for specific requirements, which can cause problems later on. Improving the functionality of a child module in this design pattern can affect existing resources created. This issue can be easily avoided if you appropriately create those data properties/objects in the root module.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 1 - Use conditional expressions and feature toggles from the beginning
&lt;/h3&gt;

&lt;p&gt;Regardless of the outcome of your overall IaC configuration for your company, always keep the "feature toggle" concept in mind when building your modules from the beginning. This means creating resources with a toggle switch, which provides flexibility in deleting and re-creating said resources easily from a root module instead of a child module. Your child module can also have feature toggles, but they should use conditional expressions in combination with the root module.&lt;/p&gt;

&lt;p&gt;For example, suppose you need to create two different types of S3 buckets: one with public access and the other with private access. You can use the following feature toggle logic in your root module, and a conditional expression in the child module.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root module&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Root&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;project-zeus-s3-bucket-public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./aws/aws-s3-bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-app-bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;is_private&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;project-zeus-s3-bucket-private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./aws/aws-s3-bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private-app-bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;is_private&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Child module&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_s3_bucket_acl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bucket_acl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&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;acl&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;is_private&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;private&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-read&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we’re parsing in the &lt;code&gt;is_private&lt;/code&gt; argument from the root module and the child module is performing a conditional expression check to see if the boolean value is set to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; accordingly. With that condition, we will set the Access Control List for the bucket to either &lt;code&gt;private&lt;/code&gt; or &lt;code&gt;public&lt;/code&gt; accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method 2 - Parsing all data from the root module into the child module
&lt;/h3&gt;

&lt;p&gt;Imagine your child module is designed to only receive orders from the root module and simply create resources without manipulating the data. However, you can still achieve the same outcome as above by parsing all argument data types from the root module. The child module can then interpret the data types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Root module&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Root&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s3-bucket-public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./aws/aws-s3-bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;bucket_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-app-bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;is_private&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;acl&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-read&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;policy&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;policy.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;website&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;index_document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;error_document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="nx"&gt;routing_rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;EOF&lt;/span&gt;
      &lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Condition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;KeyPrefixEquals&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;docs/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Redirect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ReplaceKeyPrefixWith&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;documents/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;EOF&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Child module&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Child&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;....&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bucket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;policy&lt;/span&gt;

  &lt;span class="nx"&gt;website&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;index_document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index_document&lt;/span&gt;
    &lt;span class="nx"&gt;error_document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error_document&lt;/span&gt;
    &lt;span class="nx"&gt;routing_rules&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routing_rules&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_s3_bucket_acl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bucket_acl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&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;acl&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;acl&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To summarise, any of these approaches will suffice to ensure that your child modules are reusable on a large scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Jack of All Trades - Building an IaC stack to be Cloud-agnostic
&lt;/h2&gt;

&lt;p&gt;By following the aforementioned steps and methods, your organisation can easily adopt a multi-cloud architecture. As previously mentioned, it's the structure of your folders that enables this approach. You still adhere to the same common resources folder concept as mentioned above and simply create new folders for each cloud provider you would like to adopt in your IaC stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Root module: visual representation&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
  &lt;span class="nx"&gt;patterns&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;iac&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
       &lt;span class="mi"&gt;01&lt;/span&gt;&lt;span class="nx"&gt;_foundation&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
          &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
        &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;secrets&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;azure&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
        &lt;span class="nx"&gt;az&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;az&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;az&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;az&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
        &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;cdn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
            &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;management&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Child module: visual representation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
       &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
          &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
              &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
           &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
              &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
    &lt;span class="nx"&gt;azure&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
       &lt;span class="nx"&gt;azure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;vnet&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
          &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
              &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
           &lt;span class="nx"&gt;azure&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
              &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
          &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tf&lt;/span&gt;
    &lt;span class="p"&gt;.....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it's easy to adopt any cloud provider of your choice into your IaC stack if the folders are structured properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Folder breakdown
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Patterns&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;iac&lt;/code&gt; - represents Terraform&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt; - represents the environment you’re provisioning the resources in. You may have entirely different resources for &lt;code&gt;uat&lt;/code&gt; and &lt;code&gt;prod&lt;/code&gt; environments. Therefore it’s best to keep them separate for feasibility.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;01_stage&lt;/code&gt; - the common resource folders for your root modules to share&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[provider-resource].tf&lt;/code&gt; - containing all of your root modules for that infrastructure category&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Automaton - Build a single multi-cloud, multi-environment pipeline
&lt;/h2&gt;

&lt;p&gt;Based on the discussion above, we can now build a robust and modular pipeline to support running Terraform on any cloud provider and environment. In this example, we'll be using Azure DevOps. However, the same principles can be applied to any CI/CD toolset.&lt;/p&gt;

&lt;p&gt;To cater to a multi-cloud and multi-environment architecture, it's best to build a modular and reusable pipeline. This involves creating a parent pipeline that invokes a template pipeline to execute Terraform commands using template parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parent pipeline
&lt;/h3&gt;

&lt;p&gt;With a parent pipeline, you can define all the values and content that need to be parsed into the template or child pipeline as recognised input arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# iac automation - multi-stage ci-cd pipeline&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(BuildDefinitionName)-$(Build.BuildId)-$(date:yyyyMMdd)$(rev:.r)&lt;/span&gt;

&lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vmImage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ubuntu-latest"&lt;/span&gt;

&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iacEnvironment&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IAC Environment (test, prod)&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;prod&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloudProvider&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cloud Provider (aws, azure)&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;azure&lt;/span&gt;

&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../../variables/generic-variables.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${{ if eq(parameters.iacEnvironment, 'test') }}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../../variables/test-variables.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${{ if eq(parameters.iacEnvironment, 'prod') }}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../../variables/prod-variables.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../../variables/foundation-variables.yml&lt;/span&gt;

&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;azure-devops/iac/pipelines/01-foundation-pipeline.yml"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terraform/patterns/iac/test/aws/01_foundation/**"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terraform/patterns/iac/test/azure/01_foundation/**"&lt;/span&gt;

&lt;span class="na"&gt;pr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;planning_stage&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Planning&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../../templates/planning-template.yml&lt;/span&gt;
        &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;terraformarguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
            &lt;span class="s"&gt;$(terraformarguments)&lt;/span&gt;
          &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ parameters.iacEnvironment }}&lt;/span&gt;
          &lt;span class="na"&gt;sequence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(sequence)&lt;/span&gt;
          &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(stage)&lt;/span&gt;
          &lt;span class="na"&gt;cloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ parameters.cloudProvider }}&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deployment&lt;/span&gt;
    &lt;span class="na"&gt;dependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;planning_stage&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;and(succeeded('planning_stage'))&lt;/span&gt;
    &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../../templates/deployment-template.yml&lt;/span&gt;
        &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;terraformarguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
            &lt;span class="s"&gt;$(terraformarguments)&lt;/span&gt;
          &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ parameters.iacEnvironment }}&lt;/span&gt;
          &lt;span class="na"&gt;sequence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(sequence)&lt;/span&gt;
          &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$(stage)&lt;/span&gt;
          &lt;span class="na"&gt;cloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ parameters.cloudProvider }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parent pipeline breakdown
&lt;/h3&gt;

&lt;p&gt;The goal is to create a single pipeline that can achieve a multi-cloud and multi-environment approach to running Terraform commands. However, there may be edge cases where you need to define separate pipelines for each environment. In the example above, we're using a single pipeline approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: This post will not go into too much detail about the components in the parent pipeline, as they differ from one CI/CD toolset to another. However, the general concept can be inferred from your understanding and experience of using CI/CD toolsets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Template Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We are utilising Azure DevOps' native process called Parameters. These are essentially template parameters that allow us to define values that will be used at runtime. For the example above, we’re specifying 2 parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IaC environment&lt;/li&gt;
&lt;li&gt;Cloud provider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these two values, we can dynamically invoke the corresponding root modules in Terraform to create, update, or delete our resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Variable Groups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have organised the necessary IaC stages and environment details into user-friendly and easily identifiable groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;generic-variables.yml&lt;/code&gt; - contains all of the generic information, such as shared terraform secrets, and shared credentials&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test-variables.yml&lt;/code&gt; - contains all of the environment-specific values, such as Terraform backend storage names (S3 bucket or Azure storage account names)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;foundation-variable.yml&lt;/code&gt; - contains all of the IaC stage information such as Terraform arguments, stage folders to load (foundation, common, ecs, kubernetes), location, and more for that specific IaC stage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Path Triggers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As shown in the example above, we added AWS and Azure folder paths to ensure the pipeline triggers. However, since we are using template parameters, &lt;strong&gt;manual pipeline invocation is required to deploy to other non-default environments and cloud providers mentioned&lt;/strong&gt;. Path triggers differ in each CI/CD toolset. Therefore, you could technically provide a wildcard to search for all cloud providers for the &lt;code&gt;foundation&lt;/code&gt; IaC stage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipeline Stages / Jobs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This section is where all of your template parameters and variable groups are injected to be utilised by the template pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Template pipeline or child pipeline
&lt;/h3&gt;

&lt;p&gt;As the name suggests, templates allow you to define reusable content, logic, and parameters into smaller parts that are easier to understand.&lt;/p&gt;

&lt;p&gt;Parameters and variables parsed from the parent pipeline can be processed to dynamically set the folders for your IaC stage and cloud provider. The following example demonstrates a step in a job for executing a Terraform plan. Depending on your CI/CD toolset and the marketplace plugins you use, you can write conditional logic to switch steps based on the cloud provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TerraformCLI@0&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Terraform&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Plan"&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tfPlanOutput&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan"&lt;/span&gt;
    &lt;span class="na"&gt;workingDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$(System.DefaultWorkingDirectory)/terraform/patterns/iac/$(environment)/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.cloud&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.sequence&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}_${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.stage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;providerServiceAws&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$(aws_service_connection)"&lt;/span&gt;
    &lt;span class="na"&gt;providerAwsRegion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;$(location)"&lt;/span&gt;
    &lt;span class="na"&gt;commandOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-out="$(System.DefaultWorkingDirectory)/terraform/patterns/iac/$(environment)/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.cloud&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.sequence&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}_${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.stage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/terraform.tfplan"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-detailed-exitcode&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-var-file="$(System.DefaultWorkingDirectory)/terraform/patterns/iac/$(environment)/${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.sequence&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}_${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.stage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/values.tfvars"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.terraformarguments&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
    &lt;span class="na"&gt;allowTelemetryCollection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;publishPlanResults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terraform_$(environment)_output_${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.sequence&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}_${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;parameters.stage&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}_plan"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Conclusion
&lt;/h2&gt;

&lt;p&gt;In today's world, organisations are increasingly adopting cloud services from various providers to meet their business needs. As a result, multi-cloud infrastructure is becoming more common, and managing it efficiently is becoming more challenging. Terraform is a popular tool that simplifies the process of infrastructure management by providing a declarative language for defining infrastructure as code (IaC). &lt;/p&gt;

&lt;p&gt;In this context, building multi-cloud modules in Terraform requires a well-structured folder system, a focus on reusability, and a cloud-agnostic IaC stack. By following the steps outlined in this post, you can make your Terraform configuration more modular, easier to maintain, and more adaptable to changes in your cloud infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/terraform-modules-explained/" rel="noopener noreferrer"&gt;What Are Terraform Modules and How Do They Work?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>azure</category>
      <category>cloud</category>
      <category>terraform</category>
    </item>
    <item>
      <title>What is DevOps?</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Tue, 04 Apr 2023 02:44:09 +0000</pubDate>
      <link>https://forem.com/jei/what-is-devops-2k56</link>
      <guid>https://forem.com/jei/what-is-devops-2k56</guid>
      <description>&lt;p&gt;DevOps is more than just a software development methodology – it's a culture. The DevOps culture emphasises 3 main pillars: collaboration, communication, and shared responsibility between development and operations teams. In this post, we will discuss the importance of DevOps culture in software development and how developers and operations teams can benefit from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  DevOps is not a Title
&lt;/h2&gt;

&lt;p&gt;This conundrum needs to be addressed. If you’ve seen career titles such as DevOps Manager, and DevOps Lead, it means those individuals are managing the DevOps culture in that team. The title does not necessarily imply the term literally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Importance of DevOps Culture - The 3 Pillars
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Collaboration and Communication
&lt;/h3&gt;

&lt;p&gt;One of the key principles of DevOps culture is collaboration and communication. By breaking down silos between teams, DevOps promotes cross-functional collaboration, which leads to better outcomes. Collaboration between development and operations teams can help identify potential problems earlier in the development cycle, saving time and resources down the line.&lt;/p&gt;

&lt;p&gt;Effective communication is also essential in DevOps culture. By sharing information and feedback, teams can work together to ensure that everyone is on the same page and working towards the same goals. This helps identify areas for improvement and implement changes more effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared Responsibility
&lt;/h3&gt;

&lt;p&gt;Another principle of DevOps culture is shared responsibility. In a DevOps environment, developers and operations teams share the responsibility of delivering software. This means that developers are responsible not only for writing code but also for ensuring that it runs smoothly in production. Similarly, operations teams are responsible not only for deploying and maintaining infrastructure but also for providing feedback to developers on how their code is performing in a production environment. In other words, “you build it, you ship it!”; developers can utilise the DevOps tools available to deploy their code to production.&lt;/p&gt;

&lt;p&gt;DevOps teams can create a culture of accountability and ownership by sharing responsibility. When everyone is responsible for the success of the software, it creates a sense of ownership and pride in the work being done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Improvement
&lt;/h3&gt;

&lt;p&gt;Continuous improvement is a fundamental value of DevOps culture. DevOps teams continuously seek ways to enhance their processes, tools, and practices. By continuously evaluating and improving their work, DevOps teams can remain competitive in a rapidly changing digital landscape.&lt;/p&gt;

&lt;p&gt;Continuous improvement also assists teams in learning from their mistakes. When something goes wrong, DevOps teams utilize the incident as an opportunity to learn and improve. By implementing changes based on what they have learned, teams can avoid making the same mistakes in the future. DevOps teams should always be looking for ways on improving their automation and processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;DevOps teams can employ a range of tools and practices to achieve their goals, such as continuous integration and delivery (CI/CD), automated testing, and infrastructure as code (IaC). By automating tasks and using standardized processes, DevOps teams can reduce errors and improve the quality of their software. Some of the tools include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-us/products/devops"&gt;Azure DevOps&lt;/a&gt; - CI/CD tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;, &lt;a href="https://www.pulumi.com/"&gt;Pulumi&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cdk/"&gt;AWS CDK&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager/"&gt;Azure Resource Manager&lt;/a&gt; - IaC tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sonarsource.com/products/sonarcloud/"&gt;SonarCloud&lt;/a&gt;, &lt;a href="https://www.codacy.com/"&gt;Codacy&lt;/a&gt; - Code analysis and security tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://azure.microsoft.com/en-us/products/devops/test-plans/"&gt;Azure Test Plan&lt;/a&gt; - Automated testing tool&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;DevOps culture is more than just a set of practices; it is a mindset that emphasizes collaboration, communication, shared responsibility, and continuous improvement. By embracing these values, DevOps teams can create a culture of innovation and agility that can help them stay competitive in today's fast-paced digital landscape with the toolsets available.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>productivity</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Serverless Stack, a Terraform alternative for developers</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Sat, 01 Apr 2023 05:41:09 +0000</pubDate>
      <link>https://forem.com/jei/serverless-stack-a-terraform-alternative-for-developers-2jnb</link>
      <guid>https://forem.com/jei/serverless-stack-a-terraform-alternative-for-developers-2jnb</guid>
      <description>&lt;p&gt;Picture yourself being able to confidently deploy your application, whether it's full-stack or partially serverless, without having to rely on your DevOps or Platform team. Envision yourself seamlessly hosting your Infrastructure as Code (IaC) configurations in the same repository as your application code for maximum feasibility. Most importantly, consider the possibilities if you were able to eliminate the development feedback loop that necessitates the local mocking of services and redeployment for testing. There’s a solution for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Serverless Stack
&lt;/h2&gt;

&lt;p&gt;Serverless Stack, also known as SST, is a powerful framework that enables you to effortlessly create serverless applications with backend stores on AWS. Since 2021, the SST framework has evolved into a comprehensive platform that empowers you to develop and deploy a cutting-edge full-stack application with robust backend features, including databases, GraphQL APIs, authentication, cron jobs, and various other AWS services such as ECS, S3, and CloudWatch. SST provides an array of features that efficiently addresses common developer challenges and concerns when building serverless applications, such as seamless integration with other backend tools and services in AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What type of solutions can I build with it?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;Web Apps&lt;/li&gt;
&lt;li&gt;Mobile Apps (not literally, but tight coupling with serverless architecture)&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Asynchronous Tasks / Event Driven Systems&lt;/li&gt;
&lt;li&gt;Monitoring&lt;/li&gt;
&lt;li&gt;Lambda Layers&lt;/li&gt;
&lt;li&gt;All other AWS services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SST is an excellent framework for building various solutions. However, for microservices that require loosely coupled services like account, identity, and payment services, it may not be the best choice. These solutions require a complex software design and cloud architecture, which are better suited for Kubernetes or other containerization solutions.&lt;/p&gt;

&lt;p&gt;Overall, SST empowers you to confidently build a full-stack application comprising a front-end application, back-end application, database, and multiple integration systems or services. Thanks to the underlying architecture of SST, you can seamlessly incorporate other AWS services and third-party tools and libraries that are closely intertwined with your application. These can cover various areas such as authentication, monitoring, cron jobs, asynchronous operations, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it all work and come together?
&lt;/h2&gt;

&lt;p&gt;SST framework is built on top of the notable AWS Cloud Development Kit. SST follows monorepo architecture because it combines your application code along with the IaC. By default, SST uses TypeScript to define your architecture, however, you can still use JavaScript.&lt;/p&gt;

&lt;p&gt;The project folder structure is as follows:&lt;/p&gt;

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

my-sst-app
├─ package.json
├─ sst.config.ts
├─ packages
│  ├─ core
│  │  └─ migrations
│  ├─ functions
│  ├─ graphql
│  └─ web
└─ stacks


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;stacks/&lt;/code&gt; folder contains all of your Infrastructure as Code. SST typically recommends grouping related resources together into stacks. For example, you can have a &lt;code&gt;Database.ts&lt;/code&gt; file that contains the IaC to provision a RDS instance or a DynamoDB resource. &lt;code&gt;Api.ts&lt;/code&gt; file could contain configuration to provision a API Gateway. You could then bind your database to the API in order for your functions that powers your API to have access to it. Your front-end application, &lt;code&gt;Web.ts&lt;/code&gt; could host a static website powered by Vuejs on S3 and serve content through a CDN, such as CloudFront. In conclusion, it’s all about building up the stacks and binding them together using properties that are returned from the individual resources you provision.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;packages/&lt;/code&gt; contains all the components that power your backend systems, including systems like your GraphQL API, Lambda functions, front-end application, business logic, and any other programming you require. SST recommends maintaining a Domain Driven Design pattern within the &lt;code&gt;packages/core&lt;/code&gt; folder to isolate your business logic from your API and Lambda functions. This ensures simple and maintainable code within your project. The folder contains all the implementation necessary for your application to function, which is then called by external-facing services, similar to an API. Within the &lt;code&gt;packages/core/migrations&lt;/code&gt; folder, houses all of your SQL migrations. The &lt;code&gt;packages/web&lt;/code&gt; folder houses your front-end application, whether it’s React, Vue, Next, Gatsby. &lt;code&gt;packages/functions&lt;/code&gt; houses all of your code for your Lambda functions. They should be designed with simple functionality while being invoked by services code defined in the &lt;code&gt;packages/core&lt;/code&gt; . Finally, &lt;code&gt;packages/graphql&lt;/code&gt; houses outputs generated by the GraphQL. Ideally, you would not alter this folder as it’s shared between your frontend and backend, therefore should be committed into Git.&lt;/p&gt;

&lt;p&gt;One great feature of SST is its use of &lt;strong&gt;Workspaces&lt;/strong&gt; from npm. This provides support for managing multiple packages, or in this case, a monorepo, from within a single top-level, root package. Workspaces help manage dependencies for separate packages in your repository that have their own &lt;code&gt;package.json&lt;/code&gt; file. This is especially useful if you want to keep several projects in a single monorepo that are related in some way.&lt;/p&gt;

&lt;p&gt;SST includes its own set of npm scripts that handle various tasks for your application, such as starting it up, building it, deploying it, removing it, and testing it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-sst-app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-west-2&lt;/span&gt;&lt;span class="dl"&gt;"&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="nf"&gt;stacks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Web&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;satisfies&lt;/span&gt; &lt;span class="nx"&gt;SSTConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, SST provides a configuration file that specifies your project configuration and the stacks that follow in your application. This configuration file is crucial in initializing your entire project, both on your local machine and when you deploy your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  What features does it provide?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Live Lambda Development
&lt;/h3&gt;

&lt;p&gt;SST offers a local development environment that enables you to debug and test your Lambda functions locally while being invoked remotely from AWS. This is a significant advantage of SST as it allows developers to test their changes locally without the need to mock the servers and redeploy to test them using conventional methods. Behind the scenes, SST employs AWS IoT over Websocket to communicate and forward requests between your local machine and the remote Lambda function (sort of like a proxy). This feature enables SST to execute a function locally using the same event, context, and credentials as the remote Lambda function. Changes are automatically detected, built, and reloaded live in just a few milliseconds. You can take full advantage of breakpoints to debug your code live with an IDE of your choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  SST Console
&lt;/h3&gt;

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

&lt;p&gt;SST Console is a web-based dashboard used to manage your SST applications. You can view real-time logs, invoke functions, replay invocations, view your deployed stacks, run migrations, make queries, view uploaded files in S3, query your GraphQL APIs, and more. For multitasking, you can use separate tabs or explorers to manage different parts of your application, providing a seamless monitoring experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Editor Integration
&lt;/h3&gt;

&lt;p&gt;SST is designed to seamlessly integrate with your preferred IDEs. It comes with a range of built-in features including autocomplete, inline documentation, the ability to set breakpoints in your Lambda functions, and type checking (if you're building your application in TypeScript). Currently, SST provides support for Visual Studio Code, WebStorm, and IntelliJ IDEA.&lt;/p&gt;

&lt;h3&gt;
  
  
  Migration from AWS CDK and Serverless Framework
&lt;/h3&gt;

&lt;p&gt;SST offers assistance in migrating your resources and applications from both AWS CDK and Serverless Framework with a comprehensive guide. The transfer process from AWS CDK should be relatively simple as SST was constructed on the AWS CDK. However, when dealing with the Serverless Framework, it is recommended to adopt an incremental update approach, which results in a hybrid Serverless Framework and an SST application.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I set up a project ?
&lt;/h2&gt;

&lt;p&gt;It ultimately depends on the type of application you are looking to create. There are a few different approaches you can take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standalone application - this involves building your application from the ground up using the CDK API reference.&lt;/li&gt;
&lt;li&gt;SST application - this approach involves using the SST API construct to build a variety of elements and/or resources such as frontend applications, backend applications, databases, APIs, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get started, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Have an AWS account ready to deploy your application.&lt;/li&gt;
&lt;li&gt;Setup AWS CLI on your local machine and configure IAM user credentials for it. For now, you may provide full administrative access. You may change this later on to meet your project requirements based on the AWS resources you will be utilising in order for SST to deploy your application&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npx create-next-app@latest&lt;/code&gt; to create a new Next.js application.&lt;/li&gt;
&lt;li&gt;Then, initialise SST in your project root directory with &lt;code&gt;npx create-sst@latest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Start your local development environment by running &lt;code&gt;npx sst dev&lt;/code&gt; to start SST and &lt;code&gt;npm run dev&lt;/code&gt; to start Next.js.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you've completed these steps, you can start building your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I deploy it to my AWS environment?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CLI
&lt;/h3&gt;

&lt;p&gt;The most convenient method for deployment is likely through the CLI. By running &lt;code&gt;npx sst deploy --stage prod&lt;/code&gt; at the root level of your project, you can deploy your application to an environment with a &lt;code&gt;prod&lt;/code&gt; identifier. SST utilizes CloudFormation stacks to carry out deployments, which is why you may notice your AWS account accruing CloudFormation stacks. To deploy your application to various environments, simply reference the &lt;code&gt;-stage&lt;/code&gt; option in the CLI. This will allow you to design your application to be adaptable when it comes to switching between resources and environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI/CD
&lt;/h3&gt;

&lt;p&gt;To automate your deployments, push your code to a Git provider such as GitHub and then connect it to a CI/CD service to deploy your application. There are several CI/CD providers available, including GitHub Actions, Azure DevOps, Gitlab, Bitbucket Pipelines, Buildkite, and more. As with setting up an IAM user on your local machine, it is important to store the access credentials securely in your CI/CD tool. You can add additional steps in your pipeline that prompt the pipeline agent to log in securely to your AWS account, and SST will use the credentials to deploy your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much customisation can I do with SST?
&lt;/h2&gt;

&lt;p&gt;It depends on the application architecture and design patterns you employ. If your architecture is event-driven, then you can take full advantage of the SST framework. If your architecture is centered around building a mid-level API system using something like Express.js, you can still make use of the SST framework by installing Node package libraries in your project. This will help you leverage the capabilities of SST, while also designing a simple API system that uses REST design.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can build an AWS API Gateway using SST&lt;/li&gt;
&lt;li&gt;Build a Lambda function that utilises the Express.js REST API and bind the function to the API Gateway&lt;/li&gt;
&lt;li&gt;You can extend from SST by using the AWS CDK constructs such as, S3, Cloudwatch Logs, Secrets Manager to store artifacts, send/stream your application logs, access sensitive information from the vault and bind them to your Lambda function&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;SST is a fantastic choice for developers seeking to build robust and scalable serverless applications that operate on AWS. SST offers a broad spectrum of features, such as a local development environment, and effortless integration with other backend tools and services in AWS. This provides developers with the flexibility and simplicity they require to create and deploy modern applications. Furthermore, SST is expanding its internal tooling to encompass additional constructs from AWS CDK, thereby providing an increasingly comprehensive yet user-friendly framework for building a modern, full-stack application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sst.dev/" rel="noopener noreferrer"&gt;SST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.sst.dev/" rel="noopener noreferrer"&gt;SST Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=hnTSTm5n11g" rel="noopener noreferrer"&gt;Live Lambda Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.sst.dev/assets/images/sst-console-homescreen-7e474900947354d49f6e14df285390f7.png" rel="noopener noreferrer"&gt;https://docs.sst.dev/assets/images/sst-console-homescreen-7e474900947354d49f6e14df285390f7.png&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>cloud</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to set up an index alias that points to multiple indices in Elasticsearch</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Wed, 11 Aug 2021 15:19:30 +0000</pubDate>
      <link>https://forem.com/jei/how-to-set-up-an-index-alias-that-points-to-multiple-indices-in-elasticsearch-4g7g</link>
      <guid>https://forem.com/jei/how-to-set-up-an-index-alias-that-points-to-multiple-indices-in-elasticsearch-4g7g</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuim9qc5k8087lhz2sf04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuim9qc5k8087lhz2sf04.png" alt="Index alias"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index aliasing&lt;/strong&gt; is a powerful feature in Elasticsearch that gives us the ability to control the indices. One could create as many indices as possible and use an alias to point to the right index or one can point the index alias to all indices, depending on your application needs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Scenarios
&lt;/h2&gt;

&lt;p&gt;Imagine if you had the following scenarios when working with Elasticsearch for your application needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scenario&lt;/strong&gt; &lt;strong&gt;1&lt;/strong&gt;: A snapshot of your index that needs to be restored to a new cluster, however, you forgot to restore it, and instead, you created a new index. As time passed, you realised that new data had amassed in the newly created index and you needed to combine the data from the snapshot with the new index.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenario 2&lt;/strong&gt;: You have an index that requires certain schema changes or re-indexing. To be able to ensure your users are able to search from your instance with almost no downtime, set up a new index with new schema changes and re-index the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Introducing &lt;strong&gt;multi-index aliasing&lt;/strong&gt;. You can create a single index alias that points to multiple indices. There's an endpoint from Elasticsearch that allows you to perform one or more alias actions in a single atomic operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Verify if the alias you'd like to use has not been used yet by using the &lt;code&gt;_alias/alias-name&lt;/code&gt; endpoint - &lt;code&gt;HEAD _alias/my-alias&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;If it returns a 404, it means the alias is available and can be used in setting up the multi-index aliasing&lt;/li&gt;
&lt;li&gt;If it returns a 200, it means it's being used and you need to choose another alias&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Verify your indices are readily available within your cluster/instance.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Ensure that your old snapshot is ready (if you don't have your secondary index setup).&lt;/li&gt;
&lt;li&gt;When you do restore the snapshot index, ensure that the index name is different than the newly created to avoid conflicts.

&lt;ul&gt;
&lt;li&gt;Clone the index from the old snapshot/cluster if you have to&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Run the following POST request to your designated cluster:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;_aliases&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actions&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new_index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alias&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new_index_alias&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;old_index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alias&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new_index_alias&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  But wait, what if I want to specify the new data is written to a specific index?
&lt;/h3&gt;

&lt;p&gt;You can pass in the &lt;code&gt;**is_write_index**&lt;/code&gt; parameter in the payload as follows:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;_aliases&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actions&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new_index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alias&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new_index_alias&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is_write_index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;old_index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alias&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new_index_alias&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, it's fairly straightforward to set up an index alias that points to multiple indices within your Elasticsearch instance.&lt;/p&gt;

&lt;p&gt;If you want to query data from the alias, simply perform the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;new_index_alias&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;_search&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This would help you query across two indices &lt;code&gt;new_index&lt;/code&gt; and &lt;code&gt;old_index&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero downtime:&lt;/strong&gt; Bring up a new index with new changes, point alias to new index when it's ready. Keep the old index stale, in case it's needed for future reference or just as a backup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple Indices:&lt;/strong&gt; We want to be able to query multiple indices? Then create an alias that points to multiple indices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html" rel="noopener noreferrer"&gt;https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-alias-exists.html" rel="noopener noreferrer"&gt;https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-alias-exists.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elasticsearch</category>
      <category>elasticcloud</category>
      <category>index</category>
      <category>alias</category>
    </item>
    <item>
      <title>How To Automate App Releases using Fastlane and SemVer for Hybrid Applications</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Tue, 10 Aug 2021 13:22:23 +0000</pubDate>
      <link>https://forem.com/jei/how-to-automate-app-releases-using-fastlane-and-semver-for-hybrid-applications-24m0</link>
      <guid>https://forem.com/jei/how-to-automate-app-releases-using-fastlane-and-semver-for-hybrid-applications-24m0</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq875yqvd5hutjcw5ws6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq875yqvd5hutjcw5ws6b.png" alt="Placeholder image for article"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: This tool/implementation is useful for when you have both iOS and Android binary applications residing within the same repository (usually a &lt;strong&gt;React Native application&lt;/strong&gt;) or hybrid app development tools which produce iOS and Android apps. However, it can be customisable to your needs with a little re-configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The Story
&lt;/h1&gt;

&lt;p&gt;Imagine if we could automate the entire app versioning process for our mobile applications by just typing in whether you want to bump it by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Major&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minor&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;or &lt;strong&gt;Patch&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine if you don’t have to worry about the app versioning process of knowing what is already in production and what version we need to bump it to?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo and behold, the App Release Management (ARM) tool.&lt;/strong&gt; 🎉&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: Semantic versioning MAJOR, MINOR, and PATCH is the de facto standard you use to version your applications. Please refer to this &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;link&lt;/a&gt; to find out more about SemVer standards.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Fancy word, but what does it actually do?
&lt;/h1&gt;

&lt;p&gt;It pretty much does what is mentioned above. The process is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It will fetch the latest versions from TestFlight and Google Play Console respectively.&lt;/li&gt;
&lt;li&gt;It will show you a summary of what the versions are.&lt;/li&gt;
&lt;li&gt;If both Android and iOS match, the tool will select either one of them to use as the base of bumping the version.&lt;/li&gt;
&lt;li&gt;The tool will prompt you whether you would like to bump it based on major, minor, or patch&lt;/li&gt;
&lt;li&gt;Based on the input, the tool will run a SemVer operation in calculating the next iteration in the version and display the results for you.&lt;/li&gt;
&lt;li&gt;If you’re happy with the result, you may press yes to proceed.&lt;/li&gt;
&lt;li&gt;It will update the following files for you:

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;android/app/build.gradle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ios/ProjectName.xcodeproj/project.pbxproj&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Operation completed!&lt;/li&gt;

&lt;/ol&gt;

&lt;h1&gt;
  
  
  It all looks fancy, but why this approach?
&lt;/h1&gt;

&lt;p&gt;Well, imagine if you are a product owner or a new engineer who is new to the application code and is required to manage the App Releases. This tool will aid them in completing their task with ease, without worrying about configuring the wrong version code bump by accident.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ok cool, how do I set it up?
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Please refer to the &lt;a href="https://github.com/jeiman/devops-fun/tree/main/development/app-release-management-tool" rel="noopener noreferrer"&gt;documentation README&lt;/a&gt; file for detailed instructions on how to set up the tool.&lt;/li&gt;
&lt;li&gt;Clone the &lt;a href="https://github.com/jeiman/devops-fun" rel="noopener noreferrer"&gt;devops-fun&lt;/a&gt; repository.&lt;/li&gt;
&lt;li&gt;Once completed, navigate to &lt;strong&gt;development &amp;gt; app-release-management-tool&lt;/strong&gt; folder.&lt;/li&gt;
&lt;li&gt;Ensure that the &lt;code&gt;.env&lt;/code&gt; file is present before proceeding any further. Refer to the README file for more information.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;fastlane&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Choose Option 1.&lt;/li&gt;
&lt;li&gt;The rest are pretty self-explanatory thereafter.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  What if I want to manually bump the version via a tool?
&lt;/h1&gt;

&lt;p&gt;You may run the &lt;code&gt;bump-version.sh&lt;/code&gt; and pass in a version code as an argument: &lt;code&gt;./development/app-release-management-tool/bump-version.sh 3.2.0&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What does it look like?
&lt;/h1&gt;

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

&lt;p&gt;Based on the image above, the following actions occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It will do a check against your iOS TestFlight build number and Google App Version and identify if the versions match (&lt;em&gt;Please refer to the &lt;a href="https://github.com/jeiman/devops-fun/blob/main/development/app-release-management-tool/README.md" rel="noopener noreferrer"&gt;README.md&lt;/a&gt; file on how to set up a service connection to the respective stores in order to retrieve the app details programmatically&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;If they do, it will display your current version in the App stores and will ask you for input, whether you want to bump the &lt;strong&gt;major&lt;/strong&gt;, &lt;strong&gt;minor,&lt;/strong&gt; or &lt;strong&gt;patch&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Based on your input, it will use the &lt;code&gt;semver.sh&lt;/code&gt; script to perform the necessary version bump according to the Semantic Versioning standards.&lt;/li&gt;
&lt;li&gt;If they don't match up, you'll be defaulted to using the &lt;code&gt;bump-version.sh&lt;/code&gt; which requires manual input of your SemVer for your application - ie &lt;code&gt;./bump-version.sh 2.2.0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this article has proven beneficial and useful to your release management process. If you have any inquiries, please reach out to me. Happy automating your release process! Do leave a comment or recommendations on improving the tool.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jeiman/devops-fun" rel="noopener noreferrer"&gt;https://github.com/jeiman/devops-fun&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jeiman/devops-fun/tree/main/development" rel="noopener noreferrer"&gt;https://github.com/jeiman/devops-fun/tree/main/development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;https://semver.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jontejada.com/blog/assets/semver02.png" rel="noopener noreferrer"&gt;https://jontejada.com/blog/assets/semver02.png&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/fsaintjacques/semver-tool" rel="noopener noreferrer"&gt;https://github.com/fsaintjacques/semver-tool&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>fastlane</category>
      <category>reactnative</category>
      <category>automation</category>
      <category>hybridapps</category>
    </item>
    <item>
      <title>Part 2: Automating code quality scanning using Sonar Cloud and GitHub Actions</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Mon, 09 Aug 2021 16:58:29 +0000</pubDate>
      <link>https://forem.com/jei/part-2-automating-code-quality-scanning-using-sonar-cloud-and-github-actions-8g7</link>
      <guid>https://forem.com/jei/part-2-automating-code-quality-scanning-using-sonar-cloud-and-github-actions-8g7</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/jeiman/part-1-concepts-of-code-quality-in-sonar-cloud-318j"&gt;Part 1 of our article&lt;/a&gt; talks about the fundamentals of code quality with respect to Sonar Cloud. However, these are generic terms that can be applied to any code quality tool. In this article, we will explain how we can use Sonar Cloud to automate our code quality scanning with our GitHub repositories using GitHub Actions. The goal of this article is to ensure that you have a good understanding of how Sonar Cloud performs code analysis, how the integration features on GitHub (PR decorators, inline commenting, code quality overview using widgets) will benefit your engineering teams in the long run.&lt;/p&gt;

&lt;p&gt;Some of the neat features that I found Sonar Cloud provides is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhances your workflow with continuous code quality and code security&lt;/li&gt;
&lt;li&gt;Supports all major programming languages you can think of&lt;/li&gt;
&lt;li&gt;Provides a clear overview of your overall code health in your repository, pull requests and pipelines&lt;/li&gt;
&lt;li&gt;Works with all famous Git providers (GitHub, Bitbucket, Azure DevOps and GitLab)&lt;/li&gt;
&lt;li&gt;Works with all famous CI/CD tools (GitHub Actions, Bitbucket Pipelines, Azure Pipelines, GitLab CI/CD, CircleCI, TravisCI, etc)&lt;/li&gt;
&lt;li&gt;Bug, Vulnerability, and Code Smell detection&lt;/li&gt;
&lt;li&gt;Top-notch coding rules&lt;/li&gt;
&lt;li&gt;In-ALM pull request feedback&lt;/li&gt;
&lt;li&gt;Go/No Go Quality Gate checks&lt;/li&gt;
&lt;li&gt;Automatic analysis (Currently limited to GitHub repositories)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preliminaries
&lt;/h2&gt;

&lt;p&gt;You will need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A GitHub repository with a backend or frontend application&lt;/li&gt;
&lt;li&gt;Access to GitHub Actions&lt;/li&gt;
&lt;li&gt;A Sonar Cloud account&lt;/li&gt;
&lt;li&gt;A Sonar Cloud project&lt;/li&gt;
&lt;li&gt;Some basic knowledge on CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup Process
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Sign up and import repositories
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ensure you have a GitHub repository readily available. For this, we will be choosing one of my NodeJS backend applications.&lt;/li&gt;
&lt;li&gt;Signup for a Sonar Cloud account and log in using your GitHub account to have a seamless experience.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once you have signed up, you will be redirected to this page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3ow6qlwzxums4x8xmc1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3ow6qlwzxums4x8xmc1.png" alt="SetupSonarCloud"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From this page, you can import an organisation from GitHub.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on &lt;strong&gt;Import an organisation from Github&lt;/strong&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will be redirected to your GitHub account where it will prompt you to choose an organisation to install SonarCloud. In this article, we will be choosing my own personal GitHub repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3il28988u9m07e8phns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3il28988u9m07e8phns.png" alt="Connect Sonar Cloud App with GitHub"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From there, you will be redirected back to Sonar Cloud, where you will create your Sonar Cloud organisation. Please note that at this point, you have already &lt;strong&gt;installed and connected the Sonar Cloud App on your GitHub account&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1xvip96asaopk4m540i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1xvip96asaopk4m540i.png" alt="Setup project key"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;From the image above, you can provide an organisation key that will be used later in GitHub Actions to send your code analysis metrics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78cupxpkimwuk7tocf4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78cupxpkimwuk7tocf4k.png" alt="Choose pricing plan"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, you would need to choose a Pricing plan. There are 2 options: &lt;strong&gt;Paid&lt;/strong&gt; and &lt;strong&gt;Free&lt;/strong&gt;. For this article, we will be choosing the &lt;strong&gt;Free&lt;/strong&gt; plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Create Organization&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will now be able to import any &lt;strong&gt;Public repository&lt;/strong&gt;. If you have Paid for Sonar Cloud, you may import your Private repositories.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wtmf6qib10xozdlodq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wtmf6qib10xozdlodq4.png" alt="Choose your repos"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We have selected our public repository, named &lt;code&gt;nodejs-backend-starter&lt;/code&gt;. This repository contains a very basic Node.js backend application with Unit Testing and Code Coverage setup.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NOTE: There's also an option to set up a monorepo. Based on the image above, you may see a small section at the bottom right of the image that mentions setting up a monorepo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you have selected your repositories, click &lt;strong&gt;Set Up&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It will do an Automatic Analysis of your project providing an initial analysis of it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Although Sonar Cloud offers automatic analysis for GitHub repositories only, we will be &lt;strong&gt;disabling this option&lt;/strong&gt; as we want our CI pipeline to handle the analysis process for us. With the CI pipeline, you may replicate this entire process for any Git provider and any CI/CD tool available.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate to Administration &amp;gt; Analysis Method &amp;gt; SonarCloud Automatic Analysis. Turn off this option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr53fneim5wdb5stxffgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr53fneim5wdb5stxffgf.png" alt="Turn off automatic analysis"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Navigate back to your project root page. Your project page should look something like the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4g2oqzq6smkyxrx8z7oc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4g2oqzq6smkyxrx8z7oc.png" alt="Project page"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As you can see, it states that they can't display any Quality Gate without a New Code definition. Based on the &lt;a href="https://dev.to/jeiman/part-1-concepts-of-code-quality-in-sonar-cloud-318j"&gt;Part 1 article&lt;/a&gt;, we will be setting up the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A New Code Definition&lt;/li&gt;
&lt;li&gt;A Quality Gate&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  2 Sonar Cloud Configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  2.1 Set Up New Code definition
&lt;/h4&gt;

&lt;p&gt;There are 2 options available at this moment. You can either set up a New Code definition on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A project level&lt;/li&gt;
&lt;li&gt;An organisation level&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this article, we will set it up on a project level.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;On your project page, click on &lt;strong&gt;Set New Code definition&lt;/strong&gt;. If that is not available, you may navigate to &lt;strong&gt;Administration &amp;gt; New Code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zwnnxjqhkarjmj68t2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zwnnxjqhkarjmj68t2s.png" alt="New Code Definitions"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you have read my previous article, you may know that there are a number of options to choose from. In this case, we will be choosing the &lt;strong&gt;Number of days&lt;/strong&gt; that equates to &lt;strong&gt;30 days&lt;/strong&gt; by default. The reason is we are not going to be maintaining a version for the project on Sonar Cloud for now.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.2 Setup a Quality Gate
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to your organisation page (&lt;a href="https://sonarcloud.io/organizations/jeimanjeya/projects" rel="noopener noreferrer"&gt;https://sonarcloud.io/organizations/{username}/projects&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select &lt;strong&gt;Quality Gates&lt;/strong&gt; from the sub-navigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu2d9fj6rzwcymvn8tgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu2d9fj6rzwcymvn8tgs.png" alt="Quality Gate Summary"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From the image above, there's already a default Quality Gate set up for you. We're going to be cloning this and creating our own. Click on &lt;strong&gt;Copy&lt;/strong&gt; on the &lt;strong&gt;Sonar way&lt;/strong&gt; Quality Gate*&lt;em&gt;.&lt;/em&gt;*&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Name your new cloned Quality Gate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Since there are already New Code conditions, we are simply appending &lt;strong&gt;Overall Code conditions&lt;/strong&gt;. For this article, we have added the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Coverage is less than 80%&lt;/li&gt;
&lt;li&gt;Duplicated Lines is greater than 5%&lt;/li&gt;
&lt;li&gt;Maintainability Rating is worse than A&lt;/li&gt;
&lt;li&gt;Reliability Rating is worse than A&lt;/li&gt;
&lt;li&gt;Security Rating is worse than A&lt;/li&gt;
&lt;/ol&gt;

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


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Set your new Quality Gate as &lt;strong&gt;Default&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Now that we have our project settings in place, we need to set up a project properties file next. &lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.3 Setup a project properties file
&lt;/h3&gt;

&lt;p&gt;This properties file will enable the CI pipeline to perform the necessary configuration and filtering in order to perform the code analysis. Furthermore, this will ensure we have the right settings in place when we push our commit to a branch or create a pull request that triggers the code analysis.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your code repository, create a &lt;code&gt;sonar-project.properties&lt;/code&gt; file.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="s"&gt;sonar.exclusions=**/*.bin&lt;/span&gt;
&lt;span class="s"&gt;sonar.organization=jeimanjeya&lt;/span&gt;
&lt;span class="s"&gt;sonar.projectKey=jeiman_nodejs-backend-starter&lt;/span&gt;
&lt;span class="s"&gt;sonar.projectName=jeiman_nodejs-backend-starter&lt;/span&gt;
&lt;span class="s"&gt;sonar.projectVersion=1.0&lt;/span&gt;
&lt;span class="s"&gt;sonar.sourceEncoding=UTF-8&lt;/span&gt;
&lt;span class="s"&gt;sonar.sources=src&lt;/span&gt;
&lt;span class="s"&gt;sonar.exclusions=node_modules/**&lt;/span&gt;
&lt;span class="s"&gt;sonar.test.inclusions=test/**&lt;/span&gt;
&lt;span class="s"&gt;sonar.typescript.lcov.reportPaths=coverage/lcov.info&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this file, we're basically narrowing the focus of the scanner to configure the project source path, unit test inclusion path, coverage report path and exclude redundant folder paths (node_modules).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Commit this file to your:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root directory&lt;/strong&gt;: If it is a single application repository (microrepo) architecture (the case for us)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo directory:&lt;/strong&gt; If you have a monorepo architecture&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that we have set up our project configuration and settings, we can focus on configuring the CI pipeline on GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. GitHub Actions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  3.1 Pipeline/Workflow Structure
&lt;/h4&gt;

&lt;p&gt;You have several to choose from options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Store all of your workflows in a single YAML file - &lt;code&gt;ci.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Separate them into branch workflows:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ci_develop.yml&lt;/code&gt; - for PR triggers and branch triggers on &lt;code&gt;develop&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ci_master.yml&lt;/code&gt; - for PR triggers and branch triggers on &lt;code&gt;main&lt;/code&gt; branch&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Separate them into trigger workflows:

&lt;ol&gt;
&lt;li&gt;PR triggers - &lt;code&gt;ci_pr.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Branch triggers - &lt;code&gt;ci_branch.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Separate them into monorepo workflows:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;spa-frontend.yml&lt;/code&gt; and &lt;code&gt;ms-backend.yml&lt;/code&gt; - contains PR and branch triggers for both &lt;code&gt;develop&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; branch &lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Option 1 is difficult the maintain in the long run if you follow a monorepo architecture&lt;/li&gt;
&lt;li&gt;Option 2 or 3 is the best way of maintaining your workflows on GitHub&lt;/li&gt;
&lt;li&gt;Option 4 is useful for when you have a monorepo architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this article, we are choosing Option 3 for simplification.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your final GitHub workflow for branch analysis will look like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sonar Cloud - Branch Analysis&lt;/span&gt;

&lt;span class="c1"&gt;# Controls when the action will run. Triggers the workflow on push&lt;/span&gt;
&lt;span class="c1"&gt;# events but only for the main and release-* branch&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;release-*&lt;/span&gt;

&lt;span class="c1"&gt;# A workflow run is made up of one or more jobs that can run sequentially or in parallel&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;sonarcloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build (Sonar Cloud)&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Disabling shallow clone is recommended for improving relevancy of reporting&lt;/span&gt;
        &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;15'&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run test&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SonarCloud Scan&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonarcloud-github-action@master&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SONAR_TOKEN }}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;We have included an Action from GitHub Actions and that is the Sonar Cloud Scanner. &lt;/li&gt;
&lt;li&gt;In order for Sonar Cloud Scanner to authenticate and upload the analysis reports and metrics, you will need to store the &lt;code&gt;SONAR_TOKEN&lt;/code&gt; secret in your GitHub repository.&lt;/li&gt;
&lt;li&gt;Navigate to your project settings and retrieve the project token, &lt;strong&gt;Project &amp;gt; Administration &amp;gt; Analysis Method &amp;gt; Analyze with a GitHub Action&lt;/strong&gt;. It will present you with a token.&lt;/li&gt;
&lt;li&gt;Navigate back to your repository settings on GitHub, &lt;strong&gt;Repository Settings &amp;gt; Secrets &amp;gt; New repository secret&lt;/strong&gt;. Name it as per the workflow secret name.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;, GitHub automatically appends the token for each workflow that runs on GitHub.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Commit your code into the &lt;code&gt;main&lt;/code&gt; branch and watch the pipeline run.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3quqvnmruwf2ieu846ky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3quqvnmruwf2ieu846ky.png" alt="Pipeline summary"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href="https://github.com/jeiman/nodejs-backend-starter/runs/3281611957?check_suite_focus=true" rel="noopener noreferrer"&gt;summary for the branch analysis pipeline&lt;/a&gt; has indicated that the analysis was successful.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Navigating back to Sonar Cloud, you will notice that your project branch analysis report has been updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhiu5gkt9ad2s6yuea04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhiu5gkt9ad2s6yuea04.png" alt="QG Check on branch analysis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll move on to running code analysis on a long-living branch next.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.2 Running code analysis on a long-living branch
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Simply check out a new branch from &lt;code&gt;main&lt;/code&gt; and name it to &lt;code&gt;release-{anyname}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Commit your code and the CI pipeline will pick it up based on the branch trigger logic in the workflow YAML file.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The SC Scanner will upload your analysis reports to your project on Sonar Cloud.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lli3nisr50f9qfz2ing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lli3nisr50f9qfz2ing.png" alt="Not computed"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don't be alarmed if it shows &lt;strong&gt;Not computed&lt;/strong&gt; as Sonar Cloud requires a second analysis to be able to show your Quality Gate on that long-living branch. It mentions &lt;strong&gt;Next scan will generate a Quality Gate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s5gcs03colftir0oxm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s5gcs03colftir0oxm8.png" alt="Not computed 2"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We pushed another commit to the repository to the long-living branch to show the Quality Gate.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your final Quality Gate for branch analysis (on long-living branch) will produce the following result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8tmckdymgvjqgwsiv5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8tmckdymgvjqgwsiv5j.png" alt="Branch analysis on long-living branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3.3 Running code analysis on pull requests (PR)
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Clone the &lt;code&gt;ci_branch.yml&lt;/code&gt;. Name it &lt;code&gt;ci_pr.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The only section we are changing is the event trigger. Instead of a &lt;code&gt;push&lt;/code&gt; event, we are using the &lt;code&gt;pull_request&lt;/code&gt; event.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;release-*&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Commit the code and raise a PR in your code repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your PR page should produce pipeline status checks alongside SonarCloud Code Analysis on your Merge PR section. Furthermore, your PR will contain decorations provided by the SonarCloud Bot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3hpvek6sl9w6a32b6nt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3hpvek6sl9w6a32b6nt.png" alt="PR summary report on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your &lt;a href="https://github.com/jeiman/nodejs-backend-starter/pull/1/checks?check_run_id=3281994837" rel="noopener noreferrer"&gt;PR status checks details page&lt;/a&gt; should give you a better overview of what needs fixing.&lt;/p&gt;

&lt;p&gt;If you navigate back to your Sonar Cloud project and choose your PR analysis report from the branch dropdown menu, you will see similar statistics that were displayed on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7qaf2496go3iifootil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7qaf2496go3iifootil.png" alt="PR analysis on Sonar Cloud"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's go ahead and fix our code to ensure we don't have any code smells and fine tune our Quality Gate conditions to match with a Passed state.&lt;/p&gt;

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

&lt;p&gt;Now our PR has clean code (however overall code requires fixes), we can now merge our PR. The pipeline will run another branch analysis on the &lt;code&gt;main&lt;/code&gt; branch, which is our default branch on Sonar Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Piecing it all together
&lt;/h2&gt;

&lt;p&gt;We have accomplished having a Sonar Cloud project connected to a GitHub repository that has GitHub Actions workflows in place to automate our code analysis for branch and PR triggers. Once these analyses are completed on the pipeline, you can navigate back to your Sonar Cloud project and view branch and PR analysis on both your main branch and long-living branches.&lt;/p&gt;

&lt;p&gt;One of the plus points in having integration between GitHub and Sonar Cloud is that engineering teams can benefit from having decorations forming up in their pull requests and repository. This will speed up the developer's productivity in fixing bugs, code smells, and vulnerabilities and avoid having further technical debts in their projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You can use any CI/CD tools to perform your code analysis. It does not need to be with GitHub Actions even though your repository resides on GitHub, however, for consistency you can keep them all under one umbrella.&lt;/li&gt;
&lt;li&gt;To have a complete end-to-end experience for your code quality scans on your pull requests, ensure you connect and import repositories from one unique Git organisation. The aforementioned features mainly work for that reason. Try not to mix and match repositories from different organisations (even though it's possible to do so).

&lt;ul&gt;
&lt;li&gt;1 GitHub organisation = 1 Sonar Cloud subscription&lt;/li&gt;
&lt;li&gt;1 Azure DevOps organisation = 1 Sonar Cloud subscription&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Create long-living branches on Sonar Cloud if you're following Git flow technique of &lt;code&gt;develop&lt;/code&gt; and &lt;code&gt;master&lt;/code&gt; branch. You may read up on their &lt;a href="https://community.sonarsource.com/t/how-to-create-long-living-branches-on-sonarcloud/11386" rel="noopener noreferrer"&gt;community post&lt;/a&gt; on how to achieve this. This will ensure that you are performing branch analysis on them alongside your pull request analysis.&lt;/li&gt;

&lt;li&gt;Fine-tune your Quality Gate to ensure you get the best experience from it that matches your engineering teams needs&lt;/li&gt;

&lt;li&gt;Sonar Cloud supports monorepo projects!&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I hope this 2-part series has been beneficial and helpful to your engineering needs. Sonar Cloud is a powerful code analysis tool. Please do explore their documentation to find out more or kindly reach out to me for any assistance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo links to this article
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sonarcloud.io/dashboard?id=jeiman_nodejs-backend-starter" rel="noopener noreferrer"&gt;Sonar Cloud project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jeiman/nodejs-backend-starter" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jeiman/nodejs-backend-starter/actions" rel="noopener noreferrer"&gt;GitHub Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sonarcloud.io/dashboard?branch=release-testsonarcloud&amp;amp;id=jeiman_nodejs-backend-starter" rel="noopener noreferrer"&gt;Long-living branch analysis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/power-platform/alm/overview-alm" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/power-platform/alm/overview-alm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sonarcloud.io/github" rel="noopener noreferrer"&gt;https://sonarcloud.io/github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sonarcloud</category>
      <category>github</category>
      <category>codequality</category>
      <category>git</category>
    </item>
    <item>
      <title>Part 1: Concepts of Code Quality in Sonar Cloud</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Mon, 09 Aug 2021 06:50:48 +0000</pubDate>
      <link>https://forem.com/jei/part-1-concepts-of-code-quality-in-sonar-cloud-318j</link>
      <guid>https://forem.com/jei/part-1-concepts-of-code-quality-in-sonar-cloud-318j</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhleub980wkbdv6ssws23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhleub980wkbdv6ssws23.png" alt="Placeholder image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In engineering teams/tribes, we often find ourselves stuck in a dilemma of choosing a suitable and efficient code analysis tool. A tool that will provide us all of the essential features and metrics to analyse codebases using best design practices in mind. Teams would want to prevent code problems from being merged by detecting code smells, bugs, and vulnerabilities sooner. Furthermore, they would want to view fast and accurate feedback from their respective pull requests and code merges in their repositories.&lt;/p&gt;

&lt;p&gt;The primary goals of software quality engineering are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Process control and oversight&lt;/li&gt;
&lt;li&gt;Implementing standards and metrics&lt;/li&gt;
&lt;li&gt;Data collection and analysis&lt;/li&gt;
&lt;li&gt;Test development&lt;/li&gt;
&lt;li&gt;Identification of issues and solutions&lt;/li&gt;
&lt;li&gt;Follow-up to ensure corrective actions&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;Over the years, I have worked with many code analysis tools to help developers in various teams such as Codacy, Code Climate, DeepScan, and Sonar Cloud. After spending a considerable amount of time experimenting and setting up Sonar Cloud projects, I realised it stands out from the crowd. It has a comprehensive analysis engine that offers features encompassing all of the aforementioned software quality engineering goals. Some of those features which fascinated me and my team was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pull Request decorators

&lt;ul&gt;
&lt;li&gt;Inline commenting through report annotations&lt;/li&gt;
&lt;li&gt;Pull request widgets: Provides overall code quality health on your Pull requests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Repository widgets: Provides overall code quality health on your project&lt;/li&gt;

&lt;li&gt;Scanning Old code vs New code

&lt;ul&gt;
&lt;li&gt;Code Coverage&lt;/li&gt;
&lt;li&gt;Code Duplications&lt;/li&gt;
&lt;li&gt;Maintainability Ratings&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Defining custom Quality Gate checks for different projects&lt;/li&gt;

&lt;li&gt;Defining New Code definitions for different projects&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Some of the aforementioned features (Quality Gate, Profile, New Code Definitions) are in fact settings that need to be configured in Sonar Cloud. You will need to give your attention to configuring these settings as you will not reap the benefits of fully utilising Sonar Cloud.&lt;/p&gt;

&lt;p&gt;We are going to explore the Sonar Cloud ecosystem and how all of its core features come together to provide you a comprehensive code analysis experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sonar Cloud Ecosystem
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Projects
&lt;/h2&gt;

&lt;p&gt;In Sonar Cloud, a single repository corresponds to a single project. It is how they maintain a unique set of code quality data and metrics for each repository you have. &lt;/p&gt;

&lt;h3&gt;
  
  
  Monorepo Support
&lt;/h3&gt;

&lt;p&gt;Sonar Cloud does support monorepo projects. You can create multiple projects, each corresponding to a separate monorepo project which are all bounded to the same repository. This will allow you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure one Quality Gate per project&lt;/li&gt;
&lt;li&gt;Receive multiple Quality Gate results&lt;/li&gt;
&lt;li&gt;Read project-labeled messages from SonarCloud&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each monorepo project must have a unique project key in Sonar Cloud, which will be used to uniquely identify your projects using your CI tool.&lt;/p&gt;

&lt;p&gt;The standard practice is to have the following naming convention: &lt;code&gt;{organisationName-project-monorepoName}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Project 1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sampleorg-domain-frontend&lt;/span&gt;
&lt;span class="na"&gt;Project 2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sampleorg-domain-backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful if your organisation maintains a big number of monorepo projects across various engineering tribes so the projects can be easily identified in Sonar Cloud. However, you can follow any naming convention you see fit that suits your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Code Definitions
&lt;/h2&gt;

&lt;p&gt;Sonar Cloud follows the concept of &lt;a href="https://sonarcloud.io/documentation/improving/clean-as-you-code/" rel="noopener noreferrer"&gt;Clean As You Code&lt;/a&gt;. The core idea is that you focus your attention and effort on new code. As you work on features and improvements, &lt;strong&gt;SonarCloud analyses your code on each new commit&lt;/strong&gt; and alerts you to any code quality problems and vulnerabilities. This allows you to address the issues right away and ensure that all new code added to the project is always clean. You may read their documentation to find out more information.&lt;/p&gt;

&lt;p&gt;Accompanying this are New Code Definitions. Setting up the right New Code definition for your project is vital to getting the most out of SonarCloud by determining which changes to your code are considered recent enough to merit your full focus and allow you to use the Clean as You Code methodology when addressing issues in your code. There are several options to consider when configuring your New Code Definitions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Previous version:&lt;/strong&gt; Issues in the code that have appeared since the most recent version increment of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific version:&lt;/strong&gt; Issues that have occurred on a specific version of the project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number of days:&lt;/strong&gt; Issues that have appeared on your code since the specified number of days (A numerical number)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific date:&lt;/strong&gt; Issues that have appeared on your code since the specified date&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;When you perform initial code analysis, it does not provide you a "New Code" analysis. Instead, it scans the whole project, providing you with an overall code quality health. As you go along and start analysing new commits, Sonar Cloud will present you with both an &lt;strong&gt;Overall&lt;/strong&gt; and &lt;strong&gt;New&lt;/strong&gt; code quality health analysis (depicted from the picture above).&lt;/p&gt;

&lt;p&gt;You can set a New Code Definition either on a project level or an organisation level, with the latter providing you a way of automatically applying the definitions to new projects that are created.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality Gates
&lt;/h2&gt;

&lt;p&gt;A quality gate is technically a metric of sorts that informs you whether your code meets a minimum level of quality required for the project. This consists of a set of conditions that are applied to the results of each analysis performed. If the results meet or exceed the quality gate conditions, it will show one of the following statuses accordingly: &lt;strong&gt;Passed&lt;/strong&gt; or &lt;strong&gt;Failed&lt;/strong&gt;. You can define conditions on &lt;strong&gt;New Code&lt;/strong&gt; and &lt;strong&gt;Overall Code&lt;/strong&gt;. Some examples of the conditions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coverage is less than 80.0%&lt;/li&gt;
&lt;li&gt;Duplicated Lines is greater than 3.0%&lt;/li&gt;
&lt;li&gt;Maintainability Rating is worse than A&lt;/li&gt;
&lt;li&gt;Reliability Rating is worse than A&lt;/li&gt;
&lt;li&gt;Security Hotspots Reviewed is less than 100%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The quality gates are analysed and calculated on &lt;strong&gt;Main Branch (&lt;code&gt;master&lt;/code&gt; by default)&lt;/strong&gt;, &lt;strong&gt;other Branches,&lt;/strong&gt; and &lt;strong&gt;Pull Requests&lt;/strong&gt;. You can create any number of Quality Gates for your projects and enable them per project, or create a default Quality Gate that will be applied to all projects that have been or will be created.&lt;/p&gt;

&lt;p&gt;An example of a customised Quality Gate is shown below:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Quality Profiles
&lt;/h2&gt;

&lt;p&gt;Quality profiles as you may have guessed it are programming language rules that are applied during code analysis. By default, the programming languages that are supported on Sonar Cloud have a built-in profile, called "Sonar way", using the standard best practices that are currently in the market. Although the "Sonar way" is best suited for most projects, there are cases where engineering tribes would want to customise their profiles that best suit their needs.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Branches
&lt;/h2&gt;

&lt;p&gt;In Sonar Cloud, there are 2 types of branch analysis: &lt;strong&gt;Short-lived branches&lt;/strong&gt; and &lt;strong&gt;Long-lived branches&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Short-Living Branches
&lt;/h3&gt;

&lt;p&gt;As the name suggests, these branches are meant to be used to temporarily perform analysis on them, usually via pull requests. Short-lived branches are deleted automatically after 30 days with no analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-Living Branches
&lt;/h3&gt;

&lt;p&gt;These branches are useful for when tribes follow Agile methodology, utilising Git flow techniques to maintain a set of upstream branches (sprint, release). These branches will remain in your Sonar Cloud project history until it is deleted. Some companies maintain upstream branches for a very long time, hence this option is extremely useful to conduct code analysis on these branches alongside your main branch (&lt;code&gt;master&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining long-living branches
&lt;/h3&gt;

&lt;p&gt;Long-living branches are defined on a project level. Simply navigate to your &lt;strong&gt;Project Settings &amp;gt; Administration &amp;gt; Branches &amp;amp; Pull Requests&lt;/strong&gt;. The long-living branches follow a regular expression pattern.&lt;/p&gt;

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

&lt;p&gt;By default, the pattern is &lt;code&gt;(branch|release)-.*&lt;/code&gt;. This means that when the name of the branch starts with &lt;code&gt;branch-&lt;/code&gt; or &lt;code&gt;release-&lt;/code&gt;, it will be considered a long-living branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Settings
&lt;/h3&gt;

&lt;p&gt;All of the aforementioned concepts and terminologies are in fact project and organisation settings (Quality Gates, Quality Profiles, Long-living branches, New Code Definitions, Monorepo Support). Accompanied with are general settings such as Code Coverage Exclusions, Test File Inclusions and Exclusions, Duplication Inclusions, Source File Exclusions and Inclusions, and many more. You may refer to their &lt;a href="https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to set these up.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;I hope this Part 1 article has provided you with insights on how Sonar Cloud operates and the software engineering quality it follows. Part 2 of this article will provide you a walkthrough on how to set up a Sonar Cloud project with a GitHub repository and perform code analysis using GitHub Actions.&lt;/p&gt;

&lt;p&gt;Image Source: &lt;a href="https://alexandrebrisebois.files.wordpress.com/2014/05/2011-09-18_code_reviews.png" rel="noopener noreferrer"&gt;https://alexandrebrisebois.files.wordpress.com/2014/05/2011-09-18_code_reviews.png&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sonarcloud</category>
      <category>codequality</category>
      <category>cloud</category>
      <category>github</category>
    </item>
    <item>
      <title>Automating mobile application deployments using Fastlane and CI/CD tools</title>
      <dc:creator>Jeiman Jeya</dc:creator>
      <pubDate>Mon, 03 May 2021 14:00:21 +0000</pubDate>
      <link>https://forem.com/jei/automating-mobile-application-deployments-using-fastlane-and-ci-cd-tools-2iae</link>
      <guid>https://forem.com/jei/automating-mobile-application-deployments-using-fastlane-and-ci-cd-tools-2iae</guid>
      <description>&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;




&lt;p&gt;Engineering teams these days find it troublesome to build, test and deploy their mobile application changes locally without having to maintain the tools required for it. There is a lot of maintenance involved as you need to keep track of what versions of these tools have been installed to avoid compatibility issues when you’re building the application bundles, especially hybrid apps built on React Native.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Cure
&lt;/h1&gt;




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

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://fastlane.tools/" rel="noopener noreferrer"&gt;fastlane&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;, an automation tool that aids in handling all of the tedious tasks so you don't have to. It's by far, the easiest way to build and release your mobile apps.&lt;/p&gt;

&lt;p&gt;fastlane can easily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Distribute beta builds to your testers&lt;/li&gt;
&lt;li&gt;Publish a new release to the app store in seconds&lt;/li&gt;
&lt;li&gt;Reliably code sign your application - alleviates all of your headaches&lt;/li&gt;
&lt;li&gt;Reliably maintain your provisioning profiles and application certificates in a Git repository&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How it works
&lt;/h1&gt;




&lt;p&gt;All actions in fastlane are written into &lt;em&gt;lanes&lt;/em&gt;. Defining lanes are easy. Think of them as functions in any programming language of your choosing. You define all of your actions within that lane.&lt;/p&gt;

&lt;p&gt;An example of a &lt;em&gt;lane&lt;/em&gt; is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:beta&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;increment_build_number&lt;/span&gt;
  &lt;span class="n"&gt;build_app&lt;/span&gt;
  &lt;span class="n"&gt;upload_to_testflight&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So when it comes to executing that lane, all you do is run &lt;code&gt;fastlane beta&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation &amp;amp; Setup
&lt;/h1&gt;




&lt;p&gt;In this article, we will look at setting up a fastlane script to build, sign and deploy an iOS application to Testflight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-requisites
&lt;/h2&gt;

&lt;p&gt;As with most projects, you need to perform the initial project setup to support building your application, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing your project dependencies&lt;/li&gt;
&lt;li&gt;Install XCode and Android Studio&lt;/li&gt;
&lt;li&gt;Install Java SDK&lt;/li&gt;
&lt;li&gt;Setup git repository for Android and iOS certificates - &lt;em&gt;will be explained later in the article&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  fastlane folder structure
&lt;/h2&gt;

&lt;p&gt;In ideal cases, you would have an Android application project and an iOS application project, both hosted in the same code repository as your project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;projectFolder/
    app/
    scripts/
    ios/
        fastlane/
            ....
  android/
        fastlane/
            ....
    package.json
    .gitignore
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, you will want to initialise the fastlane folder within the respective &lt;code&gt;android&lt;/code&gt; and &lt;code&gt;ios&lt;/code&gt; project sub-directories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install fastlane 

&lt;ul&gt;
&lt;li&gt;via Homebrew (&lt;code&gt;brew install fastlane&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;via RubyGems (&lt;code&gt;sudo gem install fastlane&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Navigate your terminal to your respective &lt;code&gt;android&lt;/code&gt; and &lt;code&gt;ios&lt;/code&gt; project directory and run &lt;code&gt;fastlane init&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You should have a folder structure that is similar to the one below:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fastlane/
    Fastfile
    Appfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most interesting file is &lt;code&gt;fastlane/Fastfile&lt;/code&gt;, which contains all the information that is needed to distribute your app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inside your &lt;code&gt;Fastfile&lt;/code&gt;, you can start writing lanes:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:my_lane&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Whatever actions you like go in here.&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You can start adding in actions into your lanes. fastlane actions can be found &lt;a href="https://docs.fastlane.tools/actions/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the following file structure to your &lt;code&gt;Fastfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;default_platform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ios&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# You may use Ruby functions to write custom actions for your app deployment&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;platform&lt;/span&gt; &lt;span class="ss"&gt;:ios&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

    &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Building the IPA file only"&lt;/span&gt;
      &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:build_ios_app_ipa&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;app_identifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"com.appbundle.id"&lt;/span&gt;
        &lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"AppSchemeName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;default_platform(:ios)&lt;/code&gt; - Initialise your Fastfile file with a default platform&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;platform :ios do&lt;/code&gt; - Add all actions under a platform&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From 5 to 6, it will inform fastlane that this particular Fastfile is purely for iOS operations. So instead of running the command &lt;code&gt;fastlane &amp;lt;lane_name&amp;gt;&lt;/code&gt;, you will actually run &lt;code&gt;fastlane ios &amp;lt;lane_name&amp;gt;&lt;/code&gt;. Therefore, anything parked under &lt;code&gt;platform :ios do&lt;/code&gt; will be executed when lanes are invoked in your terminal.&lt;/p&gt;

&lt;p&gt;If you are well-versed in Ruby, you may write your own Ruby functions to help you write custom actions that you require for further flexibility, especially when it comes to building several apps with different environments across your organisation. &lt;/p&gt;

&lt;p&gt;fastlane will identify them as an action regardless due to the fact that fastlane is written in &lt;em&gt;Ruby&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this article, we will follow writing the actions using a Ruby function. This is so we can promote action re-usability across other lanes deployments.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Action Steps
&lt;/h1&gt;




&lt;p&gt;Before we start writing our functionality in the lanes, we first list down our action steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Setup API Key for App Store Connect (&lt;code&gt;app_store_connect_api_key&lt;/code&gt;)&lt;/strong&gt; - This will allow fastlane to connect to your App Store to perform other actions that requires user authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setup CI (&lt;code&gt;setup_ci&lt;/code&gt;)&lt;/strong&gt; - This will setup a temporary keychain to work on your CI pipeline of your choice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create and sync provisioning profiles and certificates (&lt;code&gt;match&lt;/code&gt;)&lt;/strong&gt; - This will help us maintain our provisioning profiles and certificates across your teams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update code signing settings (&lt;code&gt;update_code_signing_settings&lt;/code&gt;)&lt;/strong&gt; - This is to update the code signing identities to match your profile name and app bundle identifier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increment your app build number (&lt;code&gt;increment_build_number&lt;/code&gt;)&lt;/strong&gt; - This will automate your application build number by retrieving the latest Testflight build number and incrementing the value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build the app (&lt;code&gt;build_app&lt;/code&gt;)&lt;/strong&gt; - This will build the app for us and generate a binary (IPA) file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upload your binary to Testflight (&lt;code&gt;upload_to_testflight&lt;/code&gt;)&lt;/strong&gt; - This will automate the process of uploading the binary file to Testflight and informing your testers accordingly&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Setup your App Store Connect API key
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Visit the following &lt;a href="https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api" rel="noopener noreferrer"&gt;page&lt;/a&gt;. It will provide you a step-by-step process in generating an API key&lt;/li&gt;
&lt;li&gt;Once you have generated a key, take note of:

&lt;ul&gt;
&lt;li&gt;Issuer ID&lt;/li&gt;
&lt;li&gt;Key ID&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Download the generated API key - A &lt;code&gt;.p8&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Store it in a secure location in which you can easily access them. Avoid storing them in the same repository as anyone in your organisation will have access to the company's Apple account. 

&lt;ul&gt;
&lt;li&gt;In this article, we are storing them in another Git repository with limited read and write scopes to specific engineers within our organisation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Setup the fastlane script
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Setup your App Store API Key to generate a hash used for JWT authorization&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_api_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s2"&gt;"if [ -d &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;appstoreapi&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; ]; then echo 'Folder exist, executing next step'; else git clone &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'APPSTORE_API_GIT_URL'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; appstoreapi; fi"&lt;/span&gt;
  &lt;span class="n"&gt;app_store_connect_api_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="ss"&gt;key_id: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'APPSTORE_KEY_ID'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="ss"&gt;issuer_id: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'APPSTORE_ISSUER_ID'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="ss"&gt;key_filepath: &lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pwd&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"/appstoreapi/AuthKey_xxx.p8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the snippet above, I am cloning a Git repository which contains my App Store Connect API key, followed by utilising the &lt;code&gt;app_store_connect_api_key&lt;/code&gt; action from fastlane. It takes in several parameters, however, there are 3 vital parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;key_id&lt;/code&gt; - The Key ID from which you took note when you generated the API key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;issuer_id&lt;/code&gt; - The Issuer ID from which you took note when you generated the API key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;key_filepath&lt;/code&gt; - The file path to your &lt;code&gt;.p8&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This step will generate a hash that will be used to authenticate the App Store using JWT.&lt;/p&gt;

&lt;p&gt;I would highly recommend storing sensitive credentials or URLs and access them from an Environment Variable (&lt;code&gt;.env&lt;/code&gt;) file in the same project folder - &lt;code&gt;fastlane/.env&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once you have prepared the file, you can easily access any Environment Variable by simply passing in &lt;code&gt;ENV['ENV_NAME']&lt;/code&gt; into the Fastfile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Define a Ruby function with 2 arguments&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within this function, we specify the action steps we mentioned above&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;setup_api_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Import the setup_api_key function&lt;/span&gt;
    &lt;span class="n"&gt;setup_ci&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Uses fastlane action to create a temporary keychain access on a CI pipeline&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Utilise the &lt;code&gt;match&lt;/code&gt; action from fastlane&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;a href="https://docs.fastlane.tools/actions/match/" rel="noopener noreferrer"&gt;match&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt; is a fastlane action that allows you to easily sync your certificates and provisioning profiles. It takes a new approach to iOS and macOS code signing, where you share one code signing identity across your engineering team to simplify the setup and prevent code signing issues. The foundation of &lt;em&gt;match&lt;/em&gt; was built using the implementation of &lt;a href="https://codesigning.guide/" rel="noopener noreferrer"&gt;codesigning.guide concept&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You can store your code signing identities in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Git repository&lt;/li&gt;
&lt;li&gt;Google Cloud&lt;/li&gt;
&lt;li&gt;Amazon S3 bucket&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we have chosen to store it a Git repository. However, with the case of storing in a Git repository, you would need to provide a form of basic authorization in order for match to access and clone your repository.&lt;/p&gt;

&lt;p&gt;Whichever Git provider you choose (GitHub, Bitbucket, Gitlab or Azure DevOps), you would need to setup a Personal Access Token (PAT), which fastlane will use to clone repository and sync your code signing identities.&lt;/p&gt;

&lt;p&gt;In your Fastfile, you will need to encode your PAT with a Base64 encryption&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;authorization_token_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'GITHUB_TOKEN'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;basic_authorization_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strict_encode64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorization_token_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;basic_authorization_token&lt;/code&gt; variable will be used in setting up the match implementation below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;git_url: &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;git_url&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;git_basic_authorization: &lt;/span&gt;&lt;span class="n"&gt;basic_authorization_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;readonly: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;type: &lt;/span&gt;&lt;span class="s2"&gt;"appstore"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;app_identifier: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;bundle_id&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the snippet above, this is a very simple implementation. Take note on the &lt;code&gt;readonly&lt;/code&gt; parameter. This is crucial in creating and syncing your profiles and certs with your Apple Developer account. If you set &lt;code&gt;readonly&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;, you will allow match to automatically sync and create new profiles and certs, should it deem your existing certs and profiles expired or corrupted. Once it has provisioned the profiles, you can set &lt;code&gt;readonly&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;. This is to avoid egde cases where it might accidentally create new certs and profiles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Update code signing identities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This step is mainly used to update the Xcode settings on a CI pipeline due to its default behaviour of selecting a default cert and profile from the Mac OS agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;update_code_signing_settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;use_automatic_signing: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="s2"&gt;"../ios/AppName.xcodeproj"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;code_sign_identity: &lt;/span&gt;&lt;span class="s2"&gt;"iPhone Distribution"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;profile_name: &lt;/span&gt;&lt;span class="s2"&gt;"match AppStore com.appbundle.id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;bundle_identifier: &lt;/span&gt;&lt;span class="s2"&gt;"com.appbundle.id"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the above snippet, you can retrieve your &lt;code&gt;profile_name&lt;/code&gt; and &lt;code&gt;bundle_identifier&lt;/code&gt; from your Apple Developer account or taking note of them from the match step once it has been executed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Increment Application build number&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We simply increment the number by accessing your latest testflight build number and incrementing the value with 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;increment_build_number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="ss"&gt;build_number: &lt;/span&gt;&lt;span class="n"&gt;latest_testflight_build_number&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"BUILD_NUMBER: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;lane_context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;SharedValues&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;BUILD_NUMBER&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;puts&lt;/code&gt; command will print out the Build number in the console, which is shared across the lane context.&lt;/p&gt;

&lt;p&gt;You may have other app build versioning models than the one mentioned in this article. Increment the build number however you see fit to your project needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Build the application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This step will involve building your application to generate a binary (APK) file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;build_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="ss"&gt;workspace: &lt;/span&gt;&lt;span class="s2"&gt;"../ios/AppName.xcworkspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;export_xcargs: &lt;/span&gt;&lt;span class="s2"&gt;"-allowProvisioningUpdates"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;scheme: &lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;clean: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;silent: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;sdk: &lt;/span&gt;&lt;span class="s2"&gt;"iphoneos"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"IPA: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;lane_context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;SharedValues&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;IPA_OUTPUT_PATH&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;build_app&lt;/code&gt; action is provided by fastlane.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;puts&lt;/code&gt; command will print out the file path location of the IPA file in which you can use to manually upload to Testflight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7.  Upload the binary file to Testflight&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This step will involve uploading your binary file to your Testflight account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;app_identifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"com.appbunde.id"&lt;/span&gt;
&lt;span class="n"&gt;upload_to_testflight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;app_identifier: &lt;/span&gt;&lt;span class="n"&gt;app_identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;upload_to_testflight&lt;/code&gt; is an action provided by fastlane.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Putting them all together&lt;/strong&gt;
&lt;/h3&gt;




&lt;p&gt;The final lane should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;"Build and push a new build to TestFlight"&lt;/span&gt;
  &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ss"&gt;:release_build&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;app_identifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"com.appbundle.id"&lt;/span&gt;
    &lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"AppSchemeName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# The custom function we wrote earlier&lt;/span&gt;
    &lt;span class="n"&gt;upload_to_testflight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;app_identifier: &lt;/span&gt;&lt;span class="n"&gt;app_identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you execute &lt;code&gt;fastlane ios release_build&lt;/code&gt; in your terminal, it will operate based on the aforementioned steps above. &lt;/p&gt;

&lt;p&gt;As you can see, we utilised a Ruby function to group all common operations under the same roof so is to ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code re-usability&lt;/li&gt;
&lt;li&gt;Consistency&lt;/li&gt;
&lt;li&gt;Clean code&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Integration with CI/CD tools
&lt;/h1&gt;

&lt;p&gt;With the fastlane scripts, you can easily integrate it with any CI/CD tools of your choosing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Gitlab CI&lt;/li&gt;
&lt;li&gt;Azure Devops&lt;/li&gt;
&lt;li&gt;Bitbucket Pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When setting up your pre-requisite steps in your pipeline YAML file, you can simply include a bash script that executes your fastlane script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;ios&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="n"&gt;folder&lt;/span&gt;

&lt;span class="n"&gt;fastlane&lt;/span&gt; &lt;span class="n"&gt;ios&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="n"&gt;release_build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above will execute your fastlane script by following the aforementioned steps above.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;fastlane is a powerful tool that helps streamline your build process across your organisation. It can be used along side your existing CI/CD pipelines or as a standalone pipeline script to be used on your local machines or custom pipeline tools such as Buildkite. It would require additional steps such as, cloning the repository and checking out branches, however, all readily available from fastlane as actions.&lt;/p&gt;

&lt;p&gt;Spend some time reading through the documentation as it contains &lt;a href="https://docs.fastlane.tools/actions/" rel="noopener noreferrer"&gt;a lot of actions&lt;/a&gt; out of the box that will prove useful for your engineering teams (&lt;a href="https://docs.fastlane.tools/actions/match/" rel="noopener noreferrer"&gt;match&lt;/a&gt;, &lt;a href="https://docs.fastlane.tools/actions/pilot/" rel="noopener noreferrer"&gt;pilot&lt;/a&gt;, &lt;a href="https://docs.fastlane.tools/actions/cert/" rel="noopener noreferrer"&gt;cert&lt;/a&gt;, &lt;a href="https://docs.fastlane.tools/actions/sigh/" rel="noopener noreferrer"&gt;sigh&lt;/a&gt;, &lt;a href="https://docs.fastlane.tools/actions/appium/" rel="noopener noreferrer"&gt;appium&lt;/a&gt;, &lt;a href="https://docs.fastlane.tools/actions/xctool/" rel="noopener noreferrer"&gt;xctool&lt;/a&gt;, &lt;a href="https://docs.fastlane.tools/actions/supply/" rel="noopener noreferrer"&gt;supply&lt;/a&gt;, and &lt;a href="https://docs.fastlane.tools/actions/" rel="noopener noreferrer"&gt;many more&lt;/a&gt;) . Furthermore, they provide an &lt;a href="https://docs.fastlane.tools/plugins/available-plugins/" rel="noopener noreferrer"&gt;extensive list of plugins&lt;/a&gt; for third-party integrations such as Firebase, App Center, Yarn, Android Versioning, Dropbox, Slack Upload, S3, Bugsnag and many more. You can supercharge your fastlane scripts by coupling it with a CI/CD tool, such as GitHub Actions, Bitbucket Pipelines or Azure DevOps. The sky's the limit!&lt;/p&gt;

</description>
      <category>fastlane</category>
      <category>devops</category>
      <category>reactnative</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
