<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ continuous deployment - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ continuous deployment - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 20 May 2026 20:48:00 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/continuous-deployment/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ The CI/CD Handbook: Learn Continuous Integration and Delivery with GitHub Actions, Docker, and Google Cloud Run ]]>
                </title>
                <description>
                    <![CDATA[ Hey everyone! 🌟 If you’re in the tech space, chances are you’ve come across terms like Continuous Integration (CI), Continuous Delivery (CD), and Continuous Deployment. You’ve probably also heard about automation pipelines, staging environments, pro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-continuous-integration-delivery-and-deployment/</link>
                <guid isPermaLink="false">6751d2f856661d3d5a501466</guid>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous delivery ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub Actions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CI/CD ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Prince Onukwili ]]>
                </dc:creator>
                <pubDate>Thu, 05 Dec 2024 16:21:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734119999570/cfbf3375-1e95-41df-b5b0-8fbb8b827f59.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey everyone! 🌟 If you’re in the tech space, chances are you’ve come across terms like <strong>Continuous Integration (CI)</strong>, <strong>Continuous Delivery (CD)</strong>, and <strong>Continuous Deployment</strong>. You’ve probably also heard about automation pipelines, staging environments, production environments, and concepts like testing workflows.</p>
<p>These terms might seem complex or interchangeable at first glance, leaving you wondering: What do they actually mean? How do they differ from one another? 🤔</p>
<p>In this handbook, I’ll break down these concepts in a clear and approachable way, drawing on relatable analogies to make each term easier to understand. 🧠💡 Beyond just theory, we’ll dive into a hands-on tutorial where you’ll learn how to set up a CI/CD workflow step by step.</p>
<p>Together, we’ll:</p>
<ul>
<li><p>Set up a Node.js project. ✨</p>
</li>
<li><p>Implement automated tests using Jest and Supertest. 🛠️</p>
</li>
<li><p>Set up a CI/CD workflow using GitHub Actions, triggered on push, and pull requests, or after a new release. ⚙️</p>
</li>
<li><p>Build and publish a Docker image of your application to Docker Hub. 📦</p>
</li>
<li><p>Deploy your application to a staging environment for testing. 🚀</p>
</li>
<li><p>Finally, roll it out to a production environment, making it live! 🌐</p>
</li>
</ul>
<p>By the end of this guide, not only will you understand the difference between CI/CD concepts, but you’ll also have practical experience in building your own automated pipeline. 😃</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-continuous-integration-deployment-and-delivery"><strong>What is Continuous Integration, Deployment, and Delivery?</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-differences-between-continuous-integration-continuous-delivery-and-continuous-deployment"><strong>Differences Between Continuous Integration, Continuous Delivery, and Continuous Deployment</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-a-nodejs-project-with-a-web-server-and-automated-tests"><strong>How to Set Up a Node.js Project with a Web Server and Automated Tests</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-github-repository-to-host-your-codebase"><strong>How to Create a GitHub Repository to Host Your Codebase</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-ci-and-cd-workflows-within-your-project"><strong>How to Set Up the CI and CD Workflows Within Your Project</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-set-up-a-docker-hub-repository-for-the-projects-image-and-generate-an-access-token-for-publishing-the-image"><strong>Set Up a Docker Hub Repository for the Project's Image and Generate an Access Token for Publishing the Image</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-a-google-cloud-account-project-and-billing-account"><strong>Create a Google Cloud Account, Project, and Billing Account</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-a-google-cloud-service-account-to-enable-deployment-of-the-nodejs-application-to-google-cloud-run-via-the-cd-pipeline"><strong>Create a Google Cloud Service Account to Enable Deployment of the Node.js Application to Google Cloud Run via the CD Pipeline</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-the-staging-branch-and-merge-the-feature-branch-into-it-continuous-integration-and-continuous-delivery"><strong>Create the Staging Branch and Merge the Feature Branch into It (Continuous Integration and Continuous Delivery)</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-merge-the-staging-branch-into-the-main-branch-continuous-integration-and-continuous-deployment"><strong>Merge the Staging Branch into the Main Branch (Continuous Integration and Continuous Deployment)</strong></a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion"><strong>Conclusion</strong></a></p>
</li>
</ol>
<h2 id="heading-what-is-continuous-integration-deployment-and-delivery"><strong>What is Continuous Integration, Deployment, and Delivery?</strong> 🤔</h2>
<h3 id="heading-continuous-integration-ci"><strong>Continuous Integration (CI)</strong></h3>
<p>Imagine you’re part of a team of six developers, all working on the same project. Without a proper system, chaos would ensue.</p>
<p>Let’s say Mr. A is building a new login feature, Mrs. B is fixing a bug in the search bar, and Mr. C is tweaking the dashboard UI—all at the same time. If everyone is editing the same "folder" or codebase directly, things could go horribly wrong: <em>"Hey! Who just broke the app?!"</em> 😱</p>
<p>To keep everything in order, teams use <strong>Version Control Systems (VCS)</strong> like GitHub, GitLab, or BitBucket. Think of it as a digital workspace where everyone can safely collaborate without stepping on each other’s toes. 🗂️✨</p>
<p>Here’s how Continuous Integration fits into this process step-by-step:</p>
<h4 id="heading-1-the-main-branch-the-general-folder">1. <strong>The Main Branch: The General Folder</strong> ✨</h4>
<p>At the heart of every project is the <strong>main branch</strong>—the ultimate source of truth. It contains the stable codebase that powers your live app. It’s where every team member contributes their work, but with one important rule: only tested and approved code gets merged here. 🚀</p>
<h4 id="heading-2-feature-branches-personal-workspaces">2. <strong>Feature Branches: Personal Workspaces</strong> 🔨</h4>
<p>When someone like Mr. A wants to work on a new feature, they create a <strong>feature branch</strong>. This branch is essentially a personal copy of the main branch where they can tinker, write code, and test without affecting others. Mrs. B and Mr. C are also working on their own branches. Everyone’s experiments stay neatly organized. 🧪💡</p>
<h4 id="heading-3-merging-changes-the-ci-workflow">3. <strong>Merging Changes: The CI Workflow</strong> 🎉</h4>
<p>When Mr. A is satisfied with his feature, he doesn’t just shove it into the main branch—CI ensures it’s done safely:</p>
<ul>
<li><p><strong>Automated Tests</strong>: Before merging, CI tools automatically run tests on Mr. A’s code to check for bugs or errors. Think of it as a bouncer guarding the main branch, ensuring no bad code gets in. 🕵️‍♂️</p>
</li>
<li><p><strong>Build Verification</strong>: The feature branch code is also "built" (converted into a deployable version of the app) to confirm it works as intended.</p>
</li>
</ul>
<p>Once these checks are passed, Mr. A’s feature branch is merged into the main branch. This frequent merging of changes is what we call <strong>Continuous Integration</strong>.</p>
<h3 id="heading-continuous-delivery-cd">Continuous Delivery (CD)</h3>
<p>Continuous Delivery (CD) often gets mixed up with Continuous Deployment, and while they share similarities, they serve distinct purposes in the development lifecycle. Let’s break it down! 🧐</p>
<h4 id="heading-the-need-for-a-staging-area">The Need for a <code>Staging</code> Area 🌉</h4>
<p>In the Continuous Integration (CI) process we discussed above, we primarily dealt with <strong>feature branches</strong> and the <strong>main branch</strong>. But directly merging changes from feature branches into the main branch (which powers the live product) can be risky. Why? 🛑</p>
<p>While automated tests and builds catch many errors, they’re not foolproof. Some edge cases or bugs might slip through unnoticed. This is where the <strong>staging branch</strong> and <strong>staging environment</strong> come into play! 🎭</p>
<p>Think of the staging branch as a “trial run.” Before unleashing changes to real customers, the codebase from feature branches is merged into the staging branch and deployed to a <strong>staging environment</strong>. This environment is an exact replica of the production environment, but it’s used exclusively by the <strong>Quality Assurance (QA) team</strong> for testing.</p>
<p>The QA team takes the role of a “test driver,” running the platform through its paces just as a real user would. They check for usability issues, edge cases, or bugs that automated tests might miss, and provide feedback to developers for fixes. 🚦 If everything passes, the codebase is cleared for deployment to production.</p>
<h4 id="heading-continuous-delivery-in-action">Continuous Delivery in Action 📦</h4>
<p>The process of merging changes into the staging branch and deploying them to the <strong>staging environment</strong> is what we call <strong>Continuous Delivery</strong>. 🛠️ It ensures that the application is always in a deployable state, ready for the next step in the pipeline.</p>
<p>Unlike Continuous Deployment (which we’ll discuss later), Continuous Delivery doesn’t automatically push changes to production (live platform). Instead, it pauses to let humans—namely the QA team or stakeholders—decide when to proceed. This adds an extra layer of quality assurance, reducing the chances of errors making it to the live product. 🕵️‍♂️</p>
<h3 id="heading-continuous-deployment-cd">Continuous Deployment (CD)</h3>
<p>Continuous Deployment (CD) takes automation to its peak. While it shares similarities with Continuous Delivery, the key difference lies in the <strong>final step</strong>: there’s no manual approval required. The final process—merging the codebase and deploying it live for end users (the QA testers or the team lead could do this).</p>
<p>Let’s explore what makes Continuous Deployment so powerful (and a little scary)! 😅</p>
<h4 id="heading-the-last-mile-of-the-cicd-pipeline">The Last Mile of the CI/CD Pipeline 🛣️</h4>
<p>Imagine you’ve gone through the rigorous process of Continuous Integration: teammates have merged their feature branches, automated tests were run, and the codebase was successfully deployed to the staging environment during Continuous Delivery.</p>
<p>Now, you’re confident that the application is free of bugs and ready to shine in the production environment—the live version of your platform used by real customers.</p>
<p>In <strong>Continuous Deployment</strong>, this final step of deploying changes to the live environment happens <strong>automatically</strong>. The pipeline triggers whenever specific events occur, such as:</p>
<ul>
<li><p>A <strong>Pull Request (PR)</strong> is merged into the <strong>main branch</strong>.</p>
</li>
<li><p>A new <strong>release version</strong> is created.</p>
</li>
<li><p>A <strong>commit</strong> is pushed directly to the production branch (though this is rare for most teams).</p>
</li>
</ul>
<p>Once triggered, the pipeline springs into action, building, testing, and finally deploying the updated codebase to the production environment. 📡</p>
<h2 id="heading-differences-between-continuous-integration-continuous-delivery-and-continuous-deployment"><strong>Differences Between Continuous Integration, Continuous Delivery, and Continuous Deployment</strong> 🔍</h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Aspect</td><td>Continuous Integration (CI)</td><td>Continuous Delivery (CD)</td><td>Continuous Deployment (CD)</td></tr>
</thead>
<tbody>
<tr>
<td>Primary Focus</td><td>Merging feature branches into the main/general codebase OR to the staging codebase.</td><td>Deploying the tested code to a staging environment for QA testing and approval.</td><td>Automatically deploying the code to the live production environment.</td></tr>
<tr>
<td><strong>Automation Level</strong></td><td>Automates testing and building processes for feature branches.</td><td>Automates deployment to staging/test environments after successful testing.</td><td>Fully automates the deployment to production with no manual approval.</td></tr>
<tr>
<td><strong>Testing Scope</strong></td><td>Automated tests run on feature branches to ensure code quality before merging into the main or staging branch.</td><td>Includes automated tests before deployment to staging and allows QA testers to perform manual testing in a controlled environment.</td><td>May include automated tests as a final check, ensuring the production environment is stable before deployment.</td></tr>
<tr>
<td><strong>Branch Involved</strong></td><td>Feature branches merging into the main/general or staging branch.</td><td>Staging branch used as an intermediate step before merging into the main branch.</td><td>Main/general branch deployed directly to production.</td></tr>
<tr>
<td><strong>Environment Target</strong></td><td>Ensures integration and testing within a local environment or build pipeline.</td><td>Deploys to staging/test environments where QA testers validate features.</td><td>Deploys to production/live environment accessed by end users.</td></tr>
<tr>
<td><strong>Key Goal</strong></td><td>Prevent integration conflicts and ensure new changes don’t break the existing codebase.</td><td>Provide a stable, near-production environment for thorough QA testing before final deployment.</td><td>Ensure that new features and updates reach users as soon as possible with minimal delays.</td></tr>
<tr>
<td><strong>Approval Process</strong></td><td>No approval needed. Feature branches are tested and merged upon passing criteria.</td><td>QA team or lead provides feedback/approval before changes are merged into the main branch for production.</td><td>No manual approval. Deployment is entirely automated.</td></tr>
<tr>
<td><strong>Example Trigger</strong></td><td>A developer merges a feature branch into the main branch.</td><td>The staging branch passes automated tests (during PR) and is ready for deployment to the testing environment.</td><td>A new release is created or a pull request is merged into the main branch, triggering an automatic production deployment.</td></tr>
</tbody>
</table>
</div><p>Now that we’ve untangled the mysteries of Continuous Integration, Continuous Delivery, and Continuous Deployment, it’s time to roll up our sleeves and put theory into practice 😁.</p>
<h2 id="heading-how-to-set-up-a-nodejs-project-with-a-web-server-and-automated-tests"><strong>How to Set Up a Node.js Project with a Web Server and Automated Tests</strong> ✨</h2>
<p>In this hands-on section, we’ll build a Node.js web server with automated tests using Jest. From there, we’ll create a CI/CD pipeline with GitHub Actions that automates testing for every <strong>pull request to the staging and main branches</strong>. Finally, we’ll publish an Image of our application to DockerHub and deploy the image to <strong>Google Cloud Run</strong>, first to a staging environment for testing and later to the production environment for live use.</p>
<p>Ready to bring your project to life? Let’s get started! 🚀✨</p>
<h3 id="heading-step-1-install-nodejs">Step 1: Install Node.js 📥</h3>
<p>To get started, you’ll need to have <strong>Node.js</strong> installed on your machine. Node.js provides the JavaScript runtime we’ll use to create our web server.</p>
<ol>
<li><p>Visit <a target="_blank" href="https://nodejs.org/en/download/package-manager">https://nodejs.org/en/download/package-manager</a></p>
</li>
<li><p>Choose your operating system (Windows, macOS, or Linux) and download the installer.</p>
</li>
<li><p>Follow the installation instructions to complete the setup.</p>
</li>
</ol>
<p>To verify that Node.js was installed successfully, open your terminal and run <code>node -v</code>. This should display the installed version of Node.js</p>
<h3 id="heading-step-2-clone-the-starter-repository">Step 2: Clone the Starter Repository 📂</h3>
<p>The next step is to grab the starter code from GitHub. If you don’t have Git installed, you can download it at <a target="_blank" href="https://git-scm.com/downloads">https://git-scm.com/downloads</a>. Choose your OS and follow the instructions to install Git. Once you’re set, it’s time to clone the repository.</p>
<p>Run the following command in your terminal to clone the boilerplate code:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> --single-branch --branch initial https://github.com/onukwilip/ci-cd-tutorial
</code></pre>
<p>This will download the project files from the <code>initial</code> branch, which contains the starter template for our Node.js web server.</p>
<p>Navigate into the project directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ci-cd-tutorial
</code></pre>
<h3 id="heading-step-3-install-dependencies">Step 3: Install Dependencies 📦</h3>
<p>Once you’re in the project directory, install the required dependencies for the Node.js project. These are the packages that power the application:</p>
<pre><code class="lang-bash">npm install --force
</code></pre>
<p>This will download and set up all the libraries specified in the project. Alright, dependencies installed? You’re one step closer!</p>
<h3 id="heading-step-4-run-automated-tests">Step 4: Run Automated Tests ✅</h3>
<p>Before diving into the code, let’s confirm that the automated tests are functioning correctly. Run:</p>
<pre><code class="lang-bash">npm <span class="hljs-built_in">test</span>
</code></pre>
<p>You should see two successful test results in your terminal. This indicates that the starter project is correctly configured with working automated tests.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733074280408/93b4ea86-1dfa-42eb-a163-b97c19c2a053.png" alt="Successful test run" class="image--center mx-auto" width="1615" height="387" loading="lazy"></p>
<h3 id="heading-step-5-start-the-web-server">Step 5: Start the Web Server 🌐</h3>
<p>Finally, let’s start the web server and see it in action. Run the following command:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>Wait for the application to start running. Open your browser and visit <a target="_blank" href="http://localhost:5000/">http://localhost:5000</a>. 🎉 You should see the starter web server up and running, ready for your CI/CD magic:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733074667521/7b80bb21-1f43-430e-8a56-2bff8b81ddad.png" alt="Successful project run" class="image--center mx-auto" width="1920" height="225" loading="lazy"></p>
<h2 id="heading-how-to-create-a-github-repository-to-host-your-codebase"><strong>How to Create a GitHub Repository to Host Your Codebase 📂</strong></h2>
<h3 id="heading-step-1-sign-in-to-github">Step 1: Sign In to GitHub</h3>
<ol>
<li><p><strong>Go to GitHub</strong>: Open your browser and visit GitHub - <a target="_blank" href="https://github.com/">https://github.com</a>.</p>
</li>
<li><p><strong>Sign In</strong>: Click on the <strong>Sign In</strong> button in the top-right corner and enter your username and password to log in, OR create an account if you don’t have one by clicking the <strong>Sign up</strong> button.</p>
</li>
</ol>
<h3 id="heading-step-2-create-a-new-repository">Step 2: Create a New Repository</h3>
<p>Once you're signed in, on the main GitHub page, you’ll see a "+" sign in the top-right corner next to your profile picture. Click on it, and select <strong>“New repository”</strong> from the dropdown.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733130465203/dac28dee-74da-4fd4-8a96-bc90aef01207.png" alt="New GitHub repository" class="image--center mx-auto" width="1381" height="382" loading="lazy"></p>
<p>Now it’s time to set the repository details. You’ll include:</p>
<ul>
<li><p><strong>Repository Name</strong>: Choose a name for your repository. For example, you can call it <code>ci-cd-tutorial</code>.</p>
</li>
<li><p><strong>Description</strong> (Optional): You can add a short description, like “A tutorial project for CI/CD with Docker and GitHub Actions.”</p>
</li>
<li><p><strong>Visibility</strong>: Choose whether you want your repository to be <strong>public</strong> (accessible by anyone) or <strong>private</strong> (only accessible by you and those you invite). For the sake of this tutorial, make it <strong>public</strong>.</p>
</li>
<li><p><strong>Do Not Check the Add a README File Box</strong>: <strong>Important</strong>: Make sure you <strong>do not check</strong> the option to <strong>Add a README file</strong>. This will automatically create a <code>README.md</code> file in your repository, which could cause conflicts later when you push your local files. We'll add the README file manually if needed later.</p>
</li>
</ul>
<p>After filling out the details, click on <strong>“Create repository”</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733130890582/04e09ac8-0ee6-4d26-a9f2-007c0e6ca08f.png" alt="Create GitHub repository" class="image--center mx-auto" width="753" height="991" loading="lazy"></p>
<h3 id="heading-step-3-change-the-remote-destination-and-push-to-your-new-repository">Step 3: Change the Remote Destination and Push to Your New Repository</h3>
<h4 id="heading-update-the-remote-repository-url"><strong>Update the Remote Repository URL</strong>:</h4>
<p>Since you've already cloned the codebase from my repository, you need to update the remote destination to point to your newly created GitHub repository.</p>
<p>Copy your repository URL (the URL of the page you were redirected to after creating the repository). It should look similar to this: <code>https://github.com/&lt;username&gt;/&lt;repo-name&gt;</code>.</p>
<p>Open your terminal in the project directory and run the following commands:</p>
<pre><code class="lang-bash">git remote set-url origin &lt;your-repo-url&gt;
</code></pre>
<p>Replace <code>&lt;your-repo-url&gt;</code> with your GitHub repository URL which you copied earlier.</p>
<h4 id="heading-rename-the-current-branch-to-main"><strong>Rename the Current Branch to</strong> <code>main</code>:</h4>
<p>If your branch is named something other than <code>main</code>, you can rename it to <code>main</code> using:</p>
<pre><code class="lang-bash">git branch -M main
</code></pre>
<h4 id="heading-push-to-your-new-repository"><strong>Push to Your New Repository</strong>:</h4>
<p>Finally, commit any changes you’ve made and push your local repository to the new remote GitHub repository by running:</p>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">'Created boilerplate'</span>
git push -u origin main
</code></pre>
<p>Now your local codebase is linked to your new GitHub repository, and the files are successfully pushed there. You can verify by visiting your repository on GitHub.</p>
<h2 id="heading-how-to-set-up-the-ci-and-cd-workflows-within-your-project">How to Set Up the CI and CD Workflows Within Your Project ⚙️</h2>
<p>Now it’s time to create the <strong>CI and CD workflows</strong> for our project! These workflows won’t run on your local PC but will be automatically triggered and executed in the cloud once you push your changes to the remote repository. GitHub Actions will detect these workflows and run them based on the triggers you define.</p>
<h3 id="heading-step-1-prepare-the-workflow-directory">Step 1: Prepare the Workflow Directory 📂</h3>
<p>Before adding the CI/CD pipelines, it's a good practice to first create a feature branch. This step mirrors the workflow commonly used in teams, where new features or changes are made in separate branches before they are merged into the main codebase.</p>
<p>To create and switch to a new branch, run the following command:</p>
<pre><code class="lang-bash">git checkout -b feature/ci-cd-pipeline
</code></pre>
<p>This will create a new branch called <code>feature/ci-cd-pipeline</code> and switch to it. Now, you can safely add and test the CI/CD workflows without affecting the main branch.</p>
<p>Once you finish, you’ll be able to merge this feature branch back into <code>main</code> or <code>staging</code> as part of the pull request process.</p>
<p>In the project’s root directory, create a folder named <code>.github</code>. Inside <code>.github</code>, create another folder called <code>workflows</code>.</p>
<p>Any YAML file placed in the <code>.github/workflows</code> directory is automatically recognized as a GitHub Actions workflow. These workflows will execute based on specific triggers, such as pull requests, pushes, or releases.</p>
<h3 id="heading-step-2-create-the-continuous-integration-workflow">Step 2: Create the Continuous Integration Workflow 🚀</h3>
<p>We’ll now create a CI workflow that automatically tests the application whenever a pull request is made to the <code>main</code> or <code>staging</code> branches.</p>
<p>First, inside the <code>workflows</code> directory, create a file named <code>ci-pipeline.yml</code>.</p>
<p>Paste the following code into the file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">CI</span> <span class="hljs-string">Pipeline</span> <span class="hljs-string">to</span> <span class="hljs-string">staging/production</span> <span class="hljs-string">environment</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">staging</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Setup,</span> <span class="hljs-string">test,</span> <span class="hljs-string">and</span> <span class="hljs-string">build</span> <span class="hljs-string">project</span>
    <span class="hljs-attr">env:</span>
      <span class="hljs-attr">PORT:</span> <span class="hljs-number">5001</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Test</span> <span class="hljs-string">application</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">application</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          echo "Run command to build the application if present"
          npm run build --if-present</span>
</code></pre>
<h4 id="heading-explanation-of-the-ci-workflow">Explanation of the CI Workflow</h4>
<p>Here’s a breakdown of each section in the workflow:</p>
<ol>
<li><p><code>name: CI Pipeline to staging/production environment</code>: This is the title of your workflow. It helps you identify this pipeline in GitHub Actions.</p>
</li>
<li><p><code>on</code>: The <code>on</code> parameter is what determines the events that trigger your workflow. When the workflow YAML file is pushed to the remote GitHub repository, GitHub Actions automatically registers the workflow using the configured triggers in the <code>on</code> field. These triggers act as event listeners that tell GitHub when to execute the workflow</p>
<p> <strong>For example:</strong></p>
<p> If we set <code>pull_request</code> as the value for the <code>on</code> parameter and specify the branches we want to monitor using the <code>branches</code> key, GitHub sets up event listeners for pull requests to those branches.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">on:</span>
   <span class="hljs-attr">pull_request:</span>
     <span class="hljs-attr">branches:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">staging</span>
</code></pre>
<p> This configuration means that GitHub will trigger the workflow whenever a pull request is made to the <code>main</code> or <code>staging</code> branches.</p>
<p> <strong>Multiple Triggers</strong>:<br> You can define multiple event listeners in the <code>on</code> parameter. For instance, in addition to pull requests, you can add a listener for push events.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">on:</span>
   <span class="hljs-attr">pull_request:</span>
     <span class="hljs-attr">branches:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">staging</span>
   <span class="hljs-attr">push:</span>
     <span class="hljs-attr">branches:</span>
       <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
</code></pre>
<p> This configuration ensures that the workflow is triggered when:</p>
<ul>
<li><p>A pull request is made to either the <code>main</code> or <code>staging</code> branch.</p>
</li>
<li><p>A push is made directly to the <code>main</code> branch.</p>
</li>
</ul>
</li>
</ol>
<p>    📘 <strong>Learn more about triggers:</strong> Check out the <a target="_blank" href="https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows">official GitHub documentation here</a>.</p>
<ol start="3">
<li><p><code>jobs</code>: The <code>jobs</code> section outlines the specific tasks (or jobs) that the workflow will execute. Each job is an independent unit of work that runs on a separate virtual machine (VM). This isolation ensures a clean, unique environment for every job, avoiding potential conflicts between tasks.</p>
<p> <strong>Key Points About Jobs:</strong></p>
<ol>
<li><p><strong>Clean VM for Each Job</strong>: When GitHub Actions runs a workflow, it assigns a dedicated VM instance to each job. This means the environment is reset for every job, ensuring there’s no overlap or interference between tasks.</p>
</li>
<li><p><strong>Multiple Jobs</strong>: Workflows can have multiple jobs, each responsible for a specific task. For example:</p>
<ul>
<li><p>A <strong>Test</strong> job to install dependencies and run automated tests.</p>
</li>
<li><p>A <strong>Build</strong> job to compile the application.</p>
</li>
</ul>
</li>
<li><p><strong>Job Organization</strong>: Jobs can be organized to run:</p>
<ul>
<li><p><strong>Sequentially</strong>: Ensures one job is completed before the next starts, for example the Test job must finish before the Build job. This sequential flow mimics the "pipeline" structure.</p>
</li>
<li><p><strong>Simultaneously</strong>: Multiple jobs can run in parallel to save time, especially if the jobs are independent of one another.</p>
</li>
</ul>
</li>
<li><p><strong>Single Job in This Workflow</strong>: In our current workflow, there is only one job, <code>test</code>, which:</p>
<ul>
<li><p>Installs dependencies.</p>
</li>
<li><p>Runs automated tests.</p>
</li>
<li><p>Builds the application.</p>
</li>
</ul>
</li>
</ol>
</li>
</ol>
<p>    📘 <strong>Learn more about jobs:</strong> Dive into the <a target="_blank" href="https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-jobs-in-a-workflow">GitHub Actions jobs documentation here</a>.</p>
<ol start="4">
<li><p><code>runs-on: ubuntu-latest</code>: Specifies the operating system the job will run on. GitHub provides pre-configured virtual environments, and we’re using the latest Ubuntu image.</p>
</li>
<li><p><code>env</code>: Sets environment variables for the job. Here, we define the <strong>PORT</strong> variable used by our application.</p>
</li>
<li><p><strong>Steps</strong>: Steps define the individual actions to execute within a job:</p>
<ul>
<li><p><code>Checkout</code>: Uses the <code>actions/checkout</code> action to clone the repository containing the codebase in the feature branch into the virtual machine instance environment. This step ensures the pipeline has access to the project files.</p>
</li>
<li><p><code>Install dependencies</code>: Runs <code>npm ci</code> to install the required Node.js packages.</p>
</li>
<li><p><code>Test application</code>: Runs the automated tests using the <code>npm test</code> command. This validates the codebase for errors or failing test cases.</p>
</li>
<li><p><code>Build application</code>: Builds the application if a build script is defined in the <code>package.json</code>. The <code>--if-present</code> flag ensures this step doesn’t fail if no build script is present.</p>
</li>
</ul>
</li>
</ol>
<p>Now that we’ve completed the CI pipeline, which runs on pull requests to the <code>main</code> or <code>staging</code> branches, let’s move on to setting up the <strong>Continuous Delivery (CD)</strong> and <strong>Continuous Deployment</strong> pipelines. 🚀</p>
<h3 id="heading-step-3-the-continuous-delivery-and-deployment-workflow">Step 3: The Continuous Delivery and Deployment Workflow</h3>
<p><strong>First, create the Pipeline File</strong>:<br>In the <code>.github/workflows</code> folder, create a new file called <code>cd-pipeline.yml</code>. This file will define the workflows for automating delivery and deployment.</p>
<p><strong>Next, paste the configuration</strong>:<br>Copy and paste the following configuration into the <code>cd-pipeline.yml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">CD</span> <span class="hljs-string">Pipeline</span> <span class="hljs-string">to</span> <span class="hljs-string">Google</span> <span class="hljs-string">Cloud</span> <span class="hljs-string">Run</span> <span class="hljs-string">(staging</span> <span class="hljs-string">and</span> <span class="hljs-string">production)</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">staging</span>
  <span class="hljs-attr">workflow_dispatch:</span> {}
  <span class="hljs-attr">release:</span>
    <span class="hljs-attr">types:</span> <span class="hljs-string">published</span>

<span class="hljs-attr">env:</span>
  <span class="hljs-attr">PORT:</span> <span class="hljs-number">5001</span>
  <span class="hljs-attr">IMAGE:</span> <span class="hljs-string">${{vars.IMAGE}}:${{github.sha}}</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Setup,</span> <span class="hljs-string">test,</span> <span class="hljs-string">and</span> <span class="hljs-string">build</span> <span class="hljs-string">project</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Test</span> <span class="hljs-string">application</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">needs:</span> <span class="hljs-string">test</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">project,</span> <span class="hljs-string">Authorize</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Actions</span> <span class="hljs-string">to</span> <span class="hljs-string">GCP</span> <span class="hljs-string">and</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Hub,</span> <span class="hljs-string">and</span> <span class="hljs-string">deploy</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Authenticate</span> <span class="hljs-string">for</span> <span class="hljs-string">GCP</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">gcp-auth</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">google-github-actions/auth@v0</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">credentials_json:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GCP_SERVICE_ACCOUNT</span> <span class="hljs-string">}}</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Cloud</span> <span class="hljs-string">SDK</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">google-github-actions/setup-gcloud@v0</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Authenticate</span> <span class="hljs-string">for</span> <span class="hljs-string">Docker</span> <span class="hljs-string">Hub</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">docker-auth</span>
        <span class="hljs-attr">env:</span>
          <span class="hljs-attr">D_USER:</span> <span class="hljs-string">${{secrets.DOCKER_USER}}</span>
          <span class="hljs-attr">D_PASS:</span> <span class="hljs-string">${{secrets.DOCKER_PASSWORD}}</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          docker login -u $D_USER -p $D_PASS
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">and</span> <span class="hljs-string">tag</span> <span class="hljs-string">Image</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          docker build -t ${{env.IMAGE}} .
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Push</span> <span class="hljs-string">the</span> <span class="hljs-string">image</span> <span class="hljs-string">to</span> <span class="hljs-string">Docker</span> <span class="hljs-string">hub</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          docker push ${{env.IMAGE}}
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Enable</span> <span class="hljs-string">the</span> <span class="hljs-string">Billing</span> <span class="hljs-string">API</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          gcloud services enable cloudbilling.googleapis.com --project=${{secrets.GCP_PROJECT_ID}}
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GCP</span> <span class="hljs-string">Run</span> <span class="hljs-bullet">-</span> <span class="hljs-string">Production</span> <span class="hljs-string">environment</span> <span class="hljs-string">(If</span> <span class="hljs-string">a</span> <span class="hljs-string">new</span> <span class="hljs-string">release</span> <span class="hljs-string">was</span> <span class="hljs-string">published</span> <span class="hljs-string">from</span> <span class="hljs-string">the</span> <span class="hljs-string">master</span> <span class="hljs-string">branch)</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'release'</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">github.event.action</span> <span class="hljs-string">==</span> <span class="hljs-string">'published'</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">github.event.release.target_commitish</span> <span class="hljs-string">==</span> <span class="hljs-string">'main'</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          gcloud run deploy ${{vars.GCR_PROJECT_NAME}} \
          --region ${{vars.GCR_REGION}} \
          --image ${{env.IMAGE}} \
          --platform "managed" \
          --allow-unauthenticated \
          --tag production \
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GCP</span> <span class="hljs-string">Run</span> <span class="hljs-bullet">-</span> <span class="hljs-string">Staging</span> <span class="hljs-string">environment</span>
        <span class="hljs-attr">if:</span> <span class="hljs-string">github.ref</span> <span class="hljs-type">!=</span> <span class="hljs-string">'refs/heads/main'</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          echo "Deploying to staging environment"
          # Deploy service with to staging environment
          gcloud run deploy ${{vars.GCR_STAGING_PROJECT_NAME}} \
          --region ${{vars.GCR_REGION}} \
          --image ${{env.IMAGE}} \
          --platform "managed" \
          --allow-unauthenticated \
          --tag staging \</span>
</code></pre>
<p>The <strong>CD pipeline</strong> configuration combines Continuous Delivery and Continuous Deployment workflows into a single file for simplicity. It builds on the concepts of CI/CD we discussed earlier, automating testing, building, and deploying the application to Google Cloud Run.</p>
<h4 id="heading-explanation-of-the-cd-pipeline">Explanation of the CD pipeline:</h4>
<ol>
<li><h4 id="heading-workflow-triggers-on">Workflow Triggers (<code>on</code>)</h4>
</li>
</ol>
<ul>
<li><p><code>push</code>: Workflow triggers on pushes to the <code>staging</code> branch.</p>
</li>
<li><p><code>workflow_dispatch</code>: Enables manual execution of the workflow via the GitHub Actions interface.</p>
</li>
<li><p><code>release</code>: Triggers when a new release is published.<br>  Example: When a release is published from the <code>main</code> branch, the app deploys to the production environment.</p>
</li>
</ul>
<ol start="2">
<li><p><strong>Job 1 – Testing the Codebase:</strong> The first job in the pipeline, Test, ensures the codebase is functional and error-free before proceeding with delivery or deployment</p>
</li>
<li><p><strong>Job 2 – Building and Deploying the Application:</strong> Aha! Moment ✨: These jobs run sequentially. 😃 The <strong>Build</strong> job begins only after the <strong>Test</strong> job is completed successfully. It prepares the application for deployment and manages the actual deployment process.</p>
<p> Here's what happens:</p>
<ul>
<li><p><strong>Authorization for GCP and Docker Hub</strong>: The workflow authenticates with both Google Cloud Platform (GCP) and Docker Hub. For GCP, it uses the <code>google-github-actions/auth@v0</code> action to handle service account credentials stored as secrets. Similarly, it logs into Docker Hub with stored credentials to enable image uploads.</p>
</li>
<li><p><strong>Build and Push Docker Image</strong>: The application is built into a Docker image and tagged with a unique identifier (<code>${{env.IMAGE}}</code>). This image is then pushed to Docker Hub, making it accessible for deployment.</p>
</li>
<li><p><strong>Deploy to Google Cloud Run</strong>: Based on the event that triggered the workflow, the application is <strong>deployed to either the staging or production environment</strong> in Google Cloud Run. A <strong>push</strong> to the <code>staging</code> branch deploys to the staging environment (Continuous Delivery), while a <strong>release</strong> from the <code>main</code> branch deploys to production (Continuous Deployment).</p>
</li>
</ul>
</li>
</ol>
<p>To ensure the security and flexibility of our pipeline, we rely on external variables and secrets rather than hardcoding sensitive information directly into the workflow file.</p>
<p>Why? Workflow configuration files are part of your repository and accessible to anyone with access to the codebase. If sensitive data, like API keys or passwords, is exposed here, it can be easily compromised. 😨</p>
<p>Instead, we use GitHub’s <strong>Secrets</strong> to securely store and access this information. Secrets allow us to define variables that are encrypted and only accessible by our workflows. For example:</p>
<ul>
<li><p><strong>DockerHub Credentials</strong>: We’ll add a Docker username and access token to the repository’s secrets. These are essential for authenticating with DockerHub to upload the built Docker images.</p>
</li>
<li><p><strong>Google Cloud Service Account Key</strong>: This key will grant the pipeline the necessary permissions to deploy the application on <strong>Google Cloud Run</strong> securely.</p>
</li>
</ul>
<p>We'll set up these variables and secrets incrementally as we proceed, ensuring each step is fully secure and functional. 🎯</p>
<h2 id="heading-set-up-a-docker-hub-repository-for-the-projects-image-and-generate-an-access-token-for-publishing-the-image"><strong>Set Up a Docker Hub Repository for the Project's Image and Generate an Access Token for Publishing the Image</strong> 📦</h2>
<p>Before we dive into the steps, let’s quickly go over what we’re about to do. In this section, you’ll learn how to create a Docker Hub repository, which acts like an online storage space for your application’s container image.</p>
<p>Think of a container image as a snapshot of your application, ready to be deployed anywhere. To ensure smooth and secure access, we’ll also generate a special access token, kind of like a revokable password that our CI/CD pipeline can use to upload your app’s image to Docker Hub. Let’s get started! 🚀</p>
<h3 id="heading-step-1-sign-up-for-docker-hub">Step 1: Sign Up for Docker Hub</h3>
<p>Here are the steps to follow to sign up for Docker Hub:</p>
<ol>
<li><p><strong>Go to the Docker Hub website</strong>: Open your web browser and visit Docker Hub - <a target="_blank" href="https://hub.docker.com/">https://hub.docker.com/</a>.</p>
</li>
<li><p><strong>Create an account</strong>: On the Docker Hub homepage, you’ll see a button labelled <strong>"Sign Up"</strong> in the top-right corner. Click on it.</p>
</li>
<li><p><strong>Fill in your details</strong>: You'll be asked to provide a few details like your username, email address, and password. Choose a strong password that you can remember.</p>
</li>
<li><p><strong>Agree to the terms</strong>: You’ll need to check a box to agree to Docker’s terms of service. After that, click <strong>“Sign Up”</strong> to create your account.</p>
</li>
<li><p><strong>Verify your email</strong>: Docker Hub will send you an email to verify your account. Open that email and click on the verification link to complete your account creation.</p>
</li>
</ol>
<h3 id="heading-step-2-sign-in-to-docker-hub">Step 2: Sign In to Docker Hub</h3>
<p>After verifying your email, go back to Docker Hub, and click on <strong>"Sign In"</strong> at the top right. Then you can use the credentials you just created to log in.</p>
<h3 id="heading-step-3-generate-an-access-token-for-the-cicd-pipeline">Step 3: Generate an Access Token (for the CI/CD pipeline)</h3>
<p>Now that you have an account, you can create an access token. This token will allow your GitHub Actions workflow to securely sign into Docker Hub and upload Docker images.</p>
<p>Once you’re logged into Docker Hub, click on your profile picture (or avatar) in the top right corner. This will open a menu. From the menu, click “Account Settings”.</p>
<p>Then in the left-hand menu of your account settings, scroll to the <strong>"Security"</strong> tab. This section is where you manage your tokens and passwords.</p>
<p>Now you’ll need to create a new access token. In the Security tab, you’ll see a link labelled <strong>“Personal access tokens”</strong> – click on it. Click the button labelled <strong>“Generate new token”</strong>.</p>
<p>You’ll be asked to give your token a description. You can name it something like "GitHub Actions CI/CD" so that you know what it's for.</p>
<p>After giving it a description, click on the “<strong>Access permissions dropdown</strong>“ and select <strong>“Read &amp; Write“,</strong> or <strong>“Read, Write, Delete“</strong>. Click “<strong>Generate</strong>“</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733129374816/c725f041-c0ef-49a0-b8ef-ca62acafc1ee.png" alt="Create Docker access token" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<p>Now, you need to copy the credentials. After clicking the generate button, Docker Hub will create an access token. <strong>Immediately copy this token along with your username</strong> and save it somewhere safe, like in a file (don’t worry, we’ll add it to our GitHub secrets). You won’t be able to see this token again, so make sure you save it!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733133363382/33dbf334-a7ec-4151-8639-5368c3ccaedb.png" alt="Copy Docker username + access token" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<h3 id="heading-step-4-add-the-token-to-github-as-a-secret">Step 4: Add the Token to GitHub as a Secret</h3>
<p>To do this, open your GitHub repository where the codebase is hosted. In the GitHub repo, click on the <strong>Settings</strong> tab (located near the top of your repo page).</p>
<p>Then on the left sidebar, scroll down and click on <strong>“Secrets and Variables”</strong>, then choose <strong>“Actions”</strong>.</p>
<ol>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733133003023/75c3bd35-1a5b-46fa-845a-0f4fd8305d53.png" alt="Open GitHub Actions Secrets" class="image--center mx-auto" width="1381" height="957" loading="lazy"></li>
</ol>
<p>Here are the steps to create and manage your new secret:</p>
<ol>
<li><p><strong>Add a new secret</strong>: Click on the <strong>“New repository secret”</strong> button.</p>
</li>
<li><p><strong>Set up the secret</strong>:</p>
<ul>
<li><p>In the <strong>Name</strong> field, type <code>DOCKER_PASSWORD</code>.</p>
</li>
<li><p>In the <strong>Value</strong> field, paste the access token you copied earlier.</p>
</li>
</ul>
</li>
<li><p><strong>Save the secret</strong>: Finally, click <strong>Add secret</strong> to save your Docker access token securely in GitHub.</p>
</li>
</ol>
<p>Then you’ll repeat the process for your Docker username. Create a new secret called <code>DOCKER_USER</code> and add your Docker username that you copied earlier.</p>
<p>And that’s it! Now your CI/CD pipeline can use this token to securely log in to Docker Hub and upload images automatically when triggered. 🎉</p>
<h3 id="heading-step-5-creating-the-dockerfile-for-the-project"><strong>Step 5: Creating the Dockerfile for the Project</strong></h3>
<p>Before you can build and publish the Docker image to Docker Hub, you need to create a <code>Dockerfile</code> that contains the necessary instructions to build your application.</p>
<p>Follow the steps below to create the <code>Dockerfile</code> in the root folder of your project:</p>
<ol>
<li><p>Navigate to your project’s root folder.</p>
</li>
<li><p>Create a new file named <code>Dockerfile</code>.</p>
</li>
<li><p>Open the <strong>Dockerfile</strong> in a text editor and paste the following content into it:</p>
</li>
</ol>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:<span class="hljs-number">18</span>-slim

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-keyword">COPY</span><span class="bash"> package.json .</span>

<span class="hljs-keyword">RUN</span><span class="bash"> npm install -f</span>

<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

<span class="hljs-comment"># EXPOSE 5001</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">5001</span>

<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"npm"</span>, <span class="hljs-string">"start"</span>]</span>
</code></pre>
<h4 id="heading-explanation-of-the-dockerfile">Explanation of the Dockerfile:</h4>
<ul>
<li><p><code>FROM node:18-slim</code>: This sets the base image for the Docker container, which is a slim version of the official Node.js image based on version 18.</p>
</li>
<li><p><code>WORKDIR /app</code>: Sets the working directory for the application inside the container to <code>/app</code>.</p>
</li>
<li><p><code>COPY package.json .</code>: Copies the <code>package.json</code> file into the working directory.</p>
</li>
<li><p><code>RUN npm install -f</code>: Installs the project dependencies using <code>npm</code>.</p>
</li>
<li><p><code>COPY . .</code>: Copies the rest of the project files into the container.</p>
</li>
<li><p><code>EXPOSE 5001</code>: This tells Docker to expose port <code>5001</code>, which is the port our app will run on inside the container.</p>
</li>
<li><p><code>CMD ["npm", "start"]</code>: This sets the default command to start the application when the container is run, using <code>npm start</code>.</p>
</li>
</ul>
<h2 id="heading-create-a-google-cloud-account-project-and-billing-account"><strong>Create a Google Cloud Account, Project, and Billing Account</strong> ☁️</h2>
<p>In this section, we’re laying the foundation for deploying our application to Google Cloud. First, we’ll set up a Google Cloud account (don’t worry, it’s free to get started!). Then, we’ll create a new project where all the resources for your app will live.</p>
<p>Finally, we’ll enable billing so you can unlock the cloud services needed for deployment. Think of this as setting up your workspace in the cloud—organized, ready, and secure! Let’s dive in! ☁️</p>
<h3 id="heading-step-1-create-or-sign-in-to-a-google-cloud-account">Step 1: Create or Sign in to a Google Cloud Account 🌐</h3>
<p>First, go to <a target="_blank" href="https://console.cloud.google.com">Google Cloud Console</a>. If you don’t have a Google Cloud account, you’ll need to create one.</p>
<p>To do this, click on <strong>Get Started for Free</strong> and follow the steps to set up your account (you’ll need to provide payment information, but Google offers $300 in free credits to get started). If you already have a Google account, simply sign in using your credentials.</p>
<p>Once you’ve signed in, you’ll be taken to your Google Cloud dashboard. This is where you can manage all your cloud projects and resources.</p>
<h3 id="heading-step-2-create-a-new-google-cloud-project">Step 2: Create a New Google Cloud Project 🏗️</h3>
<p>At the top left of the Google Cloud Console, you’ll see a drop-down menu beside the Google Cloud logo. Click on this drop-down to display your current projects.</p>
<p>Now it’s time to create a new project. In the top-left corner of the pop-up modal, click on the <strong>New Project</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733134260252/6769909a-cf9c-4c91-9d79-7676500f3981.webp" alt="Create Google Cloud Project" class="image--center mx-auto" width="720" height="359" loading="lazy"></p>
<p>You’ll be redirected to a page where you’ll need to provide some basic details for your new project. So now enter the following information:</p>
<ul>
<li><p><strong>Project Name:</strong> Enter a name of your choice for the project (for example, <code>gcr-ci-cd-project</code>).</p>
</li>
<li><p><strong>Location:</strong> Select a location for your project. You can leave it as the default "No organization" if you're just getting started.</p>
</li>
</ul>
<p>Once you've entered the project name, click the <strong>Create</strong> button. Google Cloud will now start creating your new project. It may take a few seconds.</p>
<h3 id="heading-step-3-access-your-new-project">Step 3: Access Your New Project 🛠️</h3>
<p>After a few seconds, you’ll be redirected to your <strong>Google Cloud dashboard</strong>.</p>
<p>Click on the drop-down menu beside the Google Cloud logo again, and you should now see your newly created project listed in the modal where you can select it.</p>
<p>Then click on the project name (for example, <code>gcr-ci-cd-project</code>) to enter your project’s dashboard.</p>
<h3 id="heading-step-4-link-a-billing-account-to-your-project">Step 4: Link A Billing Account To Your Project 💳</h3>
<p>To access the billing page, in the Google Cloud Console, find the <strong>Navigation Menu</strong> (the three horizontal lines) at the top left of the screen. Click on it to open a list of options. Scroll down and click on <strong>Billing</strong>. This will take you to the billing section of your Google Cloud account.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733134747962/745c8a0e-13c5-4dde-849b-303c1200f495.png" alt="Navigate to Google Cloud Billing dashboard/section " class="image--center mx-auto" width="312" height="864" loading="lazy"></p>
<p>If you haven't set up a billing account yet, you'll be prompted to do so. Click on the <strong>"Link a billing account"</strong> button to start the process.</p>
<p>Now you can create a new billing account (if you don’t have one). You’ll be redirected to a page where you can either select an existing billing account or create a new one. If you don't already have a billing account, click on <strong>"Create a billing account"</strong>.</p>
<p>Provide the necessary details, including:</p>
<ul>
<li><p><strong>Account name</strong> (for example, "Personal Billing Account" or your business name).</p>
</li>
<li><p><strong>Country</strong>: Choose the country where your business or account is based.</p>
</li>
<li><p><strong>Currency</strong>: Choose the currency in which you want to be billed.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733135153425/1287ab53-e9c5-45b5-a09d-3d3a13840ca4.png" alt="Create Google Cloud billing account" class="image--center mx-auto" width="590" height="435" loading="lazy"></p>
</li>
</ul>
<p>Next, enter your payment information (credit card or bank account details). Google Cloud will verify your payment method, so make sure the information is correct.</p>
<p>Read and agree to the Google Cloud Terms of Service and Billing Account Terms. Once you’ve done this, click <strong>"Start billing"</strong> to finish setting up your billing account</p>
<p>After setting up your billing account, you’ll be taken to a page that asks you to <strong>link</strong> it to your project. Select the billing account you just created or an existing billing account you want to use. Click Set Account to link the billing account to your project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733337276189/b80702dd-2ff6-42db-a325-c2082e8059e5.png" alt="Link Google Cloud billing account to project" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<p>After you’ve linked your billing account to your project, you should see a confirmation message indicating that billing has been successfully enabled for your project.</p>
<p>You can always verify this by returning to the Billing section in the Google Cloud Console, where you’ll see your billing account listed.</p>
<h2 id="heading-create-a-google-cloud-service-account-to-enable-deployment-of-the-nodejs-application-to-google-cloud-run-via-the-cd-pipeline"><strong>Create a Google Cloud Service Account to Enable Deployment of the Node.js Application to Google Cloud Run via the CD Pipeline</strong> 🚀</h2>
<h3 id="heading-why-do-we-need-a-service-account-and-key">Why Do We Need a Service Account and Key? 🤔</h3>
<p>A <strong>service account</strong> allows our CI/CD pipeline to authenticate and interact with Google Cloud services programmatically. By assigning specific roles (permissions), we ensure the service account can only perform tasks related to deployment, such as managing Google Cloud Run.</p>
<p>The <strong>service account key</strong> is a JSON file containing the credentials used for authentication. We securely store this key as a GitHub secret to protect sensitive information.</p>
<h3 id="heading-step-1-open-the-service-accounts-page">Step 1: Open the Service Accounts Page</h3>
<p>Here are the steps you can follow to set up your service account and get your key:</p>
<p>First, visit the Google Cloud Console at <a target="_blank" href="https://console.cloud.google.com/">https://console.cloud.google.com/</a>. Ensure you’ve selected the correct project (e.g. <code>gcr-ci-cd-project</code>). To change projects, click the drop-down menu next to the Google Cloud logo at the top-left corner and select your project.</p>
<p>Then navigate to the Navigation Menu (three horizontal lines in the top-left corner) and click on <strong>IAM &amp; Admin &gt; Service Accounts</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733147553088/e3647442-ca8e-4197-ab5f-91cee5a6d6b0.png" alt="Navigate to Google Cloud IAM - Service Account" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<h3 id="heading-step-2-create-a-new-service-account">Step 2: Create a New Service Account</h3>
<p>Click on the "Create Service Account" button. This will open a form where you’ll define your service account details.</p>
<p>Next, enter the Service Account details:</p>
<ul>
<li><p><strong>Name</strong>: Enter a descriptive name (for example, <code>ci-cd-sa</code>).</p>
</li>
<li><p><strong>ID</strong>: This will auto-fill based on the name.</p>
</li>
<li><p><strong>Description</strong>: Add a description to help identify its purpose, such as “Used for deploying Node.js app to Cloud Run.”</p>
</li>
<li><p>Click <strong>Create and Continue</strong> to proceed.</p>
</li>
</ul>
<h3 id="heading-step-3-assign-necessary-roles-permissions">Step 3: Assign Necessary Roles (Permissions)</h3>
<p>On the next screen, you’ll assign roles to the service account. Add the following roles one by one:</p>
<ul>
<li><p><strong>Cloud Run Admin</strong>: Allows management of Cloud Run services.</p>
</li>
<li><p><strong>Service Account User</strong>: Grants the ability to use service accounts.</p>
</li>
<li><p><strong>Service Usage Admin</strong>: Enables control over enabling APIs.</p>
</li>
<li><p><strong>Viewer</strong>: Provides read-only access to view resources.</p>
</li>
</ul>
<p>To add a role:</p>
<ul>
<li><p>Click on <strong>"Select a Role"</strong>.</p>
</li>
<li><p>Use the search bar to type the role name (for example, "Cloud Run Admin") and select it.</p>
</li>
<li><p>Repeat for all four roles.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733147870701/393833c9-c320-49e3-8743-dbc0d739b99b.png" alt="Create Google Cloud Service Account - Add role to a service account during creation" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<p>Your screen should look similar to this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733147949148/c509c810-767d-4900-aa44-a737cc1c8dc1.png" alt="Create a Google Cloud service account (SA) - Done assigning all roles to SA" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<p>After assigning the roles, click <strong>Continue</strong>.</p>
<h3 id="heading-step-4-skip-granting-users-access-to-the-service-account">Step 4: Skip Granting Users Access to the Service Account</h3>
<p>On the next screen, you’ll see an option to grant additional users access to this service account. Click <strong>Done</strong> to complete the creation process.</p>
<h3 id="heading-step-5-generate-a-service-account-key">Step 5: Generate a Service Account Key 🔑</h3>
<p>You should now see your newly created service account in the list. Find the row for your service account (for example, <code>ci-cd-sa</code>) and click the three vertical dots under the “Actions” column. Select <strong>"Manage Keys"</strong> from the drop-down menu.</p>
<p>To add a new key:</p>
<ul>
<li><p>Click on <strong>"Add Key" &gt; "Create New Key"</strong>.</p>
</li>
<li><p>In the pop-up dialog, select <strong>JSON</strong> as the key type.</p>
</li>
<li><p>Click <strong>Create</strong>.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733148120618/c7014982-ae7d-40ed-bbfb-0c8f5c4b8090.png" alt="Create Google Cloud service account key" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
</li>
</ul>
<p>Now, download the key file. A JSON file will automatically be downloaded to your computer. This file contains the credentials needed to authenticate with Google Cloud.</p>
<p>Make sure you keep the key secure and store it in a safe location. Don’t share it – treat it as sensitive information.</p>
<h3 id="heading-step-6-add-the-service-account-key-to-github-secrets">Step 6: Add the Service Account Key to GitHub Secrets 🔒</h3>
<p>Start by opening the downloaded JSON file using a text editor (like Notepad or VS Code). Then select and copy the entire contents of the file.</p>
<p>Then navigate to the repository you created for this project on GitHub. Click on the <strong>Settings</strong> tab at the top of the repository. Scroll down and find the <strong>Secrets and variables &gt; Actions</strong> section.</p>
<p>Now you need to add a new secret. Click the <strong>"New repository secret"</strong> button. In the <strong>Name</strong> field, enter <code>GCP_SERVICE_ACCOUNT</code>. In the <strong>Value</strong> field, paste the JSON content you copied earlier. Click <strong>Add secret</strong> to save it.</p>
<p>Do the same for the <code>GCP_PROJECT_ID</code> secret, but now add your Google Project ID as the value. To get your project ID, follow these steps:</p>
<ol>
<li><p><strong>Navigate to the Google Cloud Console</strong>: Open Google Cloud Console at <a target="_blank" href="https://console.cloud.google.com/">https://console.cloud.google.com/</a>.</p>
</li>
<li><p><strong>Locate the Project Dropdown</strong>: At the top-left of the screen, next to the <strong>Google Cloud logo</strong>, you will see a drop-down that shows the name of your current project.</p>
</li>
<li><p><strong>View the Project ID</strong>: Click the drop-down, and you'll see a list of all your projects. Your <strong>Project ID</strong> will be displayed next to the project name. It is a unique identifier used by Google Cloud.</p>
</li>
<li><p><strong>Copy the Project ID</strong>: Copy the <strong>Project ID</strong> that is displayed, and add it as the value of the <code>GCP_PROJECT_ID</code> secret.</p>
</li>
</ol>
<h3 id="heading-step-7-adding-external-variables-to-the-github-repository">Step 7: Adding External Variables to the GitHub Repository 🔧</h3>
<p>Before proceeding with deployment, we need to define some external variables that were referenced in the CD workflow. These variables ensure that the pipeline knows critical details about your Google Cloud Run services and Docker container registry.</p>
<p>Here are the steps you’ll need to follow to do this:</p>
<ol>
<li><p>First, go to your repository on GitHub.</p>
</li>
<li><p>Click the <strong>Settings</strong> tab at the top of the repository. Scroll down to <strong>Secrets and variables &gt; Actions</strong>.</p>
</li>
<li><p>Click on the <strong>Variables</strong> tab next to <strong>Secrets</strong>. Click <strong>"New repository variable"</strong> for each variable. Then you’ll need to define these variables:</p>
<ul>
<li><p><code>GCR_PROJECT_NAME</code>: Set this to the name of your Cloud Run service for the production/live environment. For example, <code>gcr-ci-cd-app</code>.</p>
</li>
<li><p><code>GCR_STAGING_PROJECT_NAME</code>: Set this to the name of your Cloud Run service for the staging/test environment. For example, <code>gcr-ci-cd-staging</code>.</p>
</li>
<li><p><code>GCR_REGION</code>: Enter the region where you’d like to deploy the services. For this tutorial, set it to <code>us-central1</code>.</p>
</li>
<li><p><code>IMAGE</code>: Specify the name of the Docker image/container registry where the published image will be uploaded. For example, <code>&lt;dockerhub-username&gt;/ci-cd-tutorial-app</code>.</p>
</li>
</ul>
</li>
<li><p>After entering each variable name and value, click <strong>Add variable</strong>.</p>
</li>
</ol>
<h3 id="heading-enabling-the-service-usage-api-on-the-google-cloud-project">Enabling the Service Usage API on the Google Cloud Project 🌐</h3>
<p>To deploy your application, the <strong>Service Usage API</strong> must be enabled in your Google Cloud project. This API allows you to manage Google Cloud services programmatically, including enabling/disabling APIs and monitoring their usage.</p>
<p>Follow these steps to enable it:</p>
<ol>
<li><p>First, visit the Google Cloud Console at <a target="_blank" href="https://console.cloud.google.com/">https://console.cloud.google.com/</a>.</p>
</li>
<li><p>Then make sure you’re in the correct project. Click the project drop-down menu near the <strong>Google Cloud logo</strong> at the top-left corner. Select <code>gcr-ci-cd-project</code> , or the name you gave your project from the list of projects.</p>
</li>
<li><p>Next you’ll need to access the API library. Open the <strong>Navigation Menu</strong> (three horizontal lines in the top-left corner). Select <strong>APIs &amp; Services &gt; Library</strong> from the menu.</p>
</li>
<li><p>In the API Library, use the search bar to search for <strong>"Service Usage API"</strong>.</p>
</li>
<li><p>Click on the <strong>Service Usage API</strong> from the search results. On the API’s details page, click <strong>Enable</strong>.</p>
</li>
<li><p>To verify, go to <strong>APIs &amp; Services &gt; Enabled APIs &amp; Services</strong> in the Google Cloud Console. Confirm that the <strong>Service Usage API</strong> appears in the list of enabled APIs.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733150269757/00a4e20b-72ac-4bd4-b05f-af6e61600e09.png" alt="Enable the Google Cloud &quot;Service Usage API&quot; in the project" class="image--center mx-auto" width="761" height="253" loading="lazy"></p>
</li>
</ol>
<h2 id="heading-create-the-staging-branch-and-merge-the-feature-branch-into-it-continuous-integration-and-continuous-delivery"><strong>Create the Staging Branch and Merge the Feature Branch into It (Continuous Integration and Continuous Delivery) 🌟</strong></h2>
<p>When changes from the <code>feature/ci-cd-pipeline</code> branch are merged into the <code>staging</code> branch, we complete the <strong>Continuous Integration (CI)</strong> process, and the workflow <code>ci-pipeline.yml</code> will run. This ensures that the changes made in the feature branch are tested and integrated into a shared branch.</p>
<p>Once the pull request (PR) is merged into <code>staging</code>, the <strong>Continuous Delivery (CD)</strong> pipeline automatically triggers, deploying the application to the staging environment. This simulates how updates are tested in a safe environment before being pushed to production.</p>
<h3 id="heading-create-the-staging-branch-on-the-remote-repository">Create the <code>staging</code> Branch on the Remote Repository</h3>
<p>To enable the CI/CD pipeline, we’ll first create a <code>staging</code> branch on the remote GitHub repository. This branch will serve as the test environment where changes are deployed before they reach the production environment.</p>
<p>To create the <code>staging</code> branch directly on GitHub, follow these steps:</p>
<ol>
<li><p>First, navigate to your repository on GitHub. Open your web browser and go to the GitHub repository where you want to create the new <code>staging</code> branch.</p>
</li>
<li><p>Then, switch to the <code>main</code> branch. On the top of the repository page, locate the <strong>Branch</strong> dropdown (usually labelled as <code>main</code> or the current branch name). Click on the dropdown and make sure you are on the <code>main</code> branch.</p>
</li>
<li><p>Next, create the <code>staging</code> branch. In the same dropdown where you see the <code>main</code> branch, type <code>staging</code> into the text box. Once you start typing, GitHub will offer you the option to create a new branch called <code>staging</code>. Select the <strong>Create branch: staging</strong> option from the dropdown.</p>
</li>
<li><p>Finally, verify the branch**.** After creating the <code>staging</code> branch, GitHub will automatically switch to it. You should now see <code>staging</code> in the branch dropdown, confirming the new branch was created.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733152232155/e6215137-5e3b-474b-88f8-af03269eccc2.png" alt="Create a new Staging branch in the GitHub repository" class="image--center mx-auto" width="933" height="339" loading="lazy"></p>
</li>
</ol>
<h3 id="heading-merge-your-feature-branch-into-the-staging-branch-via-a-pull-request-pr"><strong>Merge Your Feature Branch into the Staging Branch via a Pull Request (PR)</strong></h3>
<p>This process combines both Continuous Integration (CI) and Continuous Delivery (CD). You will commit changes from your feature branch, push them to the remote feature branch, and then open a PR to merge those changes into the <code>staging</code> branch. Here's how to do it:</p>
<h4 id="heading-step-1-commit-local-changes-on-your-feature-branch"><strong>Step 1: Commit Local Changes on Your Feature Branch</strong></h4>
<p>First, you’ll want to make sure that you are on the correct branch (the feature branch) by running:</p>
<pre><code class="lang-bash">git status
</code></pre>
<p>If you are not on the <code>feature/ci-cd-pipeline</code> branch, switch to it by running:</p>
<pre><code class="lang-bash">git checkout feature/ci-cd-pipeline
</code></pre>
<p>Now, it’s time to add your changes you made for the commit:</p>
<pre><code class="lang-bash">git add .
</code></pre>
<p>This stages all changes, including new files, modified files, and deleted files.</p>
<p>Next, commit your changes with a clear and descriptive message:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Set up CI/CD pipelines for the project"</span>
</code></pre>
<p>Then you can verify your commit by running:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span>
</code></pre>
<p>This will display your most recent commits, and you should see the commit message you just added.</p>
<h4 id="heading-step-2-push-your-feature-branch-changes-to-the-remote-repository"><strong>Step 2: Push Your Feature Branch Changes to the Remote Repository</strong></h4>
<p>After committing your changes, push them to the remote repository:</p>
<pre><code class="lang-bash">git push origin feature/ci-cd-pipeline
</code></pre>
<p>This pushes your local changes on the <code>feature/ci-cd-pipeline</code> branch to the remote GitHub repository.</p>
<p>Once the push is successful, visit your GitHub repository in a web browser, and confirm that the <code>feature/ci-cd-pipeline</code> branch is updated with your new commit.</p>
<h4 id="heading-step-3-create-a-pull-request-to-merge-the-feature-branch-into-staging"><strong>Step 3: Create a Pull Request to Merge the Feature Branch into Staging</strong></h4>
<p>Go to your repository on GitHub and ensure that you are on the main page of the repository.</p>
<p>You should see an alert at the top of the page suggesting you create a pull request for the recently pushed branch (<code>feature/ci-cd-pipeline</code>). Click the <strong>Compare &amp; Pull Request</strong> button next to the alert.</p>
<p>Now, it’s time to choose the base and compare branches. On the PR creation page, make sure the <strong>base</strong> branch is set to <code>staging</code> (this is the branch you want to merge your changes into). The <strong>compare</strong> branch should already be set to <code>feature/ci-cd-pipeline</code> (the branch you just pushed). If they’re not selected correctly, use the dropdowns to change them.</p>
<p>You’ll want to come up with a good PR description for this. Write a clear title and description for the pull request, explaining what changes you're merging and why. For example:</p>
<ul>
<li><p><strong>Title</strong>: "Merge CI/CD setup changes from feature branch"</p>
</li>
<li><p><strong>Description</strong>: "This pull request adds the CI/CD pipelines for GitHub Actions and Docker Hub integration to the project. It includes the configurations for both CI and CD workflows."</p>
</li>
</ul>
<p>Now GitHub will show a list of all the changes that will be merged. Take a moment to review them and ensure everything looks correct.</p>
<p>If all looks good after reviewing, click on the <strong>Create pull request</strong> button. This will create the PR and notify team members (if any) that changes are ready to be reviewed and merged.</p>
<p>Wait a few seconds, and you should see a message indicating that all the checks have passed. Click on the link with the description "<strong>CI Pipeline to staging/production environment...</strong>". This should direct you to the Continuous Integration workflow, where you can view the steps that ran</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733153444873/6ecdb277-0a45-44ec-981c-c7ee671cd2f0.png" alt="Create a new pull request (PR) from the feature to the staging branch" class="image--center mx-auto" width="931" height="713" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733153637817/e12fefde-9259-41a3-9bd1-63b5da1d88ea.png" alt="CI workflow run from PR (feature to staging branch)" class="image--center mx-auto" width="1381" height="957" loading="lazy"></p>
<h4 id="heading-the-continuous-integration-ci-process">The Continuous Integration (CI) Process</h4>
<p>The CI process begins when a Pull Request is made to the <code>staging</code> branch. It triggers the GitHub Actions workflow defined in the <code>.github/workflows/ci-pipeline.yml</code> file. The workflow runs the necessary steps to set up the environment, install dependencies, and build the Node.js application.</p>
<p>It then runs automated tests (using <code>npm test</code>) to ensure that the changes do not break any functionality in the codebase. If all these steps are completed successfully, the CI pipeline confirms that the feature branch is stable and ready to be merged into the <code>staging</code> branch for further testing and deployment.</p>
<h4 id="heading-step-4-merge-the-pull-request"><strong>Step 4: Merge the Pull Request</strong></h4>
<p>If your team or collaborators are part of the project, they may review your PR. This step may involve discussing any changes or improvements. If everything looks good, a reviewer will merge the PR.</p>
<p>Once the PR has been reviewed and approved, you can merge the PR. To do this, just click on the <strong>Merge pull request</strong> button. Choose <strong>Confirm merge</strong> when prompted.</p>
<p>After merging, you can go to the <code>staging</code> branch to verify that the changes were successfully merged.</p>
<h3 id="heading-navigating-to-the-actions-page-after-merging-the-pr"><strong>Navigating to the Actions Page After Merging the PR</strong></h3>
<p>Once you have successfully merged your pull request from the <code>feature/ci-cd-pipeline</code> branch into the <code>staging</code> branch, the Continuous Delivery (CD) pipeline will be triggered. To view the progress of the CD pipeline, navigate to the <strong>Actions</strong> tab in your GitHub repository. Here's how to do it:</p>
<ol>
<li><p>Go to your GitHub repository.</p>
</li>
<li><p>At the top of the page, you will see the <strong>Actions</strong> tab next to the <strong>Code</strong> tab. Click on it.</p>
</li>
<li><p>On the Actions page, you will see a list of workflows that have been triggered. Look for the one labelled <strong>CD Pipeline to Google Cloud Run (staging and production)</strong>. It should appear as a new run after the PR merge.</p>
</li>
<li><p>Click on the workflow run to view its progress and see the detailed logs for each step.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733154575368/96e236a2-ae66-494b-b544-f96955a18ac9.png" alt="Continuous Delivery workflow from merge to staging (feature to staging)" class="image--center mx-auto" width="1368" height="462" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733159329441/cb7e26a9-7a20-4b1b-9869-e00facc695c1.png" alt="Continuous Delivery workflow Jobs from merge to staging (feature to staging)" class="image--center mx-auto" width="1364" height="545" loading="lazy"></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733160506355/4682afe3-bb04-405d-af4e-fd9bd3494659.png" alt="Continuous Delivery workflow steps from merge to staging (feature to staging)" class="image--center mx-auto" width="1340" height="831" loading="lazy"></p>
<p>This will allow you to monitor the status of the CD pipeline and check if there are any issues during deployment.</p>
<p>If you look at the CD steps and workflow, you'll see that the step to deploy the application to the <strong>production</strong> environment was skipped, while the step to deploy to the <strong>staging</strong> environment was executed.</p>
<h4 id="heading-continuous-delivery-cd-pipeline-whats-going-on"><strong>Continuous Delivery (CD) pipeline – what’s going on:</strong></h4>
<p>The <strong>Continuous Delivery (CD) Pipeline</strong> automates the process of deploying the application to Google Cloud Run (testing environment). This workflow is triggered by a push to the <code>staging</code> branch, which happens after the changes from the feature branch are merged into <code>staging</code>. It can also be manually triggered via <code>workflow_dispatch</code> or upon a new release being published.</p>
<p>The pipeline consists of multiple stages:</p>
<ol>
<li><p><strong>Test Job:</strong> The pipeline begins by setting up the environment and running tests using the <code>npm test</code> command. If the tests pass, the process moves forward.</p>
</li>
<li><p><strong>Build Job:</strong> The next step builds the Docker image of the Node.js application, tags it, and then pushes it to Docker Hub.</p>
</li>
<li><p><strong>Deployment to GCP:</strong> After the image is pushed, the workflow authenticates to Google Cloud and deploys the application. If the event is a release (that is, a push to the <code>main</code> branch), the application is deployed to the production environment. If the event is a push to <code>staging</code>, the app is deployed to the staging environment.</p>
</li>
</ol>
<p>The CD process ensures that any changes made to the <code>staging</code> branch are automatically tested, built, and deployed to the staging environment, ready for further validation. When a release is published, it will trigger deployment to production, ensuring your app is always up to date.</p>
<h3 id="heading-accessing-the-deployed-application-in-the-staging-environment-on-google-cloud-run">Accessing the Deployed Application in the Staging Environment on Google Cloud Run 🌐</h3>
<p>Once the deployment to Google Cloud Run is successfully completed, you'll want to access your application running in the <strong>staging</strong> environment. Follow these steps to find and visit your deployed application:</p>
<h4 id="heading-1-navigate-to-the-google-cloud-console">1. <strong>Navigate to the Google Cloud Console</strong></h4>
<p>Open the Google Cloud Console in your browser by visiting <a target="_blank" href="https://console.cloud.google.com">https://console.cloud.google.com</a>. If you're not already signed in, make sure you log in with your Google account.</p>
<h4 id="heading-2-go-to-the-cloud-run-dashboard">2. <strong>Go to the Cloud Run Dashboard</strong></h4>
<p>In the Google Cloud Console, use the Search bar at the top or navigate through the left-hand menu: Go to <strong>Cloud Run</strong> (you can type this into the search bar, or find it under <strong>Products &amp; services</strong> &gt; <strong>Compute</strong> &gt; <strong>Cloud Run</strong>). Click on <strong>Cloud Run</strong> to open the Cloud Run dashboard.</p>
<h4 id="heading-3-select-your-staging-service">3. <strong>Select Your Staging Service</strong></h4>
<p>In the <strong>Cloud Run dashboard</strong>, you should see a list of all your services deployed across various environments. Find the service associated with the staging environment. The name should be similar to what you defined in your workflow (for example, <code>gcr-ci-cd-staging</code>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733159635861/4ac895d2-5071-4d3f-9ed1-5af2bcca8835.png" alt="Google Cloud Run service for the staging environment" class="image--center mx-auto" width="1376" height="232" loading="lazy"></p>
<h4 id="heading-4-access-the-service-url">4. <strong>Access the Service URL</strong></h4>
<p>Once you've selected your staging service, you’ll be taken to the <strong>Service details page</strong>. This page provides all the important information about your deployed service.<br>On this page, look for the <strong>URL</strong> section under the <strong>Service URL</strong> heading. The URL will look something like: <code>https://gcr-ci-cd-staging-&lt;unique-id&gt;.run.app</code>.</p>
<h4 id="heading-5-visit-the-application">5. <strong>Visit the Application</strong></h4>
<p>Click on the <strong>Service URL</strong>, and it will open your staging environment in a new tab in your browser. You can now interact with your application as if it were live, but in the <strong>staging environment</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733160050763/b097e647-bf6d-442e-87df-fc7d82d3585c.png" alt="Google Cloud Run service URL for the staging environment" class="image--center mx-auto" width="1013" height="247" loading="lazy"></p>
<h2 id="heading-merge-the-staging-branch-into-the-main-branch-continuous-integration-and-continuous-deployment"><strong>Merge the Staging Branch into the Main Branch (Continuous Integration and Continuous Deployment) 🌐</strong></h2>
<p>In this section, we'll take the updates in the staging branch, merge them into the main branch, and trigger the CI/CD pipeline. This process not only ensures your changes are production-ready but also deploys them to the production/live environment. 🚀</p>
<h3 id="heading-step-1-push-local-changes-and-open-a-pull-request">Step 1: Push Local Changes and Open a Pull Request</h3>
<p><strong>Why?</strong> The first step involves merging the staging branch into the main branch. Just like in the previous Continuous Delivery process, this ensures the integration of thoroughly tested updates.</p>
<p>Here’s how to do it:</p>
<p>First, visit the GitHub repository where your project is hosted.</p>
<p>Then go to the <strong>Pull Requests</strong> tab. Click <strong>New Pull Request</strong>. Choose <strong>staging</strong> as the source branch (base branch) and <strong>main</strong> as the target branch. Add a clear title and description for the Pull Request, explaining why these updates are ready for production deployment.</p>
<h3 id="heading-step-2-continuous-integration-ci-pipeline-execution">Step 2: Continuous Integration (CI) Pipeline Execution</h3>
<p>After merging the pull request, the <strong>Continuous Integration (CI)</strong> pipeline will automatically execute to validate that the changes are still stable when integrated into the <strong>main branch</strong>.</p>
<h4 id="heading-pipeline-steps">Pipeline Steps:</h4>
<ul>
<li><p><strong>Code Checkout</strong>: The workflow fetches the latest code from the <strong>main branch</strong>.</p>
</li>
<li><p><strong>Dependency Installation</strong>: The pipeline installs all required dependencies.</p>
</li>
<li><p><strong>Testing</strong>: Automated tests are run to validate the application's stability.</p>
</li>
</ul>
<h3 id="heading-step-3-create-a-new-release">Step 3: Create a New Release</h3>
<p>The Continuous Deployment (CD) workflow to deploy to the production environment is triggered by the creation of a new release from the main branch.</p>
<p>Let’s walk through the steps to create a release.</p>
<p>On your GitHub repository page, click on the <strong>Releases</strong> section (located under the <strong>Code</strong> tab).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733338781623/c21e7f03-5381-47f9-8807-b5a3360245ad.png" alt="Navigate to the Release page in theGitHub repo" class="image--center mx-auto" width="1351" height="550" loading="lazy"></p>
<p>Next, click <strong>Draft a new release</strong>. Set the <strong>Target</strong> branch to <strong>main</strong>. Enter a <strong>Tag version</strong> (for example, <code>v1.0.0</code>) following semantic versioning. Add a <strong>Release title</strong> and an optional description of the changes.</p>
<p>Then, click <strong>Publish Release</strong> to finalize.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733161473858/6e14214c-31fb-49b3-9dff-a719b9ec1d40.png" alt="Create a new release in the GitHub repo" class="image--center mx-auto" width="976" height="815" loading="lazy"></p>
<h4 id="heading-why-run-the-continuous-deployment-pipeline-on-release-instead-of-on-push">Why run the Continuous Deployment pipeline on release instead of on push? 🤔</h4>
<p>In our setup, we decided not to trigger the Continuous Deployment (CD) pipeline every time changes are pushed to the main branch. Instead, we trigger it only when a new release is created. This gives the team more control over when updates are deployed to the production environment.</p>
<p>Imagine a scenario where developers are working on new features—they may push changes to the main branch as part of their regular workflow, but these features might not be complete or ready for users yet. Automatically deploying every push could accidentally expose unfinished features to your users, which can be confusing or disruptive.</p>
<p>By requiring a release to trigger the deployment, the team gets a chance to finalize and polish all changes before they go live.</p>
<p>For example, developers can test new features in the staging environment, fix any issues, and merge those changes into the main branch without worrying about them immediately appearing in production. This workflow ensures that only well-tested and complete features make their way to your end users.</p>
<p>Ultimately, this approach helps maintain a smooth user experience. Instead of seeing half-built features or unexpected changes, users only see updates that are ready and functional. It also gives the team the flexibility to push changes to the main branch frequently—preventing merge conflicts and making collaboration easier—while keeping control over what gets deployed live. 🚀</p>
<h3 id="heading-step-4-navigate-to-the-actions-page">Step 4: Navigate to the Actions Page</h3>
<p>After the release is published, the CD pipeline for the production environment is triggered. To monitor this repeat the process taken for the Continuous Delivery workflow, follow these steps:</p>
<ol>
<li><p><strong>Go to the GitHub Actions tab</strong>: In your GitHub repository, click on the <strong>Actions</strong> tab.</p>
</li>
<li><p><strong>Locate the deployment workflow</strong>: Look for the <strong>CD Pipeline to Google Cloud Run (staging and production)</strong> workflow. You’ll notice that the workflow has been triggered on the <strong>main branch</strong> due to the push event.</p>
</li>
<li><p><strong>Open the workflow details</strong>: Click on the workflow to view detailed steps, logs, and statuses for each part of the deployment process.</p>
</li>
</ol>
<p>This time, the Continuous delivery workflow deploys the application to the <strong>production</strong>/<strong>live</strong> environment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733164741827/303cd415-5bb9-4149-aa5d-7088d0eab582.png" alt="Continuous Deployment workflow from merge to main (staging to main)" class="image--center mx-auto" width="1345" height="860" loading="lazy"></p>
<h3 id="heading-step-5-access-the-live-application">Step 5: Access the Live Application</h3>
<p>Once the deployment is complete, go to Google Cloud Console at <a target="_blank" href="https://console.cloud.google.com">https://console.cloud.google.com</a>.</p>
<p>Navigate to <strong>Cloud Run</strong> from the menu. Select the service corresponding to the <strong>production environment</strong> (for example, <code>gcr-ci-cd-app</code>).</p>
<p>Locate the <strong>Service URL</strong> in the service details page. Open the URL in your browser to access the live application.</p>
<p>And now, congratulations – you’re done!</p>
<h2 id="heading-conclusion">Conclusion 🌟</h2>
<p>In this article, we explored how to build and automate a CI/CD pipeline for a Node.js application, using GitHub Actions, Docker Hub, and Google Cloud Run.</p>
<p>We set up workflows to handle Continuous Integration by testing and integrating code changes and Continuous Delivery to deploy those changes to a staging environment. We also containerized our app using Docker and deployed it seamlessly to Google Cloud Run.</p>
<p>Finally, we implemented Continuous Deployment, ensuring updates to the production environment happen only when a release is created from the main branch.</p>
<p>This approach gives teams the flexibility to push and test incomplete features without impacting end users. By following these steps, you've built a robust pipeline that makes deploying your application smoother, faster, and more reliable.</p>
<h3 id="heading-study-further">Study Further 📚</h3>
<p>If you would like to learn more about Continuous Integration, Delivery, and Deployment you can check out the courses below:</p>
<ul>
<li><p><a target="_blank" href="https://www.coursera.org/learn/continuous-integration-and-continuous-delivery-ci-cd"><strong>Continuous Integration and Continuous Delivery (CI/CD) (from IBM Coursera</strong></a><strong>)</strong></p>
</li>
<li><p><a target="_blank" href="https://www.udemy.com/course/github-actions-the-complete-guide/?couponCode=CMCPSALE24"><strong>GitHub Actions - The Complete Guide (from Udemy</strong></a><strong>)</strong></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/what-is-ci-cd/"><strong>Learn CI/CD by buliding a project (freeCodeCamp tutorial)</strong></a></p>
</li>
</ul>
<h3 id="heading-about-the-author">About the Author 👨‍💻</h3>
<p>Hi, I’m Prince! I’m a software engineer passionate about building scalable applications and sharing knowledge with the tech community.</p>
<p>If you enjoyed this article, you can learn more about me by exploring more of my blogs and projects on my <a target="_blank" href="https://www.linkedin.com/in/prince-onukwili-a82143233/">LinkedIn profile</a>. You can find my <a target="_blank" href="https://www.linkedin.com/in/prince-onukwili-a82143233/details/publications/">LinkedIn articles here</a>. And you can <a target="_blank" href="https://prince-onuk.vercel.app/achievements#articles">visit my website</a> to read more of my articles as well. Let’s connect and grow together! 😊</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is CI/CD? Learn Continuous Integration/Continuous Deployment by Building a Project ]]>
                </title>
                <description>
                    <![CDATA[ Hi everyone! In this article you're going to learn about CI/CD (continuous integration and continuous deployment). We're going to review what this practice is about, how it compares to the previous approach in the software development industry, and f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-ci-cd/</link>
                <guid isPermaLink="false">66d45f2a706b9fb1c166b947</guid>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ German Cocca ]]>
                </dc:creator>
                <pubDate>Fri, 07 Apr 2023 19:31:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/jj-ying-4XvAZN8_WHo-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi everyone! In this article you're going to learn about CI/CD (continuous integration and continuous deployment).</p>
<p>We're going to review what this practice is about, how it compares to the previous approach in the software development industry, and finally see a practical example of how we can implement it in our projects.</p>
<p>Let's go!</p>
<h1 id="heading-table-of-contents">Table of Contents</h1>
<ul>
<li><p><a class="post-section-overview" href="#heading-intro">Intro</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-cicd-works">How CI/CD works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-key-benefits-of-cicd">The key benefits of CI/CD</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tools-for-cicd">Tools for CI/CD</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-a-cicd-pipeline-with-github-actions">How to set up a CI/CD pipeline with GitHub Actions</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-initializing-the-project">Initializing the project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-github-actions-and-how-do-they-work">What are GitHub Actions and how do they work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setting-up-our-workflow">Setting up our workflow</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-magic">The magic</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping up</a></p>
</li>
</ul>
<h1 id="heading-intro">Intro</h1>
<p>Continuous Integration and Continuous Delivery (CI/CD) is a software development approach that aims to improve the speed, efficiency, and reliability of software delivery. This approach involves frequent code integration, automated testing, and continuous deployment of software changes to production.</p>
<p>Before the adoption of CI/CD in the software development industry, the common approach was a traditional, <strong>waterfall model</strong> of software development.</p>
<p>In this approach, developers worked in silos, with each stage of the software development life cycle completed in sequence. The process typically involved gathering requirements, designing the software, coding, testing, and deployment.</p>
<p><strong>The disadvantages of this traditional approach include:</strong></p>
<ol>
<li><p><strong>Slow Release Cycles:</strong> Since each stage of the software development life cycle was completed in sequence, the release cycle was slow, which made it difficult to respond quickly to changing customer needs.</p>
</li>
<li><p><strong>High Failure Rates:</strong> Software projects were prone to failure due to a lack of automated testing, which meant that developers had to rely on manual testing, leading to errors and bugs in the code.</p>
</li>
<li><p><strong>Limited Collaboration:</strong> The traditional approach did not encourage collaboration between developers, testers, and other stakeholders, which made it difficult to identify and fix issues.</p>
</li>
<li><p><strong>High Cost:</strong> The manual nature of software development meant that it was expensive, with high costs associated with testing, debugging, and fixing errors.</p>
</li>
<li><p><strong>Limited Agility:</strong> Since the traditional approach was linear, it was not possible to make changes to the software quickly or respond to customer needs in real-time.</p>
</li>
</ol>
<p>CI/CD emerged as a solution to these disadvantages, by introducing a more agile and collaborative approach to software development. CI/CD enables teams to work together, integrating their code changes frequently, and automating the testing and deployment process.</p>
<h1 id="heading-how-cicd-works">How CI/CD Works</h1>
<p>CI/CD is an automated process that involves frequent code integration, automated testing, and continuous deployment of software changes to production.</p>
<p>Let's explain each step in a little more detail:</p>
<h3 id="heading-code-integration">Code Integration</h3>
<p>The first step in the CI/CD pipeline is code integration. In this step, developers commit their code changes to a remote repository (like <a target="_blank" href="https://github.com/">GitHub</a>, <a target="_blank" href="https://about.gitlab.com/">GitLab</a> or <a target="_blank" href="https://bitbucket.org/product/">BitBucket</a>), where the code is integrated with the main codebase.</p>
<p>This step aims to ensure that the code changes are compatible with the rest of the codebase and do not break the build.</p>
<h3 id="heading-automated-testing">Automated Testing</h3>
<p>Once the code is integrated, the next step is automated testing. Automated testing involves running a suite of tests to ensure that the code changes are functional, meet the expected quality standards, and are free of defects.</p>
<p>This step helps identify issues early in the development process, allowing developers to fix them quickly and efficiently.</p>
<p>If you're not familiar with the topic of testing, you can refer <a target="_blank" href="https://www.freecodecamp.org/news/test-a-react-app-with-jest-testing-library-and-cypress/">to this article I wrote a while ago</a>.</p>
<h3 id="heading-continuous-deployment">Continuous Deployment</h3>
<p>After the code changes pass the automated testing step, the next step is continuous deployment. In this step, the code changes are automatically deployed to a staging environment for further testing.</p>
<p>This step aims to ensure that the software is continuously updated with the latest code changes, delivering new features and functionality to users quickly and efficiently.</p>
<h3 id="heading-production-deployment">Production Deployment</h3>
<p>The final step in the CI/CD pipeline is production deployment. In this step, the software changes are released to end-users. This step involves monitoring the production environment, ensuring that the software is running smoothly, and identifying and fixing any issues that arise.</p>
<p>The four steps of a CI/CD pipeline work together to ensure that software changes are tested, integrated, and deployed to production automatically. This automation helps to reduce errors, increase efficiency, and improve the overall quality of the software.</p>
<p>By adopting a CI/CD pipeline, development teams can achieve faster release cycles, reduce the risk of software defects, and improve the user experience.</p>
<p>Keep in mind that the pipeline stages might look different given the specific project or company we're talking about. Meaning, some teams might or might not use automated testing, some teams might or might not have a "staging" environment, and so on.</p>
<p>The key parts that make up the CI/CD practice are integration and deployment. This means that the code has to be continually integrated in a remote repository, and that this code has to be continually deployed to a given environment after each integration.</p>
<h1 id="heading-the-key-benefits-of-cicd">The Key Benefits of CI/CD</h1>
<p>The key benefits of CI/CD include:</p>
<ol>
<li><p><strong>Faster Release Cycles:</strong> By automating the testing and deployment process, CI/CD enables teams to release software more frequently, responding quickly to customer needs.</p>
</li>
<li><p><strong>Improved Quality:</strong> Automated testing ensures that software changes do not introduce new bugs or issues, improving the overall quality of the software.</p>
</li>
<li><p><strong>Increased Collaboration:</strong> Frequent code integration and testing require developers to work closely together, leading to better collaboration and communication.</p>
</li>
<li><p><strong>Reduced Risk:</strong> Continuous deployment allows developers to identify and fix issues quickly, reducing the risk of major failures and downtime.</p>
</li>
<li><p><strong>Cost-Effective:</strong> CI/CD reduces the amount of manual work required to deploy software changes, saving time and reducing costs.</p>
</li>
</ol>
<p>In summary, CI/CD emerged as a solution to the limitations of the traditional, linear approach to software development. By introducing a more agile and collaborative approach to software development, CI/CD enables teams to work together, release software more frequently, and respond quickly to customer needs.</p>
<h1 id="heading-tools-for-cicd">Tools for CI/CD</h1>
<p>There are several tools available for implementing CI/CD pipelines in software development. Each tool has its unique features, pros, and cons. Here are some of the most commonly used tools in CI/CD pipelines today:</p>
<h3 id="heading-jenkins">Jenkins</h3>
<p><a target="_blank" href="https://www.jenkins.io/">Jenkins</a> is an open-source automation server that is widely used in CI/CD pipelines. It is highly customizable and supports a wide range of plugins, making it suitable for various development environments. Some of its key features include:</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Highly customizable with a wide range of plugins</p>
</li>
<li><p>Supports integration with various tools and technologies</p>
</li>
<li><p>Provides detailed reporting and analytics</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Requires some technical expertise to set up and maintain</p>
</li>
<li><p>Can be resource-intensive, especially for large projects</p>
</li>
<li><p>Lack of a centralized dashboard for managing multiple projects</p>
</li>
</ul>
<p>If you want to learn more about Jenkins, <a target="_blank" href="https://www.freecodecamp.org/news/learn-jenkins-by-building-a-ci-cd-pipeline/">here's a full course for you</a>.</p>
<h3 id="heading-travis-ci">Travis CI</h3>
<p><a target="_blank" href="https://www.travis-ci.com/">Travis CI</a> is a cloud-based CI/CD platform that provides automated testing and deployment for software projects. It supports several programming languages and frameworks, making it suitable for various development environments. Some of its key features include:</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Easy to set up and use</p>
</li>
<li><p>Cloud-based, so there's no need to set up and maintain infrastructure</p>
</li>
<li><p>Supports a wide range of programming languages and frameworks</p>
</li>
<li><p>Provides detailed reporting and analytics</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Limited customization options</p>
</li>
<li><p>Not suitable for large projects with complex requirements</p>
</li>
<li><p>Limited support for on-premise installations</p>
</li>
</ul>
<p>Here's a helpful tutorial about <a target="_blank" href="https://www.freecodecamp.org/news/learn-how-to-automate-deployment-on-github-pages-with-travis-ci/">how to automate deployment on GitHub Pages with Travis CI</a>.</p>
<h3 id="heading-github-actions">GitHub actions</h3>
<p><a target="_blank" href="https://github.com/features/actions">GitHub Actions</a> is a powerful CI/CD tool that allows developers to automate workflows, run tests, and deploy code directly from their GitHub repositories.</p>
<p><strong>Pros:</strong></p>
<ul>
<li><p>Integrated with GitHub</p>
</li>
<li><p>Easy to use</p>
</li>
<li><p>Provides large ecosystem and good documentation</p>
</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li><p>Limited build minutes</p>
</li>
<li><p>Complex YAML syntax</p>
</li>
</ul>
<p>Side comment: I mention GitHub actions here because it's a popular tool – but keep in mind that other online repository providers like GitLab and BitBucket also provide very similar options to GitHub actions.</p>
<h3 id="heading-built-in-cicd-features-by-hosts">Built-in CI/CD features by hosts</h3>
<p>Popular hosts such as <a target="_blank" href="https://vercel.com/">Vercel</a> or <a target="_blank" href="https://www.netlify.com/">Netlify</a> have built-in in CI/CD features that allow you to link an online repository to a given site, and deploy to that site after a given event occurs in that repo.</p>
<p><strong>Pros:</strong></p>
<ul>
<li>Very simple to set up and use</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Limited customization options</li>
</ul>
<p>Each of these tools has its unique features, pros, and cons. The choice of tool will depend on the specific requirements of your project, your team's technical expertise, and your budget.</p>
<p>Here's a tutorial about <a target="_blank" href="https://www.freecodecamp.org/news/how-to-deploy-your-front-end-app/">how to deploy a front-end app with Netlify</a>. And in this tutorial, you'll <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-jamstack-site-with-next-js-and-vercel-jamstack-handbook/">learn how to use Vercel to deploy a Next.js app</a>.</p>
<h1 id="heading-how-to-set-up-a-cicd-pipeline-with-github-actions">How to Set Up a CI/CD Pipeline with GitHub Actions</h1>
<p>Cool, so now that we have a clear idea of what CI/CD is, let's see how we can implement a simple example with an actual project using <a target="_blank" href="https://github.com/features/actions">GitHub actions</a>.</p>
<h2 id="heading-initializing-the-project">Initializing the Project</h2>
<p>We'll start with a very basic React app built with <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-react-app-different-ways/#what-is-vite">Vite</a>. You can do that by running <code>yarn create vite</code> in your console.</p>
<p>We'll focus on the CI/CD pipeline here, so there will be no complexity in the actual app code. But just to have an idea, the <code>app.jsx</code> component will have this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'App'</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Vite + Reactooooo<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>And then we'll have a test file that will check for that text to render:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { describe, expect, it } <span class="hljs-keyword">from</span> <span class="hljs-string">'vitest'</span>;
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'./utils/test-utils/test-utils.jsx'</span>;

<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'src/App.jsx'</span>;

describe(<span class="hljs-string">'App'</span>, <span class="hljs-keyword">async</span> () =&gt; {
    it(<span class="hljs-string">'should render while authenticating'</span>, <span class="hljs-function">() =&gt;</span> {
        render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>);

        expect(screen.getByText(<span class="hljs-string">'Vite + Reactooooo'</span>)).toBeInTheDocument();
    });
});
</code></pre>
<p>This test will run each time we run the <code>yarn test</code> command.</p>
<p>Next step should be to push our code to a GitHub repo. Then, let's talk a bit more about what GitHub actions are and how they work.</p>
<h2 id="heading-what-are-github-actions-and-how-do-they-work">What are GitHub Actions and How Do They Work?</h2>
<p>GitHub Actions is a CI/CD (Continuous Integration/Continuous Deployment) service provided by GitHub. It allows developers to automate workflows by defining custom scripts, known as "actions", that can be triggered by events such as pushes to a repository, pull requests, or issues.</p>
<p>Actions are defined in a YAML file, also known as a "workflow", which specifies the steps required to complete a task. GitHub Actions workflows can run on Linux, Windows, and macOS environments and support a wide range of programming languages and frameworks.</p>
<p>When an event triggers a GitHub Actions workflow, the service creates a fresh environment, installs dependencies, and runs the defined steps in the order specified. This can include tasks such as building, testing, packaging, and deploying code.</p>
<p>GitHub Actions also provides several built-in actions that can be used to simplify common tasks, such as checking out code, building and testing applications, publishing releases, and deploying to popular cloud providers like AWS, Azure, and Google Cloud.</p>
<p>GitHub Actions workflows can be run on a schedule, manually, or automatically when a specific event occurs, such as a pull request being opened or a new commit being pushed to a branch.</p>
<h2 id="heading-setting-up-our-workflow">Setting Up Our Workflow</h2>
<p>Great, so as we've seen, basically GitHub actions are a feature that allows us to define workflows four our projects. These workflows are nothing but a series of tasks or steps that will execute on GitHub's cloud after a given event we declare.</p>
<p>The way GitHub reads and executes these workflows is by automatically reading files within the <code>.github/workflows</code> directory in the root of our project. These workflow files should have the <code>.yaml</code> extension and use the <a target="_blank" href="https://www.redhat.com/en/topics/automation/what-is-yaml">YAML</a> syntax.</p>
<p>To create a new workflow we just have to create a new YAML file within that directory. We'll call ours <code>prod.yaml</code> since we'll use it to deploy the production branch of our project.</p>
<p>Keep in mind a single project can have many different workflows that run different tasks on different occasions. For example, we could have a workflow for dev and staging branches as well, as those environments could require different tasks to execute and will probably deploy on different sites.</p>
<p>After creating this file, let's drop the following code in it:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Name of our workflow</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Production</span> <span class="hljs-string">deploy</span>

<span class="hljs-comment"># Trigger the workflow on push to the main branch</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>

<span class="hljs-comment"># List of jobs</span>
<span class="hljs-comment"># A "job" is a set of steps that are executed on the same runner</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-comment"># Name of the job</span>
  <span class="hljs-attr">test-and-deploy-to-netlify:</span>
    <span class="hljs-comment"># Operating system to run on</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-comment"># List of steps that make up the job</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-comment"># Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>

    <span class="hljs-comment"># Setup Node.js environment</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-number">16.</span><span class="hljs-string">x</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v2</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-string">'16.x'</span>

    <span class="hljs-comment"># Install dependencies</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span>

    <span class="hljs-comment"># Run tests</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">test</span>

    <span class="hljs-comment"># Deploy to Netlify</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Netlify</span> <span class="hljs-string">Deploy</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">jsmrcaga/action-netlify-deploy@v2.0.0</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-comment"># Auth token to use with netlify</span>
        <span class="hljs-attr">NETLIFY_AUTH_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.NETLIFY_AUTH_TOKEN</span> <span class="hljs-string">}}</span>
        <span class="hljs-comment"># Your Netlify site id</span>
        <span class="hljs-attr">NETLIFY_SITE_ID:</span>  <span class="hljs-string">${{</span> <span class="hljs-string">secrets.NETLIFY_SITE_ID</span> <span class="hljs-string">}}</span>
        <span class="hljs-comment"># Directory where built files are stored</span>
        <span class="hljs-attr">build_directory:</span> <span class="hljs-string">'./dist'</span>
        <span class="hljs-comment"># Command to install dependencies</span>
        <span class="hljs-attr">install_command:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span>
        <span class="hljs-comment"># Command to build static website</span>
        <span class="hljs-attr">build_command:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>
</code></pre>
<p>So our workflow has the following tasks declared:</p>
<ol>
<li><p>"Checkout code" step that checks out the latest commit on the current branch.</p>
</li>
<li><p>"Use Node.js 16.x" step that sets up the Node.js environment to version 16.x.</p>
</li>
<li><p>"Install dependencies" step that installs the project dependencies using the Yarn package manager.</p>
</li>
<li><p>"Run tests" step that runs the project's tests using the Yarn package manager.</p>
</li>
<li><p>"Netlify Deploy" step that deploys the project to Netlify using the jsmrcaga/action-netlify-deploy action. This step uses the Netlify authentication token and site ID secrets stored in the GitHub repository's secrets. The build directory, install command, and build command are also specified.</p>
</li>
</ol>
<p>You probably noticed the first and last steps have the keyword <code>uses</code>. This keyword allows you to use actions or workflows developed by other GitHub users, and it's one of the best features of GitHub actions.</p>
<p>What's great is that by using this third party actions we can execute complex tasks such as deploying to an external host or building complex cloud infrastructure without the need to write every single line of necessary code.</p>
<p>As these tasks tend to be repetitive and frequently executed in many projects, we can just use a workflow developed by an official company account (such as Azure or AWS for example) or an independent open-source developer. Think about it as using a third party library. It's the same idea but taken to CI/CD workflows. Very convenient.</p>
<p>Another important thing to mention here is that in GitHub actions workflows tasks run <strong>sequentially</strong>, one after the other. And if a given task fails or throws and error, <strong>the next one won't execute</strong>. This is important because if we have a problem when installing our dependencies or a test fails, we don't want that code to be deployed.</p>
<p>Before we can push this code and see how the magic works, we first need to create a site on Netlify and get the <strong>NETLIFY_AUTH_TOKEN</strong> and <strong>NETLIFY_SITE_ID</strong>. This is quite straight forward even if you don't have previous experience with Netlify, so give it a try and Google a bit if you can't figure it out. ;)</p>
<p>Once you have these two tokens, you need to declare them as repository secrets in your GitHub repo. You can do this from the "settings" tab:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-32.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Configure both Netlify secret tokens in your repo</em></p>
<p>With this in place, now our <code>prod.yaml</code> file will be able to read these two tokens and execute the Netlify deploy action.</p>
<h2 id="heading-the-magic">The Magic</h2>
<p>Now that we have everything in place, let's push our code and see how it goes.</p>
<p>After pushing, if we go to the "actions" tabs of our repo, on the left we'll see a list of all the workflows we have in our repo. And on the right we'll see a list of each execution of the selected workflow. Since our workflow executes after each push, we should see a new execution each time we push.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>A workflow execution</em></p>
<p>When the execution has a yellow light to the left of it, it means it's still running (executing tasks). If it has a green light it means it finished executing successfully and if the light is red, you know something went wrong, haha...</p>
<p>After clicking on the execution we can see a list of the workflow's jobs (we only had a single one).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-34.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The workflow's jobs</em></p>
<p>And after clicking on the job we can see a list of the job's tasks.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-35.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The tasks of the job</em></p>
<p>Each task is expansible and within it we can see logs corresponding to that task's execution. This is quite useful for debugging purposes. ;)</p>
<p>Now if we go to our previously set up Netlify site, we should see our app up and running!</p>
<p>And now that we have our CI/CD pipeline in place, we can deploy our app after each push to the main branch, all without lifting another finger. =D</p>
<h1 id="heading-wrapping-up"><strong>Wrapping Up</strong></h1>
<p>CI/CD is a software development approach that provides several benefits to software development teams, including faster time-to-market, improved quality, increased collaboration, reduced risk, and cost-effectiveness.</p>
<p>By automating the software delivery pipeline, teams can quickly deploy new features and bug fixes, while reducing the risk of major failures and downtime.</p>
<p>With the availability of several CI/CD tools, it has become easier for teams to implement this approach and improve their software delivery process.</p>
<p>Well everyone, as always, I hope you enjoyed the article and learned something new.</p>
<p>If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/germancocca/">LinkedIn</a> or <a target="_blank" href="https://twitter.com/CoccaGerman">Twitter</a>. See you in the next one!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/giphy-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Setup a CI/CD Pipeline for a Next.js App using AWS ]]>
                </title>
                <description>
                    <![CDATA[ Hello Everyone! Deploying a web application is a challenging task (at least for me), especially when it comes to keeping it updated. It can take up a lot of time and energy if it has to be deployed manually every time you make a change.  But I recent... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/ci-cd-pipeline-for-nextjs-app-with-aws/</link>
                <guid isPermaLink="false">66ba109d90067134b63982bf</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Mon, 27 Mar 2023 21:53:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/Deploy-Next.js-using-AWS--1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello Everyone! Deploying a web application is a challenging task (at least for me), especially when it comes to keeping it updated. It can take up a lot of time and energy if it has to be deployed manually every time you make a change. </p>
<p>But I recently discovered a way to automate the deployment process for Next.js apps using AWS CodeDeploy and CodePipeline. It made my life so much easier, and I'm excited to share it with you.</p>
<p>In this tutorial, I'll guide you through the process of setting up auto-deployment for your Next.js app using the AWS services CodePipeline and CodeDeploy. By the end of it, you'll be able to save a lot of time by deploying your app automatically every time you push the code.</p>
<p>Let's get started!</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-deploy-the-nextjs-app-to-aws-ec2">How to Deploy the Next.js App to AWS EC2</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-the-nextjs-app-in-production-mode">How to Run the Next.js App in Production Mode</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-a-nextjs-app-forever-when-the-console-is-closed">How to Run a Next.js App Forever When the Console is Closed</a></li>
<li><a class="post-section-overview" href="#heading-what-is-codedeploy">What is CodeDeploy?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-auto-deployment-using-codepipeline-and-codedeploy">How to Setup Auto-Deployment using CodePipeline and CodeDeploy</a></li>
<li><a class="post-section-overview" href="#heading-how-to-attach-the-iam-role-to-ec2">How to Attach the IAM Role to EC2</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-codepipeline">How to Create the CodePipeline</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ol>
<li>EC2 machine running Ubuntu</li>
<li>Very basic knowledge of EC2 and IAM AWS Services</li>
</ol>
<h2 id="heading-how-to-deploy-the-nextjs-app-to-aws-ec2">How to Deploy the Next.js App to AWS EC2</h2>
<p>To start simple, let's manually deploy the sample Next.js boilerplate app "hello-world" to EC2. The steps are almost the same for all Next.js applications.</p>
<h3 id="heading-login-to-ec2">Login to EC2</h3>
<p>Login to the EC2 machine which you've created using the below command:</p>
<pre><code>ssh -i /path/key-pair-name.pem instance-user-name@instance-IP-address
</code></pre><p>When you try to log into EC2, this is the common error that most people will encounter (I got it, too):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-216.png" alt="Image" width="600" height="400" loading="lazy">
<em>Permissions 0664 for <code>.pem</code> file is too open error</em></p>
<p>This error describes that the <code>.pem</code> file should be read-protected. Only the root user should be able to read it. So, you have to set the file permission to <code>400</code>. Run the following command to achieve that:</p>
<pre><code>chmod <span class="hljs-number">400</span> key-pair-name.pem
</code></pre><p>EC2 by default comes with no software installed. Once you've logged into EC2, install NodeJS. There's an excellent <a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04">article</a> published by Digital Ocean and I use it every time I have to install Node on the server.</p>
<p>I have uploaded the <a target="_blank" href="https://github.com/5minslearn/deploy_nextjs_app">boilerplate repo</a> to Github. You can clone the repo by running the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/5minslearn/deploy_nextjs_app.git
</code></pre>
<p>Navigate to the project and install the dependencies by running the below commands.</p>
<p>A quick note here. I'm a big fan of yarn for its lightning-fast dependency management. But I see most people use <code>npm</code> to manage their dependencies. If you like to use <code>npm</code>, you can replace <code>yarn install</code> with <code>npm install</code> in the below commands.</p>
<p>If you like to go with <code>yarn</code>, install yarn by following this <a target="_blank" href="https://classic.yarnpkg.com/lang/en/docs/install/#debian-stable">tutorial</a> first.</p>
<pre><code>cd deploy_nextjs_app
yarn install
</code></pre><p>Let's run the application:</p>
<pre><code>yarn dev
</code></pre><p>Hit "http://ec2-public-ip-address:3000/" on your browser and you should be able to see the following page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-217.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next.js Hello World App</em></p>
<p>There's another common issue that most people face here which we'll look at next.</p>
<h3 id="heading-how-to-fix-the-timeout-error-ec2">How to fix the timeout error (EC2)</h3>
<p>"Oh, My God! My site is loading for a long time and finally, it's throwing a timeout error. What could be the issue? Where did I made mistake?"</p>
<p>If this happens to you, then you can follow the below steps to fix it.</p>
<p>This issue basically occurs if your server does not expose port 3000. Remember, by default Next apps will be running on port 3000. But, you have to allow port 3000 from the Security Group of your EC2 console to access from your browser.</p>
<p>Login to your AWS console, select your EC2 instance, and then select the Security Group option. Click on the "Edit inbound rules" button. Add port 3000 to the list as shown in the below screenshot. Then hit the "Save rules" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-218.png" alt="Image" width="600" height="400" loading="lazy">
<em>Adding port 3000 to a security group</em></p>
<p>Visit the link "http://ec2-public-ip-address:3000/", and you'll be amazed to see that your page loads like magic.</p>
<p>So far, we've just run our app in development mode and verified that it's working.</p>
<h2 id="heading-how-to-run-the-nextjs-app-in-production-mode">How to Run the Next.js App in Production Mode</h2>
<p>To deploy the app in Production Mode, you have to build your app first. Run <code>yarn build</code> to build the app and <code>yarn start</code> to start the app in production mode.</p>
<pre><code>yarn build
yarn start
</code></pre><p>Hit "http://ec2-public-ip-address:3000/" again and this time you'll see that your app loads faster than before.</p>
<p>Apps running in Production mode will always be faster when compared to the ones running in Development mode. This is because Production apps will be optimized for performance. </p>
<h2 id="heading-how-to-run-a-nextjs-app-forever-when-the-console-is-closed">How to Run a Next.js App Forever When the Console is Closed</h2>
<p>So, you have your app running now. But you might notice that it's blocking you from closing your terminal and exiting from server connection. If you do so, your site will be down. That's where PM2 comes to play. </p>
<p>Basically, PM2 is a process manager that helps keep Node applications alive all the time. It runs in the background managing Node applications for you.</p>
<p>Install PM2 using the following command:</p>
<pre><code>sudo yarn <span class="hljs-built_in">global</span> add pm2
</code></pre><p>After PM2 installation, run the below command to run and manage your app in the background:</p>
<pre><code>pm2 start yarn --name [name-<span class="hljs-keyword">of</span>-your-app] -- start -p [port-number]
</code></pre><p>Replace <code>[name-of-your-app]</code> with your app name and <code>[port-number]</code> with 3000. Here's an example command,</p>
<pre><code>pm2 start yarn --name next_hello_world_app -- start -p <span class="hljs-number">3000</span>
</code></pre><p>Hit "http://ec2-public-ip-address:3000/" and you'll again be amazed to see your app up and running.</p>
<p>It's always a best practice to save the PM2 process. When you reboot your instance, your PM2 instances will be lost. In order to restore it to its old state, you have to save the PM2 process. Here's the command for that:</p>
<pre><code>pm2 save
</code></pre><p>Here's the command to restore your PM2 instances on reboot (don't execute this now, we'll come back to this shortly):</p>
<pre><code>pm2 resurrect
</code></pre><p>We have successfully deployed the Next.js app manually. But remember, every time you make a code change and want to see the changes on your site, you have to login into EC2, pull the latest changes, build the app, and restart the app. </p>
<p>This will consume a lot of time and I'm too lazy to do it. So let's automate this in the next step!</p>
<p>Before setting up automatic deployment you have to know how CodeDeploy works.</p>
<h2 id="heading-what-is-codedeploy">What is CodeDeploy?</h2>
<p>CodeDeploy lets you deploy your application automatically to any number of EC2 instances. We need to prepare two items before beginning this process:</p>
<ol>
<li>CodeDeploy Agent must be installed in the EC2 instance. We use this to continuously poll CodeDeploy and deploy if any new changes are available.</li>
<li>A file called <code>appspec.yml</code> must be present in the root folder. This file describes the steps to be followed for the deployment.</li>
</ol>
<p>There is awesome <a target="_blank" href="https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-install-ubuntu.html">documentation</a> by AWS to help you install CodeDeploy Agent. Please follow each and every step to install CodeDeploy Agent on your EC2 machine.</p>
<p>To verify that CodeDeploy agent is installed, run the below command. If you see <em>active (running),</em> Kudos to you! CodeDeploy was installed successfully.</p>
<pre><code>sudo service codedeploy-agent status
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-219.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodeDeploy Agent running status</em></p>
<p>Now let's create the <code>appspec.yml</code> file. I've written the deployment instructions in the <code>deploy.sh</code> file. It's enough to run this file in the <code>appspec.yml</code> file. If you want to learn more about <code>appspec.yml</code>, check out the AWS official <a target="_blank" href="https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure.html">documentation</a>.</p>
<p>Create a file called <code>appspec.yml</code> and add the following contents:</p>
<pre><code>version: <span class="hljs-number">0.0</span>
<span class="hljs-attr">os</span>: linux
<span class="hljs-attr">hooks</span>:
  ApplicationStart:
    - location: deploy.sh
      <span class="hljs-attr">timeout</span>: <span class="hljs-number">300</span>
      <span class="hljs-attr">runas</span>: ubuntu
</code></pre><p>I hope you understand the instructions in the above file. If not, here's a super simple explanation. I'm advising the CodeDeploy Agent that I'm running a Linux OS in my instance and instructing it to run the <code>deploy.sh</code> file as <code>ubuntu</code> user with the timeout set to 300 seconds. </p>
<p>Here's my <code>deploy.sh</code> file:</p>
<pre><code>#!<span class="hljs-regexp">/bin/</span>bash
cd /path/to/project/on/EC2 
git pull origin master
yarn install &amp;&amp;
yarn build &amp;&amp;
pm2 restart [name]
</code></pre><p>This file contains instructions to navigate to the project folder on EC2, pull the latest code from source control, install dependencies, build the project, and restart the project instance.</p>
<p>This file is already available in the repo. No action for you here. Now it's time to set up automatic deployment.</p>
<h2 id="heading-how-to-setup-auto-deployment-using-codepipeline-and-codedeploy">How to Setup Auto-Deployment using CodePipeline and CodeDeploy</h2>
<p>Two IAM roles have to be created to set up auto-deployment. Some complications will begin from here. To make things simple, I've attached screenshots with the appropriate items highlighted with red boxes.</p>
<h3 id="heading-create-an-iam-role-for-codedeploy">Create an IAM Role for CodeDeploy</h3>
<p>You have to create this role to deploy the code every time you push. </p>
<p>Navigate to IAM in the AWS Console by searching for "IAM" in the search bar at the top. Click Roles on the left pane and Click the "Create role" button at the top right.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-220.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create IAM role</em></p>
<p>Choose AWS service in Trusted entity types and choose CodeDeploy in the Use cases section and proceed to the next step.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-221.png" alt="Image" width="600" height="400" loading="lazy">
<em>IAM role for CodeDeploy</em></p>
<p>Now, you can see that the AWSCodeDeployRole policy is the only policy available, and it'll be chosen by default in this (Permissions) step. Let's proceed to the next section. No action for you here. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-222.png" alt="Image" width="600" height="400" loading="lazy">
<em>AWSCodeDeploy Permission</em></p>
<p>Enter a name for your IAM role. You should choose a meaningful name to identify this in the future. I'm calling it <em>service-role-for-code-deploy</em>. Review the permission in the JSON and click the Create role button at the bottom.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-223.png" alt="Image" width="600" height="400" loading="lazy">
<em>AWSCodeDeploy Permission Review</em></p>
<h3 id="heading-create-an-iam-role-for-ec2">Create an IAM role for EC2</h3>
<p>Let's create the next role. This role is for EC2. Choose AWS service in the Trusted entity type, EC2 in the Common use cases section, and choose CodeDeploy in Use cases for other AWS services. Click Next to proceed to the next section.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-224.png" alt="Image" width="600" height="400" loading="lazy">
<em>IAM role for EC2</em></p>
<p>There are a lot of policies available for EC2 and CodeDeploy. In the Add permissions section, search for <em>codedeploy</em> (No space between code and deploy) and select "AmazonEC2RoleForCodeDeploy" and proceed to the next step.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-225.png" alt="Image" width="600" height="400" loading="lazy">
<em>Adding AmazonEC2RoleForCodeDeploy permission</em></p>
<p>No change in this step. Review and give a meaningful name (I'm naming it as "code-deploy-role-for-ec2") for your role and click "Create role" button.</p>
<h2 id="heading-how-to-attach-the-iam-role-to-ec2">How to Attach the IAM Role to EC2</h2>
<p>Once the IAM role for EC2 is created, we have to attach it to the EC2 instance.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-226.png" alt="Image" width="600" height="400" loading="lazy">
<em>EC2 instance before attaching the IAM role</em></p>
<p>To attach the IAM role to the EC2 instance, open your EC2 instance, click on the "Actions" button on the top right, and select "Security" in the drop-down. Then select "Modify IAM role".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-227.png" alt="Image" width="600" height="400" loading="lazy">
<em>Modify IAM role for EC2 instance</em></p>
<p>Select the IAM role which you created last (code-deploy-role-for-ec2) and click the "Update IAM role" button. Reboot the EC2 for the changes to take effect.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-228.png" alt="Image" width="600" height="400" loading="lazy">
<em>Update IAM role for EC2 instance</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-229.png" alt="Image" width="600" height="400" loading="lazy">
<em>EC2 instance after attaching IAM role</em></p>
<p>After rebooting the EC2, login to EC2 with SSH and run the <code>pm2 resurrect</code> command to restore the PM2 processes. Failing to do this may land you at "PM2 Process or Namespace not found error" while running automatic deployment. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-230.png" alt="Image" width="600" height="400" loading="lazy">
<em>PM2 process restore</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-231.png" alt="Image" width="600" height="400" loading="lazy">
<em>PM2 process or namespace not found an error</em></p>
<h3 id="heading-how-to-create-the-codedeploy-application">How to Create the CodeDeploy Application</h3>
<p>In the AWS Console, search "CodeDeploy" in the search bar at the top. Select "Applications" in the left pane. Click on the "Create application" button on the top right.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-232.png" alt="Image" width="600" height="400" loading="lazy">
<em>Navigate to CodeDeploy in AWS Console</em></p>
<p>Enter the Application name, choose the "EC2/On-premises" compute platform, and click the "Create application" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-233.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create CodeDeploy application</em></p>
<p>Once it's done, you'll automatically be redirected to the Deployment groups section. We have to create a deployment group. Click on the "Create deployment group" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-234.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create CodeDeploy Deployment group</em></p>
<p>Enter the deployment group name, select the service role (1st created role) you created, and select the deployment type as in-place:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-235.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create CodeDeploy Deployment group</em></p>
<p>In the Environment configuration section, select "Amazon EC2 instances" and select the key as Name. Enter your EC2 instance name in the value.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-236.png" alt="Image" width="600" height="400" loading="lazy">
<em>Code Deployment Group Environment configuration</em></p>
<p>In the Agent configuration section, select Never, as we installed CodeDeployAgent already. Select "CodeDeployDefault.AllAtOnce" in the Deployment settings section. Leave the "Enable load balancing" checkbox unchecked. Finally, click the "Create a deployment group" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-237.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodeDeploy deployment group configurations</em></p>
<h2 id="heading-how-to-create-the-codepipeline">How to Create the CodePipeline</h2>
<p>AWS CodePipeline helps you to automate your release pipelines for fast and reliable application and infrastructure updates. Now it's time to create our CodePipeline. In the AWS Console, search for "CodePipeline" in the search bar.</p>
<p>Select "Pipelines" in the left pane and click on "Create pipeline" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-238.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create CodePipeline</em></p>
<p>Enter the Pipeline name, and Role name. Remember, we created roles for EC2 and CodeDeploy, but not for CodePipeline. AWS by default creates it from here. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-239.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodePipeline settings</em></p>
<h3 id="heading-add-source-stage">Add Source Stage</h3>
<p>In this step, we have to connect our repo with CodePipeline to deploy the changes immediately after the code is pushed.</p>
<p>We'll be using GitHub as our source. Choose GitHub (version 2) in the source provider, and click on the "Connect to GitHub" button. This will open up a new pop-up window. Click on the "Connect to GitHub" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-240.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodePipeline adding source stage</em></p>
<p>This will take you to the GitHub authorization page where you have to sign into your GitHub account. Click on the "Install a new app" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-241.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodePipeline Github Authorization</em></p>
<p>Choose "Only select repositories" and choose your repository below that.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-242.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing AWS connector for GitHub</em></p>
<p>Once installed, it will prompt you for the password. Click the "Connect" button once you're done with your authentication.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-243.png" alt="Image" width="600" height="400" loading="lazy">
<em>Connecting GitHub to AWS</em></p>
<p>After connecting to GitHub, select the Repository name and branch name. To start the CodePipline on code change, it's important to select the check box "Start the pipeline on source code change" – otherwise auto deployment will not happen. For "Output and artifact format", select "CodePipeline default" and click the "Next" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-244.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodePipeline - Select source code repo</em></p>
<p>The next step is to add the build stage, but since we're deploying a simple app we don't need a build stage. Enterprise companies prefer to build their app using AWS CodeBuild service. Let's keep things simple and simply skip the build stage. </p>
<p>If you want me to write about CodeBuild let me know, I will try to cover it in my upcoming tutorials. </p>
<h3 id="heading-add-deploy-stage">Add Deploy Stage</h3>
<p>In the deployment stage step, choose "AWS CodeDeploy" for the "Deploy provider" and select the region where you created the above CodeDeploy application. Then select the "Application name" and "Deployment group" that we created in the previous steps and click the "Next" button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-245.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodePipleine - Adding Deployment stage</em></p>
<p>The last step is "Review". Review everything carefully and click on the "Create pipeline" button. Once the pipeline is created it will start the deployment process. If you followed all the above steps, the pipeline should read "Succeeded" on your very first build.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-246.png" alt="Image" width="600" height="400" loading="lazy">
<em>Pipeline Succeeded</em></p>
<h3 id="heading-how-to-verify-auto-deployment">How to Verify Auto-Deployment</h3>
<p>Now let's verify if the Auto-deployment works properly. This is the Home page of our project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-247.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next.js Hello World App</em></p>
<p>Let's change the text from "Hello World" to "Welcome to 5minslearn" and push the code to GitHub.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-248.png" alt="Image" width="600" height="400" loading="lazy">
<em>Git code diff</em></p>
<p>Here we go! The CodePipeline has triggered automatically and the changes were successfully deployed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-249.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodeDeploy getting triggered automatically on code changes in Git</em></p>
<p>Now head to "http://ec2-public-ip-address:3000/", you will see the below page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-250.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next.js App after auto deployment</em></p>
<p>Congrats! 🎉 We successfully completed setting up auto-deployment for a Next.js app.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we learned how to deploy Next.js manually on EC2 and set up auto-deployment using AWS services such as CodeDeploy and CodePipeline.</p>
<p>Hope you enjoyed reading this article! If you are stuck at any point feel free to drop your queries to my <a target="_blank" href="mailto:arun@gogosoon.com">email</a>. I'll be happy to help you!</p>
<p>If you wish to learn more about AWS, subscribe to my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_nextjs_deployment">newsletter</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_nextjs_deployment">https://5minslearn.gogosoon.com/</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ MERN App Development – How to Build a CI/CD Pipeline with Jenkins ]]>
                </title>
                <description>
                    <![CDATA[ By Rakesh Potnuru As you continue to develop your software, you must also continue to integrate it with previous code and deploy it to servers.  Manually doing this is a time-consuming process that can occasionally result in errors. So we need to do ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/automate-mern-app-deployment-with-jenkins/</link>
                <guid isPermaLink="false">66d460c5d14641365a05095d</guid>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Jenkins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mongo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 08 Mar 2023 17:42:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/CICD-Pipeline-with-Jenkins.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rakesh Potnuru</p>
<p>As you continue to develop your software, you must also continue to integrate it with previous code and deploy it to servers. </p>
<p>Manually doing this is a time-consuming process that can occasionally result in errors. So we need to do this in a continuous and automated manner – which is what you will learn in this article.</p>
<p>We'll go over how you can improve your MERN (MongoDB, Express, React, and NodeJs) app development process by setting up a CI/CD pipeline with Jenkins. You'll see how to automate deployment for faster, more efficient releases.</p>
<h2 id="heading-lets-get-started">Let's Get Started</h2>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Basic understanding of MERN stack technologies.</li>
<li>Basic understanding of Docker.</li>
<li>Get source code from <a target="_blank" href="https://github.com/itsrakeshhq/productivity-app">GitHub</a></li>
</ul>
<h2 id="heading-the-problem">The Problem</h2>
<p>Consider this <a target="_blank" href="https://github.com/itsrakeshhq/productivity-app">productivity app</a> – it's a MERN project that we are going to use in this article. There are numerous steps we must complete, from building the application to pushing it to the Docker hub. </p>
<p>First, we must run tests with a command to determine whether all tests pass or not. If all tests pass, we build the Docker images and then push those images to Docker Hub. If your application is extremely complex, you may need to take additional steps. </p>
<p>Now, imagine that we're doing everything manually, which takes time and can lead to mistakes.</p>
<p><img src="https://i.imgur.com/iWAmMm4.jpg" alt="Waiting for deployment without devops meme" width="1600" height="840" loading="lazy">
<em>Waiting for deployment without devops meme</em></p>
<h2 id="heading-the-solution">The Solution</h2>
<p>To address this problem, we can create a CI/CD <strong>Pipeline</strong>. So, whenever you add a feature or fix a bug, this pipeline gets triggered. This automatically performs all of the steps from testing to deploying.</p>
<h2 id="heading-what-is-cicd-and-why-is-it-important">What is CI/CD and Why is it Important?</h2>
<p><strong>C</strong>ontinuous <strong>I</strong>ntegration and <strong>C</strong>ontinuous <strong>D</strong>eployment is a series of steps performed to automate software integration and deployment. CI/CD is the heart of DevOps.</p>
<p><img src="https://i.imgur.com/uMFtPwJ.png" alt="ci cd steps" width="1920" height="1080" loading="lazy">
<em>CI/CD steps</em></p>
<p>From development to deployment, our MERN app goes through four major stages: testing, building Docker images, pushing to a registry, and deploying to a cloud provider. All of this is done manually by running various commands. And we need to do this every time a new feature is added or a bug is fixed. </p>
<p>But this will significantly reduce developer productivity, which is why CI/CD can be so helpful in automating this process. In this article, we will cover the steps up until pushing to the registry.</p>
<p><img src="https://i.imgur.com/g2omESy.png" alt="ci cd meme" width="1600" height="840" loading="lazy">
<em>CI/CD meme</em></p>
<h2 id="heading-the-project">The Project</h2>
<p>The project we are going to use in this tutorial is a very simple full-stack MERN application.</p>
<p><img src="https://i.imgur.com/GSvRlQ0.gif" alt="project demo" width="600" height="338" loading="lazy">
<em>Project demo</em></p>
<p>It contains two microservices.</p>
<ol>
<li>Frontend</li>
<li>Backend</li>
</ol>
<p>You can learn more about the project <a target="_blank" href="https://blog.itsrakesh.co/lets-build-and-deploy-a-full-stack-mern-web-application">here</a>.</p>
<p>Both of these applications contains a Dockerfile. You can learn how to dockerize a MERN application <a target="_blank" href="https://blog.itsrakesh.co/dockerizing-your-mern-stack-app-a-step-by-step-guide">here</a>.</p>
<h2 id="heading-what-is-jenkins">What is Jenkins?</h2>
<p>To run a CI/CD pipeline, we need a CI/CD server. This is where all of the steps written in a pipeline run. </p>
<p>There are numerous services available on the market, including GitHub Actions, Travis CI, Circle CI, GitLab CI/CD, AWS CodePipeline, Azure DevOps, and Google Cloud Build. Jenkins is one of the popular CI/CD tools, and it's what we'll use here.</p>
<h2 id="heading-how-to-set-up-jenkins-server-on-azure">How to Set Up Jenkins Server on Azure</h2>
<p>Because Jenkins is open source and it doesn't provide a cloud solution, we must either run it locally or self-host on a cloud provider. Now, running locally can be difficult, particularly for Windows users. As a result, I've chosen to self-host it on Azure for this demo.</p>
<p>If you want to run locally or self-host somewhere other than Azure (follow <a target="_blank" href="https://www.jenkins.io/doc/book/installing/">these</a> guides by Jenkins), skip this section and proceed to the <strong>How to Configure Jenkins</strong> section.</p>
<p>First, you'll need to sign in to your <a target="_blank" href="https://Azure.microsoft.com?wt.mc_id=studentamb_90351">Azure</a> account (Create one if you don't have one already). Open Azure Cloud Shell.</p>
<p><img src="https://i.imgur.com/IN6RXAe.png" alt="opening azure cloud shell" width="2120" height="467" loading="lazy">
<em>Opening Azure Cloud Shell</em></p>
<p>Then create a directory called <code>jenkins</code> to store all the Jenkins config, and switch to that directory:</p>
<pre><code class="lang-bash">mkdir jenkins
<span class="hljs-built_in">cd</span> jenkins
</code></pre>
<p>Create a file called <code>cloud-init-jenkins.txt</code>. Open with nano or vim,</p>
<pre><code class="lang-bash">touch cloud-init-jenkins.txt
nano cloud-init-jenkins.txt
</code></pre>
<p>and paste this code into it:</p>
<pre><code class="lang-bash"><span class="hljs-comment">#cloud-config</span>
package_upgrade: <span class="hljs-literal">true</span>
runcmd:
  - sudo apt install openjdk-11-jre -y
  - wget -qO - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
  - sh -c <span class="hljs-string">'echo deb https://pkg.jenkins.io/debian-stable binary/ &gt; /etc/apt/sources.list.d/jenkins.list'</span>
  - sudo apt-get update &amp;&amp; sudo apt-get install jenkins -y
  - sudo service jenkins restart
</code></pre>
<p>Here, we'll use this file to install Jenkins after creating a virtual machine. First, we install openjdk, which is required for Jenkins to function. The Jenkins service is then restarted after we install it.</p>
<p>Next, create a resource group. (A resource group in Azure is like a container that holds all the related resources of a project in one group. Learn more about resource groups <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal#what-is-a-resource-group?wt.mc_id=studentamb_90351">here</a>.)</p>
<pre><code class="lang-bash">az group create --name jenkins-rg --location centralindia
</code></pre>
<p><strong>Note:</strong> make sure to change the location to the one closest to you.</p>
<p>Now, create a virtual machine.</p>
<pre><code class="lang-bash">az vm create \
--resource-group jenkins-rg \
--name jenkins-vm \
--image UbuntuLTS \
--admin-username <span class="hljs-string">"azureuser"</span> \
--generate-ssh-keys \
--public-ip-sku Standard \
--custom-data cloud-init-jenkins.txt
</code></pre>
<p>You can verify the VM installation with this command:</p>
<pre><code class="lang-bash">az vm list -d -o table --query <span class="hljs-string">"[?name=='jenkins-vm']"</span>
</code></pre>
<p>Don't be confused. This command simply displays JSON data in a tabular format for easy verification.</p>
<p>Jenkins server runs on port <code>8080</code>, so we need to expose this port on our VM. You can do that like this:</p>
<pre><code class="lang-bash">az vm open-port \
--resource-group jenkins-rg \
--name jenkins-vm  \
--port 8080 --priority 1010
</code></pre>
<p>Now we can access the Jenkins dashboard in the browser with the URL <code>http://&lt;your-vm-ip&gt;:8080</code>. Use this command to get the VM IP address:</p>
<pre><code class="lang-bash">az vm show \
--resource-group jenkins-rg \
--name jenkins-vm -d \
--query [publicIps] \
--output tsv
</code></pre>
<p>You can now see the Jenkins application in your browser.</p>
<p><img src="https://i.imgur.com/Sy1Glar.png" alt="jenkins dashboard" width="2007" height="1025" loading="lazy">
<em>Jenkins dashboard</em></p>
<p>As you'll notice, Jenkins is asking us to provide an admin password which is automatically generated during its installation.</p>
<p>But first let's SSH into our virtual machine where Jenkins is installed.</p>
<pre><code class="lang-bash">ssh azureuser@&lt;ip_address&gt;
</code></pre>
<p>Now, type in the below command to get the password:</p>
<pre><code class="lang-bash">sudo cat /var/lib/jenkins/secrets/initialAdminPassword
</code></pre>
<p>Copy and paste it. Then click <strong>Continue</strong>.</p>
<h2 id="heading-how-to-configure-jenkins">How to Configure Jenkins</h2>
<p>First, you'll need to click <strong>Install suggested plugins</strong>. It will take some time to install all the plugins.</p>
<p><img src="https://i.imgur.com/vDaaqE3.png" alt="installing suggested plugins" width="2010" height="1095" loading="lazy">
<em>Installing suggested plugins</em></p>
<p>An admin user is needed to restrict access to Jenkins. So go ahead and create one. After finishing, click <strong>Save and continue</strong>.</p>
<p><img src="https://i.imgur.com/qqkwQN6.png" alt="create an admin user" width="2010" height="1036" loading="lazy">
<em>Create an admin user</em></p>
<p>Now you will be presented with the Jenkins dashboard.</p>
<p>The first step is to install the "Blue Ocean" plugin. Jenkins has a very old interface, which may make it difficult for some people to use. This blue ocean plugin provides a modern interface for some Jenkins components (like creating a pipeline).</p>
<p>To install plugins, go to <strong>Manage Jenkins</strong> -&gt; click <strong>Manage Plugins</strong> under "System Configuration" -&gt; <strong>Available plugins</strong>. Search for "Blue Ocean" -&gt; check the box and click <strong>Download now and install after restart</strong>.</p>
<p><img src="https://i.imgur.com/dAKBLiq.png" alt="blue ocean" width="1920" height="1080" loading="lazy">
<em>Blue ocean</em></p>
<p>Great, we're all set. Now let's create a pipeline.</p>
<h2 id="heading-how-to-write-a-jenkinsfile">How to Write a Jenkinsfile</h2>
<p>To create a pipeline, we need a <strong>Jenkinsfile</strong>. This file contains all the pipeline configurations – stages, steps, and so on. Jenkinsfile is to Jenkins as a Dockerfile is to Docker.</p>
<p>Jenkinsfile uses the <strong>Groovy</strong> syntax. The syntax is very simple. You can understand everything by just looking at it.</p>
<p>Let's start by writing:</p>
<pre><code class="lang-groovy">pipeline {

}
</code></pre>
<p>The word 'agent' should be the first thing you mention in the pipeline. An agent is similar to a container or environment in which jobs run. You can use multiple agents to run jobs in parallel. You can find more information about Jenkins agents can <a target="_blank" href="https://www.jenkins.io/doc/book/using/using-agents/">here</a>.</p>
<pre><code class="lang-groovy">pipeline {
    agent any
}
</code></pre>
<p>Here we are telling Jenkins to use any available agent.</p>
<p>We have a total of 5 stages in our pipeline:</p>
<p><img src="https://i.imgur.com/ezvdElo.png" alt="ci cd pipeline stages" width="1920" height="1080" loading="lazy">
<em>CI/CD pipeline stages</em></p>
<h3 id="heading-stage-1-checkout-code">Stage 1: Checkout code</h3>
<p>Different CI/CD tools use different naming conventions. In Jenkins, these are referred to as stages. In each stage we write various steps.</p>
<p>Our first stage is checking out code from a source code management system (in our case, GitHub).</p>
<pre><code class="lang-groovy">pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
    }
}
</code></pre>
<p>Commit the changes and push to your GitHub repo.</p>
<p>Since we haven't created any pipelines yet, let's do that now.</p>
<p>Before we begin, we must ensure that Git is installed on our system. If you followed my previous steps to install Jenkins on an Azure VM, Git is already installed. </p>
<p>You can test it by running the following command (make you are still SSHed into the VM):</p>
<pre><code class="lang-bash">git --version
</code></pre>
<p>If it isn't already installed, you can do so with:</p>
<pre><code class="lang-bash">sudo apt install git
</code></pre>
<p>Open blue ocean. Click <strong>Create new pipeline</strong>.</p>
<p><img src="https://i.imgur.com/FNffT6p.png" alt="creating new pipeline" width="2010" height="1036" loading="lazy">
<em>Creating new pipeline</em></p>
<p>Then select your source code management system. If you chose GitHub, you must provide an access token for Jenkins to access your repository. I recommend clicking on <strong>Create an access token here</strong> because it is a template with all of the necessary permissions. Then click <strong>Connect</strong>.</p>
<p><img src="https://i.imgur.com/H9TUsHV.png" alt="selecting scm" width="2010" height="1036" loading="lazy">
<em>Selecting scm</em></p>
<p>After that, a pipeline will be created. Since our repository already contains a Jenkinsfile, Jenkins automatically detects it and runs the stages and steps we mentioned in the pipeline.</p>
<p>If everything went well, the entire page will turn green. (Other colors: <strong>blue</strong> indicates that the pipeline is running, <strong>red</strong> indicates that something went wrong in the pipeline, and <strong>gray</strong> indicates that we stopped the pipeline.)</p>
<p><img src="https://i.imgur.com/FtvJlND.png" alt="stage one successful" width="1884" height="486" loading="lazy">
<em>Stage one successful</em></p>
<h3 id="heading-stage-2-run-frontend-tests">Stage 2: Run frontend tests</h3>
<p>In general, all the CI/CD pipelines contains some tests that needs to be run before deploying. So I added simple tests to both the frontend and backend. Let's start with the frontend tests.</p>
<pre><code class="lang-groovy">stage('Client Tests') {
    steps {
        dir('client') {
            sh 'npm install'
            sh 'npm test'
        }
    }
}
</code></pre>
<p>We're changing the directory to <code>client/</code> because that's where the frontend code is. And then install the dependencies with <code>npm install</code> and run the tests with <code>npm test</code> in a shell.</p>
<p>Again, before we restart the pipeline, we have to make sure node and npm are installed or not. Install node and npm with these commands in the virtual machine:</p>
<pre><code class="lang-bash">curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
</code></pre>
<p>After that, run the following:</p>
<pre><code class="lang-bash">sudo apt-get install -y nodejs
</code></pre>
<p>Now, commit the code and restart the pipeline.</p>
<p><img src="https://i.imgur.com/OWYcdDu.png" alt="run client tests" width="1886" height="438" loading="lazy">
<em>Run client tests</em></p>
<h3 id="heading-stage-3-run-backend-tests">Stage 3: Run backend tests</h3>
<p>Now do the same thing for the backend tests.</p>
<p>But there is one thing we need to do before we proceed. If you take a look at the codebase and <code>activity.test.js</code>, we are using a few environment variables. So let's add these environment varibales in Jenkins.</p>
<h4 id="heading-how-to-add-environment-variables-in-jenkins">How to add environment variables in Jenkins</h4>
<p>To add environment variables, go to <strong>Manage Jenkins</strong> -&gt; click <strong>Manage Credentials</strong> under "Security" -&gt;  <strong>System</strong> -&gt; <strong>Global credentials (unrestricted)</strong> -&gt; click <strong>+ Add Credentials</strong>.</p>
<p>For <strong>Kind</strong> select "Secret text", leave <strong>Scope</strong> default, and for <strong>Secret</strong> write the secret value and <strong>ID</strong>. This is what we use when using these environment variables in the Jenkinsfile.</p>
<p>Add the following env variables:</p>
<p><img src="https://i.imgur.com/xGjg2mG.png" alt="environment variables" width="2091" height="796" loading="lazy">
<em>Environment variables</em></p>
<p>Then in the Jenkinsfile, use these env variables:</p>
<pre><code class="lang-groovy">environment {
    MONGODB_URI = credentials('mongodb-uri')
    TOKEN_KEY = credentials('token-key')
    EMAIL = credentials('email')
    PASSWORD = credentials('password')
}
</code></pre>
<p>Add a stage to install dependencies, set these variables in the Jenkins environment, and run the tests:</p>
<pre><code class="lang-groovy">stage('Server Tests') {
    steps {
        dir('server') {
            sh 'npm install'
            sh 'export MONGODB_URI=$MONGODB_URI'
            sh 'export TOKEN_KEY=$TOKEN_KEY'
            sh 'export EMAIL=$EMAIL'
            sh 'export PASSWORD=$PASSWORD'
            sh 'npm test'
        }
    }
}
</code></pre>
<p>Again, commit the code and restart the pipeline.</p>
<p><img src="https://i.imgur.com/hpjMUyT.png" alt="run server tests" width="1059" height="595" loading="lazy">
<em>Run server tests</em></p>
<h3 id="heading-stage-4-build-docker-images">Stage 4: Build Docker images</h3>
<p>Now, we have to specify a step to build the Docker images from the Dockerfiles.</p>
<p>Before we proceed, install Docker in the VM (if you don't already have it installed).</p>
<p>To install Docker:</p>
<pre><code class="lang-bash">sudo apt install docker.io
</code></pre>
<p>Add the user <code>jenkins</code> to the <code>docker</code> group so that Jenkins can access the Docker daemon – otherwise you'll get a permission denied error.</p>
<pre><code class="lang-bash">sudo usermod -a -G docker jenkins
</code></pre>
<p>Then restart the <code>jenkins</code> service.</p>
<pre><code class="lang-bash">sudo systemctl restart jenkins
</code></pre>
<p>Add a stage in the Jenkinsfile.</p>
<pre><code class="lang-groovy">stage('Build Images') {
    steps {
        sh 'docker build -t rakeshpotnuru/productivity-app:client-latest client'
        sh 'docker build -t rakeshpotnuru/productivity-app:server-latest server'
    }
}
</code></pre>
<p>Commit the code and restart the pipeline.</p>
<p><img src="https://i.imgur.com/USh63SD.png" alt="build docker images" width="1984" height="914" loading="lazy">
<em>Build docker images</em></p>
<h3 id="heading-stage-5-push-images-to-the-registry">Stage 5: Push images to the registry</h3>
<p>As a final stage, we will push the images to Docker hub.</p>
<p>Before that, add your docker hub username and password to the Jenkins credentials manager, but for <strong>Kind</strong> choose "Username with password".</p>
<p><img src="https://i.imgur.com/ue0MMKM.png" alt="username with password type credential" width="2010" height="1095" loading="lazy">
<em>Username with password type credential</em></p>
<p>Add the final stage where we login and push images to Docker hub.</p>
<pre><code class="lang-groovy">stage('Push Images to DockerHub') {
    steps {
        withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
            sh 'docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD'
            sh 'docker push rakeshpotnuru/productivity-app:client-latest'
            sh 'docker push rakeshpotnuru/productivity-app:server-latest'
        }
    }
}
</code></pre>
<p><img src="https://i.imgur.com/copfIou.png" alt="push images to dockerhub" width="1991" height="919" loading="lazy">
<em>Push images to dockerhub</em></p>
<p>Here is the complete Jenkinsfile:</p>
<pre><code class="lang-groovy">// This is a Jenkinsfile. It is a script that Jenkins will run when a build is triggered.
pipeline {
    // Telling Jenkins to run the pipeline on any available agent.
    agent any

    // Setting environment variables for the build.
    environment {
        MONGODB_URI = credentials('mongodb-uri')
        TOKEN_KEY = credentials('token-key')
        EMAIL = credentials('email')
        PASSWORD = credentials('password')
    }

    // This is the pipeline. It is a series of stages that Jenkins will run.
    stages {
        // This state is telling Jenkins to checkout the source code from the source control management system.
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        // This stage is telling Jenkins to run the tests in the client directory.
        stage('Client Tests') {
            steps {
                dir('client') {
                    sh 'npm install'
                    sh 'npm test'
                }
            }
        }

        // This stage is telling Jenkins to run the tests in the server directory.
        stage('Server Tests') {
            steps {
                dir('server') {
                    sh 'npm install'
                    sh 'export MONGODB_URI=$MONGODB_URI'
                    sh 'export TOKEN_KEY=$TOKEN_KEY'
                    sh 'export EMAIL=$EMAIL'
                    sh 'export PASSWORD=$PASSWORD'
                    sh 'npm test'
                }
            }
        }

        // This stage is telling Jenkins to build the images for the client and server.
        stage('Build Images') {
            steps {
                sh 'docker build -t rakeshpotnuru/productivity-app:client-latest client'
                sh 'docker build -t rakeshpotnuru/productivity-app:server-latest server'
            }
        }

        // This stage is telling Jenkins to push the images to DockerHub.
        stage('Push Images to DockerHub') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
                    sh 'docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD'
                    sh 'docker push rakeshpotnuru/productivity-app:client-latest'
                    sh 'docker push rakeshpotnuru/productivity-app:server-latest'
                }
            }
        }
    }
}
</code></pre>
<p><img src="https://i.imgur.com/NQxFXhO.png" alt="pipeline ran successfully" width="2120" height="1155" loading="lazy">
<em>Pipeline ran successfully</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In summary, let's review what we've covered:</p>
<ul>
<li>We explored the significance of implementing Continuous Integration and Continuous Deployment (CI/CD) in software development.</li>
<li>We delved into the fundamentals of Jenkins and acquired knowledge on how to deploy a Jenkins server on the Azure cloud platform.</li>
<li>We customized Jenkins to meet our specific requirements.</li>
<li>Lastly, we wrote a Jenkinsfile and built a pipeline utilizing the user-friendly interface of Jenkins Blue Ocean.</li>
</ul>
<p>That's all for now! Thanks for reading 🙂.</p>
<p>Connect with me on <a target="_blank" href="https://twitter.com/rakesh_at_tweet">twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Github Actions to Deploy a Next.js Website to AWS S3 ]]>
                </title>
                <description>
                    <![CDATA[ The beauty of Next.js and static web apps is that they let you run the project pretty much anywhere using object storage, like on AWS S3. But it can be a pain to manually update those files each time.  How can we use GitHub Actions to automate and co... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-github-actions-to-deploy-a-next-js-website-to-aws-s3/</link>
                <guid isPermaLink="false">66b8e3759232d58aac300b17</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub Actions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Mon, 02 Nov 2020 19:27:28 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/10/actions-s3.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The beauty of Next.js and static web apps is that they let you run the project pretty much anywhere using object storage, like on AWS S3. But it can be a pain to manually update those files each time. </p>
<p>How can we use GitHub Actions to automate and continuously deploy our app to S3?</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-github-actions">What are GitHub Actions?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-continuous-deployment">What is Continuous Deployment?</a></li>
<li><a class="post-section-overview" href="#heading-what-are-we-going-to-build">What are we going to build?</a></li>
<li><a class="post-section-overview" href="#heading-step-0-setting-up-a-new-nextjs-project-on-github">Step 0: Setting up a new Next.js project on GitHub</a></li>
<li><a class="post-section-overview" href="#heading-step-1-manually-creating-and-deploying-a-nextjs-project-to-a-new-s3-bucket">Step 1: Manually creating and deploying a Next.js project to a new S3 Bucket</a></li>
<li><a class="post-section-overview" href="#heading-step-2-creating-a-new-github-action-workflow-to-automatically-build-a-nextjs-project">Step 2: Creating a new GitHub Action workflow to automatically build a Next.js project</a></li>
<li><a class="post-section-overview" href="#heading-step-3-configuring-a-github-action-to-deploy-a-static-website-to-s3">Step 3: Configuring a GitHub Action to deploy a static website to S3</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/D3h91EvRxuk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-are-github-actions">What are GitHub Actions?</h2>
<p>GitHub Actions is a free service from GitHub that allows us to automate code tasks.</p>
<p>I <a target="_blank" href="https://www.freecodecamp.org/news/what-are-github-actions-and-how-can-you-automate-tests-and-slack-notifications/">previously wrote about</a> how we can use them to automate tasks like running tests on our code and sending notifications to Slack.</p>
<p>They provide a flexible way to automatically run code based on our existing workflows. This provides a lot of possibilities like even deploying our website!</p>
<h2 id="heading-what-is-aws-s3">What is AWS S3?</h2>
<p><a target="_blank" href="https://aws.amazon.com/s3/">S3</a> (Simple Storage Service) is an object storage service from AWS. It allows you to store files in the cloud easily making them available around the world.</p>
<p>It also allows you to use these files as a website. Because we can upload an HTML file as an object, we can also configure S3 to access that file as an HTTP request. This means that we can <a target="_blank" href="https://www.freecodecamp.org/news/how-to-host-and-deploy-a-static-website-or-jamstack-app-to-s3-and-cloudfront/">host an entire website right in S3</a>.</p>
<h2 id="heading-what-is-continuous-deployment">What is Continuous Deployment?</h2>
<p>Continuous Deployment, often referred to by its acronym CD, is the practice of maintaining code in a releasable state and deploying that code automatically or in short cycles.</p>
<p>Particularly in our use case, we’re going to configure our project so that any time a new update is pushed or merged to the primary Git branch, our website will deploy.</p>
<h2 id="heading-what-are-we-going-to-build">What are we going to build?</h2>
<p>We’re first going to bootstrap a simple <a target="_blank" href="https://nextjs.org/">Next.js</a> app using the default Next.js starting template and configure it to compile to static files.</p>
<p>If you don’t want to create a Next.js project, you can follow along with even a simple HTML file and not run any of the build commands. But Next.js is a modern way to build dynamic web apps, so we’ll start there.</p>
<p>With our website files ready to go, we’ll create and configure an S3 bucket in AWS where we’ll host our website.</p>
<p>Finally, we’ll create a new GitHub Action workflow that will automatically update the website files in S3 any time a new change occurs on our primary branch (<code>main</code>).</p>
<h2 id="heading-step-0-setting-up-a-new-nextjs-project-on-github">Step 0: Setting up a new Next.js project on GitHub</h2>
<p>We’re going to get started with the default template with Next.js.</p>
<p>After navigating to the directory you want to create your project in, run:</p>
<pre><code>yarn create next-app my-<span class="hljs-keyword">static</span>-website
# or
npx create-next-app my-<span class="hljs-keyword">static</span>-website
</code></pre><p>Note: Feel free to replace <code>my-static-website</code> with the name of your choice. We’ll use that for the rest of this tutorial.</p>
<p>If you navigate to that directory and run the development command, you should be able to successfully start up your development server.</p>
<pre><code>cd my-<span class="hljs-keyword">static</span>-website
yarn dev
# or
npm run dev
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/10/new-nextjs-app.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New Next.js App</em></p>
<p>Next, let’s configure our project to statically compile.</p>
<p>Inside the <code>package.json</code> file, update the <code>build</code> script to:</p>
<pre><code class="lang-json"><span class="hljs-string">"build"</span>: <span class="hljs-string">"next build &amp;&amp; next export"</span>,
</code></pre>
<p>What this will do is tell Next to take the website and export it to static files, which we’ll use to host the site.</p>
<p>We can test this out by running the command:</p>
<pre><code>yarn build
# or
npm run build
</code></pre><p>And once finished, we can look inside of the <code>out</code> directory and see all of the files of our new website.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/nextjs-build-export-output.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Static output from Next.js</em></p>
<p>Finally, we want to host this on GitHub.</p>
<p>Inside of your GitHub account, <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/create-a-repo">create a new repository</a>. This will then provide instructions on how you can <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line">add an existing project</a> to that repo.</p>
<p>And once you push our your project to GitHub, we should be ready to set up our new website project!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/project-on-github.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New repo in GitHub</em></p>
<p>Follow along with the commits:</p>
<ul>
<li><a target="_blank" href="https://github.com/colbyfayock/my-static-website/commit/ca9e4bca3c37fbd8553b0b183890c32836c35296">Adding the initial Next.js project</a> via <a target="_blank" href="https://nextjs.org/docs/api-reference/create-next-app">Create Next App</a></li>
<li><a target="_blank" href="https://github.com/colbyfayock/my-static-website/commit/7907f4a0fac5f0aed2922202c5f0070dfc055f83">Configuring Next.js to export the project</a></li>
</ul>
<h2 id="heading-step-1-manually-creating-and-deploying-a-nextjs-project-to-a-new-s3-bucket">Step 1: Manually creating and deploying a Next.js project to a new S3 Bucket</h2>
<p>To get started with our new S3 Bucket, first log in to your AWS account and navigate to the S3 service.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/aws-s3-console.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>No buckets in S3</em></p>
<p>We’ll want to create a new bucket, using the name of our choice, which will be used for the S3 endpoint where our website is hosted. We’ll also want to configure our S3 bucket to be able to host a website.</p>
<p><em>Note: this tutorial will not walk you through how to host a website on S3, but you can check out my other tutorial that will <a target="_blank" href="https://www.freecodecamp.org/news/how-to-host-and-deploy-a-static-website-or-jamstack-app-to-s3-and-cloudfront/">walk you through hosting a website on S3</a> step-by-step.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/s3-bucket-website-hosting.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Static website hosting in AWS S3</em></p>
<p>Once we have our S3 bucket configure as a website, we can go back to our Next.js project folder, run our build command, and then upload all of our files from the <code>out</code> directory into our new S3 bucket.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/website-files-in-s3.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>S3 Bucket with Static App</em></p>
<p>And once those files are uploaded and we’ve configured our S3 bucket for website hosting, we should now be able to see our project live on the web!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/nextjs-s3-website.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>AWS S3 hosted Next.js app</em></p>
<h2 id="heading-step-2-creating-a-new-github-action-workflow-to-automatically-build-a-nextjs-project">Step 2: Creating a new GitHub Action workflow to automatically build a Next.js project</h2>
<p>To get started, we’re going to need to create a new workflow.</p>
<p>If you’re familiar with GitHub Actions, you could create one manually, but we’ll quickly walk through how to do this in the UI.</p>
<p>Navigate to the Actions tab of your GitHub repository and click on "set up a workflow yourself."</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/github-actions-new-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New GitHub Action Workflow</em></p>
<p>GitHub provides a starting template that we can use for our workflow, though we’ll want to make some changes.</p>
<p>Let’s do the following:</p>
<ul>
<li>Optional: rename the file to deploy.yml</li>
<li>Optional: rename the workflow to CD (as it’s a bit different from CI)</li>
<li>Optional: remove all of the comments to make it a bit easier to read</li>
<li>Remove the <code>pull_request</code> definition in the <code>on</code> property</li>
<li>Remove all <code>steps</code> except for <code>uses: actions/checkout@v2</code></li>
</ul>
<p>So at this point we should be left with:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">CD</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
</code></pre>
<p>This code alone will trigger a process that spins up a new instance of Ubuntu and simply checks out the code from GitHub any time there’s a new change pushed to the <code>main</code> branch.</p>
<p>Next, once we have our code checked out, we want to build it. This will allow us to take that output and sync it to S3.</p>
<p>This step will differ slightly depending on if you are using yarn or npm for your project.</p>
<p>If you’re using yarn, under the <code>steps</code> definition, add the following:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">node-version:</span> <span class="hljs-number">12</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">-g</span> <span class="hljs-string">yarn</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">install</span> <span class="hljs-string">--frozen-lockfile</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>
</code></pre>
<p>If you’re using npm, add the following:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">node-version:</span> <span class="hljs-number">12</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
</code></pre>
<p>Between both of these sets of steps, what we’re doing is:</p>
<ul>
<li>Setting up node: this is so that we can use npm and node to install and run our scripts</li>
<li>Install Yarn (Yarn Only): if we’re using yarn, we install it as a global dependency so that we can use it</li>
<li>Install Dependencies: we install our dependencies and we use a specific command that makes sure we use the lock file available to avoid any unexpected package upgrades</li>
<li>Build: finally, we run our build command which will compile our Next.js project into the <code>out</code> directory!</li>
</ul>
<p>And now we can commit that file right to our <code>main</code> branch which will kick off a new run of our workflow that we can see in our Actions tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/github-action-run-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New workflow in GitHub Actions</em></p>
<p>To see that it works, we can navigate into that run, select our workflow, and see that all of our steps ran including building our project!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/github-action-successful-build.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Successful build logs for a GitHub Action workflow</em></p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-static-website/commit/59e0a5158d6afbf54793d826d05455f5205c98fb">Follow along with the commit!</a></p>
<h2 id="heading-step-3-configuring-a-github-action-to-deploy-a-static-website-to-s3">Step 3: Configuring a GitHub Action to deploy a static website to S3</h2>
<p>Now that we’re building our project automatically, we want to automatically update our website in S3.</p>
<p>To do that, we’re going to use the GitHub Action <a target="_blank" href="https://github.com/aws-actions/configure-aws-credentials">aws-actions/configure-aws-credentials</a> and the AWS CLI.</p>
<p>The GitHub Action that we’re using will take in our AWS credentials and configuration and make it available to use throughout the lifecycle of the workflow.</p>
<p>As of now, the Ubuntu instance that GitHub Actions provides allows us to use the AWS CLI as it comes included. So we’ll be able to use the CLI commands right in our workflow.</p>
<p>Alternatively, we could use the <a target="_blank" href="https://github.com/jakejarvis/s3-sync-action">S3 Sync action</a>. But by using the AWS CLI, we gain more flexibility to customize our setup, we can use it for additional CLI commands, and it’s also generally nice to get familiar with the AWS CLI.</p>
<p>So to get started, let’s add the following snippet as additional steps in our workflow:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">aws-actions/configure-aws-credentials@v1</span>
  <span class="hljs-attr">with:</span>
    <span class="hljs-attr">aws-access-key-id:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_ACCESS_KEY_ID</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">aws-secret-access-key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_SECRET_ACCESS_KEY</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">aws-region:</span> <span class="hljs-string">us-east-1</span>
</code></pre>
<p>What the above will do is use the AWS credentials configuration action to set up our AWS Access Key, Secret Key, and region based on our settings.</p>
<p>The AWS Region can be customized to whatever region you typically use with your AWS account. I’m in the northeast United States, So I’ll keep <code>us-east-1</code>.</p>
<p>The Access Key and Secret Key are credentials that you’ll need to generate with your AWS account. The way our code is set up is that we’ll store those values inside of GitHub Secrets, which will prevent those keys from being leaked. When the action runs, Github changes those values to stars (<code>***</code>) so people can't access those keys.</p>
<p>So to set up those secrets, we first want to generate Access Keys in AWS.</p>
<p>Navigate to the AWS console. Under the user menu, select <strong>My Security Credentials</strong>, and then select <strong>Create access key</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/aws-console-create-access-key.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Creating an Access Key in AWS</em></p>
<p>This will provide you with two values: the <strong>Access key ID</strong> and the <strong>Secret access key</strong>. Save these values, as you won’t be able to access the Secret key ID again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/aws-secret-access-keys.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Finding Secret and Access Key in AWS</em></p>
<p><em>Note: remember to NOT include the Access Key and Secret Key inside of your code. This could lead to someone compromising your AWS credentials.</em></p>
<p>Next, inside of the GitHub repo, navigate to Settings, Secrets, then select New secret.</p>
<p>Here we’ll want to add our AWS keys using the following secrets:</p>
<ul>
<li>AWS_ACCESS_KEY_ID: your AWS Access key ID</li>
<li>AWS_SECRET_ACCESS_KEY: your AWS Secret key</li>
</ul>
<p>And once saved you should have your two new secrets.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/github-secrets-access-keys.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Creating Secrets in GitHub</em></p>
<p>Now that we have our credentials configured, we should be ready to run the command to sync our project to S3.</p>
<p>Inside of the GitHub Action, add the following step:</p>
<pre><code class="lang-yaml"><span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">aws</span> <span class="hljs-string">s3</span> <span class="hljs-string">sync</span> <span class="hljs-string">./out</span> <span class="hljs-string">s3://[bucket-name]</span>
</code></pre>
<p><em>Note: be sure to replace <code>[bucket-name]</code> with the name of your S3 Bucket.</em></p>
<p>This command will trigger a sync with our specified S3 bucket, using the contents of the <code>out</code> directory, which is where our project builds to.</p>
<p>And now, if we commit our changes, we can see that our action is automatically triggered once committed to the <code>main</code> branch, where we build our project and sync it to S3!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/github-action-sync-s3-bucket.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Successful AWS S3 sync in GitHub Action workflow</em></p>
<p><em>Note: Make sure that before setting up this action you’ve configured the S3 bucket to host a website (including unblocking permissions on S3 bucket) – otherwise this action may fail.</em></p>
<p>At this point, our project probably looks the same, as we didn’t make any changes to the code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/nextjs-s3-website.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Next.js app on AWS S3</em></p>
<p>But if you make a code change, such as changing the title of the homepage inside of <code>pages/index.js</code> and commit that change:</p>
<pre><code class="lang-jsx">&lt;h1 className={styles.title}&gt;
  Colby<span class="hljs-string">'s &lt;a href="https://nextjs.org"&gt;Next.js!&lt;/a&gt; Site
&lt;/h1&gt;</span>
</code></pre>
<p>We can see that our change triggers the workflow to kick off:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/github-action-commit-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New GitHub Action workflow from code change</em></p>
<p>And once our workflow finishes, we can see that our content is now automatically updated on our website:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/updated-nextjs-site-title.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>AWS S3 hosted app with updated code changes</em></p>
<p>Follow along with the commits:</p>
<ul>
<li><a target="_blank" href="https://github.com/colbyfayock/my-static-website/commit/f891412b827aca4b06e9bf3de8e4e5b4c5704fc8">Adding AWS configuration and S3 sync command</a></li>
<li><a target="_blank" href="https://github.com/colbyfayock/my-static-website/commit/bb9b981416645e35c6d3442e02d6b61f2ba032d2">Title update to test workflow</a></li>
</ul>
<h2 id="heading-what-else-can-we-do">What else can we do?</h2>
<h3 id="heading-setting-up-cloudfront">Setting up CloudFront</h3>
<p>The goal of this post wasn’t to go through the entire process of configuring a website for AWS, but if you’re serving a website on S3,  you might want to also include CloudFront in front of it.</p>
<p>You can check out <a target="_blank" href="https://www.freecodecamp.org/news/how-to-host-and-deploy-a-static-website-or-jamstack-app-to-s3-and-cloudfront/">my other guide</a> here which walks you through setting up CloudFront as well as a step-by-step guide through creating the site in S3.</p>
<h3 id="heading-invaliding-cloudfront-cache">Invaliding CloudFront cache</h3>
<p>If your S3 website is behind CloudFront, chances are, you’ll want to make sure CloudFront isn’t caching the new changes.</p>
<p>With the AWS CLI, we can also trigger a cache invalidation with CloudFront to make sure it’s grabbing the latest changes.</p>
<p><a target="_blank" href="https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-invalidation.html">Check out the docs here</a> to learn more.</p>
<h3 id="heading-pull-request-deployments">Pull request deployments</h3>
<p>If you’re constantly working on website changes in a pull request, sometimes it can be easier to see the changes live.</p>
<p>You can set up a new workflow that only runs on pull requests, where the workflow can dynamically create a new bucket based on the branch or environment and add a comment to the pull request with that URL.</p>
<p>You might be able to find a GitHub Action that exists to manage the comments on the pull request for you or you can check out the <a target="_blank" href="https://docs.github.com/en/free-pro-team@latest/rest/reference/actions">GitHub Actions docs</a>.</p>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">🐦 Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">🎥 Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
    <li>
      <a href="https://github.com/sponsors/colbyfayock">💝 Sponsor Me</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are Github Actions and How Can You Automate Tests and Slack Notifications? ]]>
                </title>
                <description>
                    <![CDATA[ Automation is a powerful tool. It both saves us time and can help reduce human error.  But automation can be tough and can sometimes prove to be costly. How can Github Actions help harden our code and give us more time to work on features instead of ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-github-actions-and-how-can-you-automate-tests-and-slack-notifications/</link>
                <guid isPermaLink="false">66b8e39047c23b7ae1ad0bdf</guid>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ automation testing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CI/CD ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous delivery ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub Actions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ slack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Wed, 03 Jun 2020 14:45:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/05/github-actions.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Automation is a powerful tool. It both saves us time and can help reduce human error. </p>
<p>But automation can be tough and can sometimes prove to be costly. How can Github Actions help harden our code and give us more time to work on features instead of bugs?</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-github-actions">What are Github Actions?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-cicd">What is CI/CD?</a></li>
<li><a class="post-section-overview" href="#heading-what-are-we-going-to-build">What are we going to build?</a></li>
<li><a class="post-section-overview" href="#heading-part-0-setting-up-a-project">Part 0: Setting up a project</a></li>
<li><a class="post-section-overview" href="#heading-part-1-automating-tests">Part 1: Automating tests</a></li>
<li><a class="post-section-overview" href="#heading-part-2-post-new-pull-requests-to-slack">Part 2: Post new pull requests to Slack</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/1n-jHHNSoTw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-are-github-actions">What are Github Actions?</h2>
<p><a target="_blank" href="https://github.com/features/actions">Actions</a> are a relatively new feature to <a target="_blank" href="https://github.com/">Github</a> that allow you to set up CI/CD workflows using a configuration file right in your Github repo.</p>
<p>Previously, if you wanted to set up any kind of automation with tests, builds, or deployments, you would have to look to services like <a target="_blank" href="https://circleci.com/">Circle CI</a> and <a target="_blank" href="https://travis-ci.org/">Travis</a> or write your own scripts. But with Actions, you have first class support to powerful tooling to automate your workflow.</p>
<h2 id="heading-what-is-cicd">What is CI/CD?</h2>
<p>CD/CD stands for Continuous Integration and Continuous Deployment (or can be Continuous Delivery). They're both practices in software development that allow teams to build projects together quickly, efficiently, and ideally with less errors.</p>
<p>Continuous Integration is the idea that as different members of the team work on code on different git branches, the code is merged to a single working branch which is then built and tested with automated workflows. This helps to constantly make sure everyone's code is working properly together and is well-tested.</p>
<p>Continuous Deployment takes this a step further and takes this automation to the deployment level. Where with the CI process, you automate the testing and the building, Continuous Deployment will automate deploying the project to an environment. </p>
<p>The idea is that the code, once through any building and testing processes, is in a deployable state, so it should be able to be deployed.</p>
<h2 id="heading-what-are-we-going-to-build">What are we going to build?</h2>
<p>We're going to tackle two different workflows.</p>
<p>The first will be to simply run some automated tests that will prevent a pull request from being merged if it is failing. We won't walk through building the tests, but we'll walk through running tests that already exist.</p>
<p>In the second part, we'll set up a workflow that sends a message to slack with a link to a pull request whenever a new one is created. This can be super helpful when working on open source projects with a team and you need a way to keep track of requests.</p>
<h2 id="heading-part-0-setting-up-a-project">Part 0: Setting up a project</h2>
<p>For this guide, you can really work through any node-based project as long as it has tests you can run for Part 1.</p>
<p>If you'd like to follow along with a simpler example that I'll be using, I've set up a new project that you can clone with a single function that has two tests that are able to run and pass.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/function-with-test.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>A function with two tests</em></p>
<p>If you'd like to check out this code to get started, you can run:</p>
<pre><code class="lang-shell">git clone --single-branch --branch start git@github.com:colbyfayock/my-github-actions.git
</code></pre>
<p>Once you have that cloned locally and have installed the dependencies, you should be able to run the tests and see them pass!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/passing-tests.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Passing tests</em></p>
<p>It should also be noted that you'll be required to have this project added as a new repository on Github in order to follow along.</p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-github-actions/commit/6919b1b9beea4823fd28375f1864d233e23f2d26">Follow along with the commit!</a></p>
<h2 id="heading-part-1-automating-tests">Part 1: Automating tests</h2>
<p>Tests are an important part of any project that allow us to make sure we're not breaking existing code while we work. While they're important, they're also easy to forget about.</p>
<p>We can remove the human nature out of the equation and automate running our tests to make sure we can't proceed without fixing what we broke.</p>
<h3 id="heading-step-1-creating-a-new-action">Step 1: Creating a new action</h3>
<p>The good news, is Github actually makes it really easy to get this workflow started as it comes as one of their pre-baked options.</p>
<p>We'll start by navigating to the <strong>Actions</strong> tab on our repository page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-actions-dashboard.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Github Actions starting page</em></p>
<p>Once there, we'll immediately see some starter workflows that Github provides for us to dive in with. Since we're using a node project, we can go ahead and click <strong>Set up this workflow</strong> under the <strong>Node.js</strong> workflow.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-action-new-nodejs-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up a Node.js Github Action workflow</em></p>
<p>After the page loads, Github will land you on a new file editor that already has a bunch of configuration options added.</p>
<p>We're actually going to leave this "as is" for our first step. Optionally, you can change the name of the file to <code>tests.yml</code> or something you'll remember.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-action-create-new-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding a new Github Action workflow file</em></p>
<p>You can go ahead and click <strong>Start commit</strong> then either commit it directory to the <code>master</code> branch or add the change to a new branch. For this walkthrough, I'll be committing straight to <code>master</code>.</p>
<p>To see our new action run, we can again click on the <strong>Actions</strong> tab which will navigate us back to our new Actions dashboard.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-action-workflow-status.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Viewing Github Action workflow events</em></p>
<p>From there, you can click on <strong>Node.js CI</strong> and select the commit that you just made above and you'll land on our new action dashboard. You can then click one of the node versions in the sidebar via <strong>build (#.x)</strong>, click the <strong>Run npm test</strong> dropdown, and we'll be able to see the output of our tests being run (which if you're following along with me, should pass!).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-action-workflow-logs.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Viewing logs of a Github Action workflow</em></p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-github-actions/commit/10e397966572ed9975cac40f6ab5f41c1255a947">Follow along with the commit!</a></p>
<h3 id="heading-step-2-configuring-our-new-action">Step 2: Configuring our new action</h3>
<p>So what did we just do above? We'll walk through the configuration file and what we can customize.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-action-workflow-file.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Github Action Node.js workflow file</em></p>
<p>Starting from the top, we specify our name:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">CI</span>
</code></pre>
<p>This can really be whatever you want. Whatever you pick should help you remember what it is. I'm going to customize this to "Tests" so I know exactly what's going on.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">master</span> ]
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">master</span> ]
</code></pre>
<p>The <code>on</code> key is how we specify what events trigger our action. This can be a variety of things like based on time with <a target="_blank" href="https://en.wikipedia.org/wiki/Cron">cron</a>. But here, we're saying that we want this action to run any time someone pushes commits to  <code>master</code> or someone creates a pull request targeting the <code>master</code> branch. We're not going to make a change here.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
</code></pre>
<p>This next bit creates a new job called <code>build</code>. Here we're saying that we want to use the latest version of Ubuntu to run our tests on. <a target="_blank" href="https://ubuntu.com/">Ubuntu</a> is common, so you'll only want to customize this if you want to run it on a specific environment.</p>
<pre><code class="lang-yaml">    <span class="hljs-attr">strategy:</span>
      <span class="hljs-attr">matrix:</span>
        <span class="hljs-attr">node-version:</span> [<span class="hljs-number">10.</span><span class="hljs-string">x</span>, <span class="hljs-number">12.</span><span class="hljs-string">x</span>, <span class="hljs-number">14.</span><span class="hljs-string">x</span>]
</code></pre>
<p>Inside of our job we specify a <a target="_blank" href="https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategy">strategy</a> matrix. This allows us to run the same tests on a few different variations. </p>
<p>In this instance, we're running the tests on 3 different versions of <a target="_blank" href="https://nodejs.org/en/">node</a> to make sure it works on all of them. This is definitely helpful to make sure your code is flexible and future proof, but if you're building and running your code on a specific node version, you're safe to change this to only that version.</p>
<pre><code class="lang-yaml">    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Use</span> <span class="hljs-string">Node.js</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">node-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">matrix.node-version</span> <span class="hljs-string">}}</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">ci</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span> <span class="hljs-string">--if-present</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">test</span>
</code></pre>
<p>Finally, we specify the steps we want our job to run. Breaking this down:</p>
<ul>
<li><code>uses: actions/checkout@v2</code>: In order for us to run our code, we need to have it available. This checks out our code on our job environment so we can use it to run tests.</li>
<li><code>uses: actions/setup-node@v1</code>: Since we're using node with our project, we'll need it set up on our environment. We're using this action to do that setup  for us for each version we've specified in the matrix we configured above.</li>
<li><code>run: npm ci</code>: If you're not familiar with <code>npm ci</code>, it's similar to running <code>npm install</code> but uses the <code>package-lock.json</code> file without performing any patch upgrades. So essentially, this installs our dependencies.</li>
<li><code>run: npm run build --if-present</code>: <code>npm run build</code> runs the build script in our project. The <code>--if-present</code> flag performs what it sounds like and only runs this command if the build script is present. It doesn't hurt anything to leave this in as it won't run without the script, but feel free to remove this as we're not building the project here.</li>
<li><code>run: npm test</code>: Finally, we run <code>npm test</code> to run our tests. This uses the <code>test</code> npm script set up in our <code>package.json</code> file.</li>
</ul>
<p>And with that, we've made a few tweaks, but our tests should run after we've committed those changes and pass like before!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-action-workflow-logs-npm-test.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Logs of passing tests in Github Action workflow</em></p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-github-actions/commit/087cd8e8592d1f2b520b6e44b70b0a242a9d2d72">Follow along with the commit!</a></p>
<h3 id="heading-step-3-testing-that-our-tests-fail-and-prevent-merges">Step 3: Testing that our tests fail and prevent merges</h3>
<p>Now that our tests are set up to automatically run, let's try to break it to see it work.</p>
<p>At this point, you can really do whatever you want to intentionally break the tests, but <a target="_blank" href="https://github.com/colbyfayock/my-github-actions/pull/1">here's what I did</a>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/bad-changes-code-diff.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Code diff - https://github.com/colbyfayock/my-github-actions/pull/1</em></p>
<p>I'm intentionally returning different expected output so that my tests will fail. And they do!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-failing-checks.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Failing status checks on pull request</em></p>
<p>In my new pull request, my new branch breaks the tests, so it tells me my checks have failed. If you noticed though, it's still green to merge, so how can we prevent merges?</p>
<p>We can prevent pull requests from being merged by setting up a Protected Branch in our project settings.</p>
<p>First, navigate to <strong>Settings</strong>, then <strong>Branches</strong>, and click <strong>Add rule</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-add-protected-branch.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Github branch protection rules</em></p>
<p>We'll then want to set the branch name pattern to <code>*</code>, which means all branches, check the <strong>Require status checks to pass before merging option</strong>, then select all of our different status checks that we'd like to require to pass before merging.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-configure-protected-branch.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up a branch protection rule in Github</em></p>
<p>Finally, hit <strong>Create</strong> at the bottom of the page.</p>
<p>And once you navigate back to the pull request, you'll notice that the messaging is a bit different and states that we need our statuses to pass before we can merge.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-failing-checks-cant-merge.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Failing tests preventing merge in pull request</em></p>
<p><em>Note: as an administrator of a repository, you'll still be able to merge, so this technically only prevents non-administrators from merging. But will give you increased messaging if the tests fail.</em></p>
<p>And with that, we have a new Github Action that runs our tests and prevents pull requests from merging if they fail.</p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-github-actions/pull/1">Follow along with the pull request!</a></p>
<p><em>Note: we won't be merging that pull request before continuing to Part 2.</em></p>
<h2 id="heading-part-2-post-new-pull-requests-to-slack">Part 2: Post new pull requests to Slack</h2>
<p>Now that we're preventing merge requests if they're failing, we want to post a message to our <a target="_blank" href="http://slack.com/">Slack</a> workspace whenever a new pull request is opened up. This will help us keep tabs on our repos right in Slack.</p>
<p>For this part of the guide, you'll need a Slack workspace that you have permissions to create a new developer app with and the ability to create a new channel for the bot user that will be associated with that app.</p>
<h3 id="heading-step-1-setting-up-slack">Step 1: Setting up Slack</h3>
<p>There are a few things we're going to walk through as we set up Slack for our workflow:</p>
<ul>
<li>Create a new app for our workspace</li>
<li>Assign our bot permissions</li>
<li>Install our bot to our workspace</li>
<li>Invite our new bot to our channel</li>
</ul>
<p>To get started, we'll create a new app. Head over to the <a target="_blank" href="https://api.slack.com/apps">Slack API Apps dashboard</a>. If you already haven't, log in to your Slack account with the Workspace you'd like to set this up with.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-create-new-app.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a new Slack app</em></p>
<p>Now, click <strong>Create New App</strong> where you'll be prompted to put in a name and select a workspace you want this app to be created for. I'm going to call my app "Gitbot" as the name, but you can choose whatever makes sense for you. Then click <strong>Create App</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-add-name-new-app.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring a new Slack app</em></p>
<p>Once created, navigate to the <strong>App Home</strong> link in the left sidebar. In order to use our bot, we need to assign it <a target="_blank" href="https://oauth.net/">OAuth</a> scopes so it has permissions to work in our channel, so select <strong>Review Scopes to Add</strong> on that page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-app-review-scopes.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Reviewing Slack app scopes</em></p>
<p>Scroll own and you'll see a <strong>Scopes</strong> section and under that a <strong>Bot Token</strong> section. Here, click <strong>Add an OAuth Scope</strong>. For our bot, we don't need a ton of permissions, so add the <code>channels:join</code> and <code>chat:write</code> scopes and we should be good to go.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-app-add-scopes.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding scopes for a Slack app Bot Token</em></p>
<p>Now that we have our scopes, let's add our bot to our workspace. Scroll up on that same page to the top and you'll see a button that says <strong>Install App to Workspace</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-install-app-to-workspace.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Installing Slack app to a workspace</em></p>
<p>Once you click this, you'll be redirected to an authorization page. Here, you can see the scopes we selected for our bot. Next, click <strong>Allow</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-app-allow-workspace-permissions.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Allowing permission for Slack app to be installed to workspace</em></p>
<p>At this point, our Slack bot is ready to go. At the top of the <strong>OAuth &amp; Permissions</strong> page, you'll see a <strong>Bot User OAuth Access Token</strong>. This is what we'll use when setting up our workflow, so either copy and save this token or remember this location so you know how to find it later.</p>
<p><em>Note: this token is private - don't give this out, show it in a screencast, or let anyone see it!</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-app-oauth-token.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Copying OAuth Access Token for Slack bot user</em></p>
<p>Finally, we need to invite our Slack bot to our channel. If you open up your workspace, you can either use an existing channel or create a new channel for these notifications, but you'll want to enter the command <code>/invite @[botname]</code> which will invite our bot to our channel.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-invite-bot-to-channel.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Inviting Slack bot user to channel</em></p>
<p>And once added, we're done with setting up Slack!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-app-bot-joined-channel.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Slack bot was added to channel</em></p>
<h3 id="heading-create-a-github-action-to-notify-slack">Create a Github Action to notify Slack</h3>
<p>Our next step will be somewhat similar to when we created our first Github Action. We'll create a workflow file which we'll configure to send our notifications.</p>
<p>While we can use our code editors to do this by creating a file in the <code>.github</code> directory, I'm going to use the Github UI.</p>
<p>First, let's navigate back to our <em>Actions</em> tab in our repository. Once there, select <strong>New workflow</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-new-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up a new Github Action workflow</em></p>
<p>This time, we're going to start the workflow manually instead of using a pre-made Action. Select <strong>set up a workflow yourself</strong> at the top.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-set-up-new-workflow.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up a Github Action workflow manually</em></p>
<p>Once the new page loads, you'll be dropped in to a new template where we can start working. Here's what our new workflow will look like:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Slack</span> <span class="hljs-string">Notifications</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">master</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">notifySlack:</span>

    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Notify</span> <span class="hljs-string">slack</span>
      <span class="hljs-attr">env:</span>
        <span class="hljs-attr">SLACK_BOT_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.SLACK_BOT_TOKEN</span> <span class="hljs-string">}}</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">abinoda/slack-action@master</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">args:</span> <span class="hljs-string">'{\"channel\":\"[Channel ID]\",\"blocks\":[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"*Pull Request:* $<span class="hljs-template-variable">{{ github.event.pull_request.title }}</span>\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"*Who?:* $<span class="hljs-template-variable">{{ github.event.pull_request.user.login }}</span>\n*Request State:* $<span class="hljs-template-variable">{{ github.event.pull_request.state }}</span>\"}},{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"&lt;$<span class="hljs-template-variable">{{ github.event.pull_request.html_url }}</span>|View Pull Request&gt;\"}}]}'</span>
</code></pre>
<p>So what's happening in the above?</p>
<ul>
<li><code>name</code>: we're setting a friendly name for our workflow</li>
<li><code>on</code>: we want our workflow to trigger when there's a pull request is created that targets our <code>master</code> branch</li>
<li><code>jobs</code>: we're creating a new job called <code>notifySlack</code></li>
<li><code>jobs.notifySlack.runs-on</code>: we want our job to run on a basic setup of the latest Unbuntu</li>
<li><code>jobs.notifySlack.steps</code>: we really only have one step here - we're using a pre-existing Github Action called <a target="_blank" href="https://github.com/marketplace/actions/post-slack-message">Slack Action</a> and we're configuring it to publish a notification to our Slack</li>
</ul>
<p>There are two points here we'll need to pay attention to, the <code>env.SLACK_BOT_TOKEN</code> and the <code>with.args</code>.</p>
<p>In order for Github to communicate with Slack, we'll need a token. This is what we're setting in <code>env.SLACK_BOT_TOKEN</code>. We generated this token in the first step. Now that we'll be using this in our workflow configuration, we'll need to <a target="_blank" href="https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository">add it as a Git Secret in our project</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-slack-token-secret.jpg" alt="Image" width="600" height="400" loading="lazy">
_Github secrets including SLACK_BOT<em>TOKEN</em></p>
<p>The  <code>with.args</code> property is what we use to configure the payload to the Slack API that includes the channel ID (<code>channel</code>) and our actual message (<code>blocks</code>).</p>
<p>The payload in the arguments is stringified and escaped. For example, when expanded it looks like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"channel"</span>: <span class="hljs-string">"[Channel ID]"</span>,
  <span class="hljs-attr">"blocks"</span>: [{
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"section"</span>,
    <span class="hljs-attr">"text"</span>: {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"mrkdwn"</span>,
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"*Pull Request:* ${{ github.event.pull_request.title }}"</span>
    }
  }, {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"section"</span>,
    <span class="hljs-attr">"text"</span>: {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"mrkdwn"</span>,
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"*Who?:*n${{ github.event.pull_request.user.login }}n*State:*n${{ github.event.pull_request.state }}"</span>
    }
  }, {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"section"</span>,
    <span class="hljs-attr">"text"</span>: {
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"mrkdwn"</span>,
      <span class="hljs-attr">"text"</span>: <span class="hljs-string">"&lt;${{ github.event.pull_request._links.html.href }}|View Pull Request&gt;"</span>
    }
  }]
}
</code></pre>
<p><em>Note: this is just to show what the content looks like, we need to use the original file with the stringified and escaped argument.</em></p>
<p>Back to our configuration file, the first thing we set is our channel ID. To find our channel ID, you'll need to use the Slack web interface. Once you open Slack in your browser, you want to find your channel ID in the URL:</p>
<pre><code>https:<span class="hljs-comment">//app.slack.com/client/[workspace ID]/[channel ID]</span>
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-web-channel-id.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Channel ID in Slack web app URL</em></p>
<p>With that channel ID, you can modify our workflow configuration and replace <code>[Channel ID]</code> with that ID:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">with:</span>
  <span class="hljs-attr">args:</span> <span class="hljs-string">'{\"channel\":\"C014RMKG6H2\",...</span>
</code></pre>
<p>The rest of the arguments property is how we set up our message. It includes variables from the Github event that we use to customize our message. </p>
<p>We won't go into tweaking that here, as what we already have will send a basic pull request message, but you can test out and build your own payload with Slack's <a target="_blank" href="https://app.slack.com/block-kit-builder/">Block Kit Builder</a>.</p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-github-actions/commit/e228b9899ef3da218d1a100d06a72259d45ea19e">Follow along with the commit!</a></p>
<h3 id="heading-test-out-our-slack-workflow">Test out our Slack workflow</h3>
<p>So now we have our workflow configured with our Slack app, finally we're ready to use our bot!</p>
<p>For this part, all we need to do is create a new pull request with any change we want. To test this out, I simply <a target="_blank" href="https://github.com/colbyfayock/my-github-actions/pull/2">created a new branch</a> where I added a sentence to the <code>README.md</code> file.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/github-test-pull-request.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Code diff - <a target="_blank" href="https://github.com/colbyfayock/my-github-actions/pull/2">https://github.com/colbyfayock/my-github-actions/pull/2</a></em></p>
<p>Once you <a target="_blank" href="https://github.com/colbyfayock/my-github-actions/pull/2">create that pull request</a>, similar to our tests workflow, Github will run our Slack workflow! You can see this running in the Actions tab just like before.</p>
<p>As long as you set everything up correctly, once the workflow runs, you should now have a new message in Slack from your new bot.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/slack-github-notification.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Slack bot automated message about new pull request</em></p>
<p><em>Note: we won't be merging that pull request in.</em></p>
<h2 id="heading-what-else-can-we-do">What else can we do?</h2>
<h3 id="heading-customize-your-slack-notifications">Customize your Slack notifications</h3>
<p>The message I put together is simple. It tells us who created the pull request and gives us a link to it.</p>
<p>To customize the formatting and messaging, you can use the Github <a target="_blank" href="https://app.slack.com/block-kit-builder/">Block Kit Builder</a> to create your own.</p>
<p>If you'd like to include additional details like the variables I used for the pull request, you can make use of Github's available <a target="_blank" href="https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#contexts">contexts</a>. This lets you pull information about the environment and the job to customize your message.</p>
<p>I couldn't seem to find any sample payloads, so here's an example of a sample <code>github</code> context payload you would expect in the event.</p>
<p><a target="_blank" href="https://gist.github.com/colbyfayock/1710edb9f47ceda0569844f791403e7e">Sample github context</a></p>
<h3 id="heading-more-github-actions">More Github actions</h3>
<p>With our ability to create new custom workflows, that's not a lot we can't automate. Github even has a <a target="_blank" href="https://github.com/marketplace?type=actions">marketplace</a> where you can browse around for one.</p>
<p>If you're feeling like taking it a step further, you can even create your own! This lets you set up scripts to configure a workflow to perform whatever tasks you need for your project.</p>
<h2 id="heading-join-in-the-conversation">Join in the conversation!</h2>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/colbyfayock/status/1268197100539514881"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h2 id="heading-what-do-you-use-github-actions-for">What do you use Github actions for?</h2>
<p>Share with me on <a target="_blank" href="https://twitter.com/colbyfayock">Twitter</a>!</p>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">? Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">?️ Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What Are Environment Variables and How Can I Use Them with Gatsby and Netlify? ]]>
                </title>
                <description>
                    <![CDATA[ When starting to integrate 3rd party services into your application or website, you'll start to find it useful to have different environments, such as a development and production environment.  How can we configure this so we don't have to directly e... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-environment-variables-and-how-can-i-use-them-with-gatsby-and-netlify/</link>
                <guid isPermaLink="false">66b8e38ec9bc6d235bb126b2</guid>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Gatsby ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GatsbyJS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Tue, 28 Apr 2020 14:45:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/04/environment-variables.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When starting to integrate 3rd party services into your application or website, you'll start to find it useful to have different environments, such as a development and production environment. </p>
<p>How can we configure this so we don't have to directly edit our code to change our environment?</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-environment-variables">What are environment variables?</a></li>
<li><a class="post-section-overview" href="#heading-how-can-environment-variables-be-useful">How can environment variables be useful?</a></li>
<li><a class="post-section-overview" href="#heading-how-can-i-keep-these-files-secure">How can I keep these files secure?</a></li>
<li><a class="post-section-overview" href="#heading-gatsby-and-environment-variables">Gatsby and environment variables</a></li>
<li><a class="post-section-overview" href="#heading-netlify-and-environment-variables">Netlify and environment variables</a></li>
<li><a class="post-section-overview" href="#heading-step-1-creating-a-hello-world-website">Step 1: Creating a "Hello, world" website</a></li>
<li><a class="post-section-overview" href="#heading-step-2-creating-a-local-environment-variable-with-gatsby">Step 2: Creating a local environment variable with Gatsby</a></li>
<li><a class="post-section-overview" href="#heading-step-3-deploying-the-website-to-netlify">Step 3: Deploying the website to Netlify</a></li>
<li><a class="post-section-overview" href="#heading-where-can-you-add-or-update-more-variables-in-netlify">Where can you add or update more variables in Netlify?</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/oq_RPOI0xsU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-are-environment-variables">What are environment variables?</h2>
<p>Environment variables are predetermined values that are typically used to provide the ability to configure a value in your code from outside of your application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/environment-variable-secret.jpg" alt="Image" width="600" height="400" loading="lazy">
_MY_SECRET<em>KEY environment variable used for authorization</em></p>
<p>When developing locally, or sometimes even in a deployment pipeline, you'll oftentimes find these variables stored in a file named with some kind of variation of  <code>.env</code>.</p>
<h2 id="heading-how-can-environment-variables-be-useful">How can environment variables be useful?</h2>
<p>Probably the most common use case for environment variables is being able to set up different configuration options for different environments. Often when developing against third party services, you want to have a development version or sandbox available to make test requests against, that way it doesn't impact real production data.</p>
<p>Environment variables are helpful because they allow you to change which of your environments use which third party service environment by changing an API key, endpoint, or whatever the service uses to distinguish between environments.</p>
<p>The code you deploy should be predictable, so by not having to change any code, just the configuration outside of the code, you can maintain that predictability.</p>
<h2 id="heading-how-can-i-keep-these-files-secure">How can I keep these files secure?</h2>
<p>This is probably one of the more important points here – you need to ensure you're handling these files with care and not checking them into a git repository. By exposing these keys by inadvertently uploading them to a public location, the internet could easily find these keys and abuse them for their own gains.</p>
<p>For instance, <a target="_blank" href="https://aws.amazon.com/">AWS</a> keys are a valuable source. People run bots with the sole purpose of trying to scan Github for keys. If someone finds an AWS key, they could use this key to access resources such as running a bitcoin operation at your expense. This isn't to scare you, its to make you aware so you avoid your keys getting compromised.</p>
<p>So how can we keep these secure? The easiest way is to add the environment file where you keep these keys to your <code>.gitignore</code> file.</p>
<p>To do this, simply open your existing <code>.gitignore</code> file or create a new one at the root of your repository and add the filename as a new line:</p>
<pre><code># Inside .gitignore
.env
</code></pre><p>If you want to get more advanced and make sure this never happens to a repository, you can check out some tools like <a target="_blank" href="https://github.com/awslabs/git-secrets">git-secrets</a> from AWS Labs or <a target="_blank" href="https://github.com/zricethezav/gitleaks">GitLeaks</a> that even has a <a target="_blank" href="https://github.com/marketplace/actions/gitleaks">Github Action</a> to make it easy to integrate with Github.</p>
<h2 id="heading-gatsby-and-environment-variables">Gatsby and environment variables</h2>
<p><a target="_blank" href="https://www.gatsbyjs.org/">Gatsby</a> by default makes two files available as part of its <a target="_blank" href="https://www.gatsbyjs.org/docs/environment-variables/">environment variable workflow</a> that makes these values available in the client: <code>.env.development</code> and <code>.env.production</code>. These correlate to the <code>gatsby develop</code> and <code>gatsby build</code> scripts to either develop or build your site.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/environment-variable-secret-gatsby.jpg" alt="Image" width="600" height="400" loading="lazy">
_MY_SECRET<em>KEY environment variable for development and production</em></p>
<p>To make use of these files within the Gatsby development and build process, Gatsby requires you to prefix these variables with <code>GATSBY_</code>. This also works if you'd like to have them available from an OS process level.</p>
<p>Though you could integrate <a target="_blank" href="https://github.com/motdotla/dotenv">dotenv</a> if you have more advanced needs or don't want to use the <code>GATSBY_</code> prefix, your path of least resistance is probably to just follow the Gatsby way when working in Gatsby.</p>
<h2 id="heading-netlify-and-environment-variables">Netlify and environment variables</h2>
<p><a target="_blank" href="https://www.netlify.com/">Netlify</a> provides the ability to add environment variables as part of its <strong>Build &amp; deploy</strong> settings which gets picked up as part of the build processes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/netlify-environment-variable.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding an environment variable in Netlify</em></p>
<p>Luckily, Netlify makes it easy to add whatever environment variable you'd like to the build process! To add one, you can simply navigate to the <strong>Environment</strong> section of your project's <strong>Build &amp; deploy</strong> settings page and add a variable under <strong>Environment variables.</strong></p>
<p>We'll walk you through this process a little later.</p>
<h2 id="heading-step-1-creating-a-hello-world-website">Step 1: Creating a "Hello, world" website</h2>
<p>For our walkthrough, we're going to set up a really basic example of a Gatsby website just for the purposes of testing this out.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/new-website-gatsby-starter-leaflet.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New website with Gatsby Sass Starter</em></p>
<p>Though this isn't really a common use case of environment variables, where normally you would use them for things like API keys and service configurations, this will give you a great idea of how it fundamentally works.</p>
<p>We're going to use this <a target="_blank" href="https://github.com/colbyfayock/gatsby-starter-sass">Gatsby Sass Starter</a> I created which will give us a starting point and add "Hello, [Environment]" depending on where it's running.</p>
<p>To get started, let's create our local project by using the <a target="_blank" href="https://www.gatsbyjs.org/docs/gatsby-cli/">Gatsby CLI</a>. Navigate to where you'd like to store this project and run:</p>
<pre><code class="lang-shell">gatsby new my-env-project https://github.com/colbyfayock/gatsby-starter-sass
</code></pre>
<p>You can change <code>my-env-project</code> to whatever directory you'd like this project created in, but once you run this command, you'll now have a project in that new directory.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/new-gatsby-project-command-line.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New Gatsby project in the terminal</em></p>
<p>To get started, once inside that directory, run <code>yarn develop</code> to make changes locally or <code>yarn build</code> to compile your new site.</p>
<p>Once you're ready to go, you'll want to add this project to Github. If you're not familiar with how to do this, you can l<a target="_blank" href="https://help.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line">earn how to add an existing project to Github</a> here.</p>
<h2 id="heading-step-2-creating-a-local-environment-variable-with-gatsby">Step 2: Creating a local environment variable with Gatsby</h2>
<p>Our next step is to create a local environment and add a change that will let us see that it works.</p>
<p>To get started, let's first create a new file at the root of our project called <code>.env.development</code>. It might ask you if you really want to use the <code>.</code> prefix, make sure you say yes!</p>
<p>Inside that file, let's add:</p>
<pre><code># Inside .env.development
GATSBY_MY_ENVIRONMENT=<span class="hljs-string">"Development"</span>
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2020/04/gatsby-development-environment-file.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Creating an .env.development file</em></p>
<p>Next, to make sure we don't forget to do this, let's also add this <code>.env.development</code> file to our <code>.gitignore</code> so we don't accidentally commit this to our git history. If you don't already have a <code>.gitignore</code> file, make sure you create it at the root of your project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/adding-development-environment-file-gitignore.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding .env.development to your .gitignore</em></p>
<p>Finally, to check that this works, let's open <code>pages/index.js</code> and let's replace our <code>&lt;h1&gt;</code> tag's content with a "Hello, world!" variation:</p>
<pre><code class="lang-jsx">&lt;h1&gt;Hello, {process.env.GATSBY_MY_ENVIRONMENT}&lt;/h1&gt;
</code></pre>
<p>And if we save that change and open it in our browser, we should see "Hello, Development"!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/using-environment-variable-gatsby.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Using an environment variable for your Gatsby site</em></p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-env-project/commit/e3e7000fbfab4cecac7739458034e70958e52211">Follow along with the commit!</a></p>
<h2 id="heading-step-3-deploying-the-website-to-netlify">Step 3: Deploying the website to Netlify</h2>
<p>So we have our website created using a simple environment variable. Next we'll want to actually deploy that site to Netlify. If you haven't already, we'll need to <a target="_blank" href="https://help.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line">add our website to Github</a> or another Git provider. Make sure to have that set up before continuing on.</p>
<p>After creating an account and logging in to Netlify, let's click the <strong>New site from Git</strong> button the main dashboard, follow the instructions for connecting your Github or other Git provider to Netlify, and then find your new repository.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/adding-new-github-repository-netlify.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding a new Github repository to Netlify</em></p>
<p>Once you select your repository, you'll be asked to configure your build process. Luckily, Netlify can detect that we're using a Gatsby site and has it pre-filled for us. Unless you've added something special, keep the basic configuration to use <code>gatsby build</code> to build your project and <code>public/</code> for the output.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/configuring-netlify-build.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring Netlify build settings</em></p>
<p>Now before we hit <strong>Deploy</strong>, there's one thing we want to add, and that's our environment variable!</p>
<p>Right above the <strong>Deploy site</strong> button there's an <strong>Advanced</strong> button. Click that and you'll see a new dropdown with an additional <strong>New variable</strong> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/configuring-environment-variable-netlify.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring an environment variable in the Netlify setup</em></p>
<p>Click that <strong>New variable</strong> button, add our <code>GATSBY_MY_ENVIRONMENT</code> as a new variable and add <code>Production</code> as the value. And finally, hit <strong>Deploy site</strong>!</p>
<p>From here, you should be able to watch your website deploy and once finished, you'll see your new site with "Hello, Production"!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/deployed-gatsby-site-with-environment-variable.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Deployed Gatsby site using Netlify environment variable</em></p>
<h2 id="heading-where-can-you-add-or-update-more-variables-in-netlify">Where can you add or update more variables in Netlify?</h2>
<p>With our example, we only added one variable during the setup. But Netlify lets you add or update any other variables you'd like.</p>
<p>If you'd ever like to change that variable or add more, you can navigate to the <strong>Environment</strong> section of the <strong>Build &amp; deploy</strong> settings, where you can edit and add any other variables in the <strong>Environment variables</strong> section.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/04/environment-variable-settings-netlify.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Environment variables settings in Netlify</em></p>
<h2 id="heading-looking-to-learn-more">Looking to learn more?</h2>
<p>Here are a few other things to help you get started with development fundamentals!</p>
<ul>
<li><a target="_blank" href="https://www.colbyfayock.com/2019/09/what-is-gatsby-and-why-its-time-to-get-on-the-hype-train">What is Gatsby and why it's time to get on the hype train?</a></li>
<li><a target="_blank" href="https://www.colbyfayock.com/2020/02/what-is-the-jamstack-and-how-do-i-get-started">What is the JAMstack and how do I get started?</a></li>
<li><a target="_blank" href="https://www.colbyfayock.com/2020/02/how-to-become-a-full-stack-web-developer-in-2020">How to Become a Full Stack Web Developer in 2020</a></li>
<li><a target="_blank" href="https://www.colbyfayock.com/2019/08/put-down-the-javascript-learn-html-css">Put Down the Javascript - Learn HTML &amp; CSS</a></li>
<li><a target="_blank" href="https://www.colbyfayock.com/2020/04/set-future-you-up-for-success-with-good-coding-habits">Set Future You Up for Success with Good Coding Habits</a></li>
</ul>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">? Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">?️ Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The real difference between Continuous Integration and Continuous Deployment ]]>
                </title>
                <description>
                    <![CDATA[ By Jean-Paul Delimat There is plenty of content out there describing what Continuous Integration, Continuous Delivery, and Continuous Deployment are. But what purposes do these processes serve in the first place?  It is crucial to understand the prob... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-real-difference-between-ci-and-cd/</link>
                <guid isPermaLink="false">66d45f75ffe6b1f641b5fa11</guid>
                
                    <category>
                        <![CDATA[ continuous delivery ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Continuous Integration ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 01 Dec 2019 21:37:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/12/continuous-integration-and-delivery.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jean-Paul Delimat</p>
<p>There is plenty of content out there describing what Continuous Integration, Continuous Delivery, and Continuous Deployment are. But what purposes do these processes serve in the first place? </p>
<p>It is crucial to understand the problems CI and CD solve to use them properly. This will allow your team to improve your process and avoid putting effort into chasing fancy metrics that do not bring any value to your process.</p>
<h2 id="heading-continuous-integration-is-a-team-problem">Continuous Integration is a team problem</h2>
<p>If you work in a team, chances are there are several developers working on the same repository. There is a main branch in the repository carrying the latest version of the code. Developers work on different things on different branches. Once someone is done with their change, they'll push or merge it to the main branch. Eventually the whole team will pull this change.</p>
<p>The scenario we want to avoid is that a faulty commit makes it to the main branch. Faulty means the code does not compile or the app won't start or is unusable. Why? Not because the app is broken or because all tests must always be green. That is not a problem–you can decide not to deploy that version and wait for a fix. </p>
<p>The problem is that your entire team is stuck. All the developers who pulled the faulty commit will spend 5 minutes wondering why it doesn't work. Several will probably try to find the faulty commit. Some will try to fix the issue by themselves in parallel of the faulty code author.</p>
<p>This is a waste of time for your team. The worst part is that repeated incidents fuel a mistrust of the main branch and encourage developers to work apart.</p>
<blockquote>
<p>Continuous Integration is all about preventing the main branch from breaking so your team is not stuck. That's it. It is <strong>not</strong> about having all your tests green all the time and the main branch deployable to production at every commit.</p>
</blockquote>
<p>The process of Continuous Integration is independent of any tool. You could manually verify that the merge of your branch and the main branch works locally, and then only actually push the merge to the repository. But that would be very inefficient. That's why Continuous Integration is implemented using automated checks.</p>
<p>The checks ensure that, at the bare minimum:</p>
<ul>
<li>The app should build and start</li>
<li>Most critical features should be functional at all times (user signup/login journey and  key business features)</li>
<li>Common layers of the application that all the developers rely on should be stable. This means unit tests on those parts.</li>
</ul>
<p>In practice, this means you need to pull any unit test framework that works for you and secure the common layers of the application. Sometimes it is not that much code and can be done fairly quickly. Also you need to add a "smoke test" verifying that the code compiles and that the application starts. This is especially important in technologies with crazy dependency injections like Java Spring or .NET core. In large projects it is so easy to miswire your dependencies that verifying that the app always starts is a must.</p>
<blockquote>
<p>If you have hundreds or thousands of tests you don't need to run them all for each merge. It will take a lot of time and most tests probably verify "non team blocker" features.</p>
</blockquote>
<p>We'll see in the next sections how the process of Continuous Delivery will make good use of these many tests.</p>
<h3 id="heading-its-not-about-tools">It's not about tools</h3>
<p>Tools and automated checks are all fine. But if your developers only merge giant branches they work on for weeks, they won't help you. The team will spend a good amount of time merging the branches and fixing the code incompatibilities that will arise eventually. It is as much a waste of time as being blocked by a faulty commit.</p>
<blockquote>
<p>Continuous Integration is not about tools. It is about working in small chunks and integrating your new code to the main branch and pulling frequently. </p>
</blockquote>
<p>Frequently means at least daily. Split the task you are working on into smaller tasks. Merge your code very often and pull very often. This way nobody works apart for more than a day or two and problems do not have time to become snowballs.</p>
<p>A large task does not need to be all in one branch. It should never be. Techniques to merge work in progress to the main branch are called "branching by abstraction" and "feature toggles". See the blog post <a target="_blank" href="https://fire.ci/blog/how-to-get-started-with-continuous-integration/">How to get started with Continuous Integration</a>  for more details.</p>
<h3 id="heading-key-points-for-a-good-ci-build">Key points for a good CI build</h3>
<p>It's very simple. <strong>Keep it short. 3-7 minutes should be the max.</strong> It's not about CPU and resources. It is about developers' productivity. The first rule of productivity is focus. Do one thing, finish it, then move to the next thing. </p>
<p>Context switching is costly. Studies show it takes ~23 minutes to deeply refocus on something when you get disturbed. </p>
<p>Imagine you push your branch to merge it. You start another task. You spend 15-20 minutes getting into it. The minute after you are in the zone you receive a "build failed" notification from your 20 minutes long CI build for the previous task. You get back to fix it. You push it again. You easily lost more than 20 minutes moving back and forth.</p>
<blockquote>
<p>Multiply 20 minutes once or twice a day by the number of developers in your team... That's a lot of precious time wasted.</p>
</blockquote>
<p>Now imagine if the feedback came within 3 minutes. You probably wouldn't have started the new task at all. You would have proof read your code one more time or reviewed a PR while waiting. The failed notification would come and you would fix it. Then you could move on to the next task. That is the kind of focus your process should enable.</p>
<p>Keeping your CI build short makes it a trade off. Tests that run longer or provide little value in the context of CI should be moved to the CD step. And yes, failures there also need to be fixed. But since they are not preventing anybody from doing their thing, you can take the fixes as a "next task" when you finish what you are doing. Just turn off the notifications while working and check every now and then. Keep the context switching to a minimum.</p>
<h2 id="heading-continuous-delivery-and-deployment-are-engineering-problems">Continuous Delivery and Deployment are engineering problems</h2>
<p>Let’s settle on the definitions to get that out of the way.</p>
<p><strong>Continuous Delivery</strong> is about being able to deploy any version of your code at all times. In practice it means the last or pre-last version of your code. You don’t deploy automatically, usually because you don’t have to or are limited by your project lifecycle. But as soon as someone feels like it, a deployment can be done in a minimal amount of time. That someone can be the test/QA team that wants to test things out on a staging or pre-production environment. Or it can actually be time to roll out the code to production.</p>
<p>The idea of Continuous Delivery is to prepare artifacts as close as possible from what you want to run in your environment. These can be .jar or .war files if you are working with Java, or executables if you are working with .NET. These can also be folders of transpiled JS code or even Docker containers, whatever makes deployment shorter (i.e. you have pre-built as much as you can in advance).</p>
<p>By preparing artifacts, I don't mean turning code into artifacts. This is usually a few scripts and minutes of execution. Preparing means:</p>
<blockquote>
<p>Run all the tests you can to ensure that, once deployed, the code will actually work. Run unit tests, integration tests, end to end tests, and even performance tests if you can automate that. </p>
</blockquote>
<p>This way you can filter which versions of your main branch are actually production ready and which are not. The ideal test suite:</p>
<ul>
<li>Ensures that the application's key functionalities work. Ideally all functionalities</li>
<li>Ensures that no performance deal breaker has been introduced so when your new version hits your many users, it has a chance to last</li>
<li>Dry run any database updates your code needs to avoid surprises</li>
</ul>
<p>It does not need to be very fast. 30 minutes or 1 hour is acceptable.</p>
<p><strong>Continuous Deployment</strong> is the next step. You deploy the most up to date and production ready version of your code to some environment. Ideally production if you trust your CD test suite enough. </p>
<p>Note that, depending on the context, this is not always possible or worth the effort. Continuous Delivery is often enough to be productive, especially if you are working in a close network and have limited environments you can deploy to. It can also be that the release cycle of your software prevents unplanned deploys.</p>
<p>Continuous Delivery and Continuous Deployment (let’s call them CD from now on) are not team problems. They are about finding the right balance between execution time, maintenance efforts and relevance of your tests suite to be able to say "This version works as it should." </p>
<p>And it is a balance. If your tests last 30 hours that is a problem. See <a target="_blank" href="https://news.ycombinator.com/item?id=18442941">this epic post</a> about what the Oracle database test suite looks like. But if you spend so much time keeping your tests up to date with the latest code that it impedes the team's progress, that is not good either. Also if your test suite ensures pretty much nothing... it is basically useless.</p>
<p>In an ideal world we want one set of deployable artifacts per commit to the main branch. You can see we have a vertical scalability problem: the faster we move from code to artifacts, the more ready we are to deploy the newest version of the code.</p>
<h2 id="heading-whats-the-big-difference">What’s the big difference?</h2>
<p>Continuous Integration is a horizontal scalability problem. You want developers to merge their code often so the checks must be fast. Ideally within minutes to avoid developers switching context all the time with highly async feedback from the CI builds. </p>
<p>The more developers you have, the more computing power you need to run simple checks (build and test) on all the active branches.</p>
<blockquote>
<p><strong>A good CI build:</strong></p>
<p>Ensures no code that breaks basic stuff and prevents other team members to work is introduced to the main branch, and</p>
<p>Is fast enough to provide feedback to developers within minutes to prevent context switching between tasks.</p>
</blockquote>
<p>Continuous Delivery and Deployment are vertical scalability problems. You have one rather complex operation to perform.</p>
<blockquote>
<p><strong>A good CD build:</strong></p>
<p>Ensures that as many features as possible are working properly.</p>
<p>The faster the better, but it is not a matter of speed. A 30-60 minutes build is OK.</p>
</blockquote>
<p>A common misconception is to see CD as a horizontal scalability problem like CI: the faster you can move from code to artifacts, the more commits you can actually process, and the closer to the ideal scenario you can be. </p>
<p>But we don't need that. Producing artifacts for every commit and as fast as possible is usually overkill. You can very well approach CD on a best effort basis: have a single CD build that will just pick the latest commit to verify once a given build is finished.</p>
<p>Make no mistake about CD. It is really hard. Getting to sufficient test confidence to say your software is ready to be deployed automatically usually works on low surface applications like APIs or simple UIs. It is very difficult to achieve on a complex UI or a large monolith system.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Tools and principles used to execute CI and CD are often very similar. The goals are very different though. </p>
<p>Continuous Integration is a trade off between speed of feedback loop to developers and relevance of the checks your perform (build and test). No code that would impede the team progress should make it to the main branch. </p>
<p>Continuous Delivery of Deployment is about running as thorough checks as you can to catch issues on your code. Completeness of the checks is the most important factor. It is usually measured in terms code coverage or functional coverage of your tests. Catching errors early on prevents broken code to get deployed to any environment and saves the precious time of your test team.</p>
<p>Craft your CI and CD builds to achieve these goals and keep your team productive. No workflow is perfect. Problems will arise every now and then. Use them as lessons learned to strengthen your workflow every time they do.</p>
<p>Published on 27 Nov 2019 on the <a target="_blank" href="https://fire.ci/blog/">Fire CI Blog</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to automate deployment on GitHub-pages with Travis CI ]]>
                </title>
                <description>
                    <![CDATA[ By Dhruv Barochiya Disclaimer: This story is not sponsored by any of the tools that has been described into the article (Travis-CI, Github, Github-Pages) You have created a project in React.js and deployed it on the GitHub-pages (not yet ?? — creat... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-how-to-automate-deployment-on-github-pages-with-travis-ci/</link>
                <guid isPermaLink="false">66d45e3f182810487e0ce145</guid>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Travis CI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 21 Jun 2019 16:18:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/Druhv-article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dhruv Barochiya</p>
<blockquote>
<p>Disclaimer: This story is not sponsored by any of the tools that has been described into the article (Travis-CI, Github, Github-Pages)</p>
</blockquote>
<p>You have created a project in React.js and deployed it on the GitHub-pages (not yet ?? — <a target="_blank" href="https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843">create your first project in React.js</a>) But what if you are making frequent changes into the code base and also want to keep the deployed version updated to the latest ? … You will find yourself in the tedious process of running the deployment scripts again and again !!!</p>
<blockquote>
<p>What if the deployment process can be automated ??</p>
</blockquote>
<p>After some quick google search session, I found that it is possible and can be achieved by Travis CI — an open source tool can be used to automate the deployment of various types of projects.</p>
<h2 id="heading-what-you-will-learn-gt">What you will learn &gt;</h2>
<p>In this article, you will be able to learn how to implement the system which will trigger the react deployment scripts using the TRAVIS-CI to deploy the project onto the GitHub-pages whenever there are any changes found in the master branch of the code repository.</p>
<ul>
<li>Setup Automated deployment of <strong>‘</strong><a target="_blank" href="https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843"><strong>react-portfolio’</strong></a> project</li>
<li>Learn about some frequent errors encountered while the process</li>
<li>Learn about some concepts related to ‘<strong>continuous deployment’</strong></li>
</ul>
<h2 id="heading-lets-learn-some-fundamentals">Let’s learn some fundamentals</h2>
<blockquote>
<p>Skip this section if you know you are not that type !!</p>
</blockquote>
<h3 id="heading-continuous-integrationci-amp-continuous-deliverycd-gt">Continuous Integration(CI) &amp; Continuous Delivery(CD) &gt;</h3>
<blockquote>
<p>“In <a target="_blank" href="https://en.wikipedia.org/wiki/Software_engineering">software engineering</a>, continuous integration (CI) is the practice of merging all developers’ working copies to a shared <a target="_blank" href="https://en.wikipedia.org/wiki/Trunk_%28software%29">mainline</a> several times a day” — <a target="_blank" href="https://en.wikipedia.org/wiki/Continuous_integration">wikipedia</a></p>
</blockquote>
<p>In other words, the developers will try to merge their feature code into the master branch as frequent as possible. Following this practice enables the developers and product managers to release the product more frequently.</p>
<p>There are some extended versions of the CI pipelines in which these changes are also being tested automatically which makes the code deployable at any time, it’s called <strong>‘Continuous Delivery</strong>’. A further extension of this pipeline is called <strong>‘Continuous Deployment’</strong> pipeline, where these tested code changes are pushed automatically into the production servers. ( We will be implementing the continuous deployment pipeline in our case)</p>
<h3 id="heading-travis-ci-gt">Travis CI &gt;</h3>
<p><strong>Travis CI</strong> is a hosted continuous integration service used to build and test software projects hosted at GitHub. Open source projects can be tested without any charges !!</p>
<p>Travis CI can be configured by adding a <code>.travis.yml</code> file to the repository. when Travis CI has been activated for a given repository, GitHub will notify whenever new commits are pushed to the repository or any pull request is submitted then according to the rules defined in the <code>.travis.yml</code> file, Travis CI will perform the steps which can be anything — from running tests, building the application or deployment scripts. Travis CI offers a wide range of options to build the software and of course, our beloved ❤️<code>javascript</code> is one of them.</p>
<blockquote>
<p><strong>NOTE<em>:</em></strong> <em>Github has</em> <a target="_blank" href="https://education.github.com/pack"><strong><em>student developer pack</em></strong></a> <em>available with a bunch of premium features from different platforms (Travis CI is one of them) for free to students who wish to learn new things — get your student pack now !!</em></p>
</blockquote>
<h3 id="heading-devops-gt">DevOps &gt;</h3>
<p><strong>DevOps</strong> is a set of software development practices that combines <a target="_blank" href="https://en.wikipedia.org/wiki/Software_development">software development</a> (<em>Dev</em>) and <a target="_blank" href="https://en.wikipedia.org/wiki/Information_technology_operations">information technology operations</a>(<em>Ops</em>) to shorten the <a target="_blank" href="https://en.wikipedia.org/wiki/Systems_development_life_cycle">systems development life cycle</a> while <a target="_blank" href="https://en.wikipedia.org/wiki/Continuous_delivery">delivering features, fixes, and updates</a> frequently. The concept of DevOps is founded on building a culture of collaboration between teams.</p>
<blockquote>
<p>“DevOps is more than practice — it’s about culture”</p>
</blockquote>
<p>Continuous Integration, Continuous Delivery, Continuous Deployment are some of the few key practices of the DevOps. Apart from these DevOps engineers heavily uses the power of the cloud infrastructure to make the deployment process seamless.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*9pVLG4BzEWIcMnfhFp9ULQ.png" alt="Image" width="1600" height="823" loading="lazy"></p>
<hr>
<h2 id="heading-enough-talking-lets-do-some-action">Enough talking !!! Let’s do some action</h2>
<p>As you have already deployed on the GitHub pages using the <code>gh-pages</code> node module, there will be a branch called <code>gh-pages</code>on the repository which holds the files which are deployed onto the Github pages servers. After the integration of the Travis CI, we would ab able to implement the system where any changes made by the user on the <code>master</code> branch will automatically trigger a build. If the build is successful, then the build scripts will be triggered which will update the <code>gh-pages</code> branch. User will be notified about the status of the build via email notifications from the Travis CI</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*athThq_0-5cg1foDqt0v5w.png" alt="Image" width="1052" height="744" loading="lazy"></p>
<h3 id="heading-create-an-account-on-travis-ci-gt">Create an account on Travis-CI &gt;</h3>
<ul>
<li>Go to <a target="_blank" href="https://travis-ci.com/">Travis-ci.com</a> and <a target="_blank" href="https://travis-ci.com/signin"><em>Sign up with GitHub</em></a>.</li>
<li>Accept the terms &amp; conditions of Travis CI. You’ll be redirected to GitHub.</li>
<li>Click the <em>Activate</em> button, and select the repositories you want to use with Travis CI.</li>
<li>Add authorization token ( This will be done automatically when you sign-in with GitHub)</li>
</ul>
<h3 id="heading-add-travisyml-file-into-the-repository-gt">Add travis.yml file into the repository &gt;</h3>
<p>This file contains the instructions which tell Travis-CI — what?..how?..when?</p>
<blockquote>
<p><strong>NOTE</strong>: When you trigger a job in the Travis-CI, it will boot up a virtual machine with the appropriate deployment environment configured in the <code>_.travis.yml_</code></p>
</blockquote>
<p>Let’s break down the code —</p>
<pre><code class="lang-yml"><span class="hljs-attr">language:</span> <span class="hljs-string">node_js</span>
<span class="hljs-attr">node_js:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">"stable"</span>
<span class="hljs-attr">cache:</span>
  <span class="hljs-attr">directories:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">node_modules</span>
<span class="hljs-attr">script:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">npm</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
<span class="hljs-attr">deploy:</span>
  <span class="hljs-attr">provider:</span> <span class="hljs-string">pages</span>
  <span class="hljs-attr">skip_cleanup:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">github_token:</span> <span class="hljs-string">$github_token</span>
  <span class="hljs-attr">local_dir:</span> <span class="hljs-string">build</span>
  <span class="hljs-attr">on:</span>
    <span class="hljs-attr">branch:</span> <span class="hljs-string">master</span>
</code></pre>
<p><code>on</code> : Travis-CI will automatically trigger a job whenever there are some changes made on the branch specified in this field.</p>
<p><code>deploy</code> : In this filed we have declared that we will use the deployment <a target="_blank" href="https://docs.travis-ci.com/user/deployment/pages/">provider for the GitHub pages</a> provided by the Travis-CI which is nothing but the configuration instructions for setting up the environment for deployment.</p>
<p><code>script</code> : This filed contains the build scripts which will be executed while running the job. For this case that is the build script, you can also add test scrips ( code-coverage, fusion test, etc.) before the build.</p>
<p><code>cache</code> : Travis-CI provides an option to cache the library files and modules which will be the constant for all the builds. Cached files can be used again by the later build jobs which decreases the end-to-end running time of the job.</p>
<h2 id="heading-all-set-gt">All set &gt;</h2>
<p>Ohkay everything is in the place, now onwards if you commit anything on the master branch it will trigger a Travis-CI build job which will look something like in the below screenshots. You can also trigger a build manually from the Travis-CI dashboard itself.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*W34g38dx2jy5wxP4yS5y3w.png" alt="Image" width="1600" height="649" loading="lazy">
<em>Travis-CI job(Running)</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*V6MOHQiV2agPnAtfo6Wyjw.png" alt="Image" width="1600" height="558" loading="lazy">
<em>Travis-CI job (successful)</em></p>
<h2 id="heading-but-there-is-always-a-but-huh">But …. (there is always a but !! huh!!)</h2>
<p>I am pretty sure your build dashboard will not look like the above one same as life has not been smooth we were told it would be ?. There can be infinite reasons due to which your Travis-CI dashboard is full of failed builds ( I know..I have been through this)</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*xoGfeAu4sb-_l7ggTbjC7Q.png" alt="Image" width="1600" height="591" loading="lazy"></p>
<p>This is the time when your most valuable “googling” skills will come handy. I will explain what all are the errors I have faced while I was trying to create a pipeline.</p>
<ul>
<li>Security errors</li>
<li>Token errors</li>
<li>Just random errors (You have to get dirty &amp; find the solution!!)</li>
</ul>
<h3 id="heading-token-errors-gt">Token errors &gt;</h3>
<p>If your builds are failing due permissions error then there are high chances that there is some <a target="_blank" href="https://docs.travis-ci.com/user/deployment/pages/#setting-the-github-token">problem with tokens</a>. You need to go to the token URL <a target="_blank" href="https://github.com/settings/tokens">https://github.com/settings/tokens</a> and see when it was used lately, if it shows <strong><em>never</em></strong> then you have found your culprit.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*9NrQnLn0Mrp7Oex9H_F-Og.png" alt="Image" width="1600" height="479" loading="lazy"></p>
<p>Follow the below steps,</p>
<ul>
<li>Delete and create a new token</li>
<li>Add it to the Travis environment variables ( Go to job settings )</li>
<li>Re-try the build</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*5CtnigPrV0L3ylole9kvVw.png" alt="Image" width="1600" height="966" loading="lazy"></p>
<h3 id="heading-security-errors-gt">Security errors &gt;</h3>
<p>There are plenty of security practices we ignore while coding &amp; building web applications. When we run in local these security errors are not given much emphasis and often discarded as warning messages, but when we are trying to deploy the service using the Travis-CI these warnings will cause the build failure.</p>
<p>I will mention the errors I encountered while working on my project(I would encourage you to mention the errors you have encountered) The great thing is that most of them have their own dedicated web-pages which explain the underlying problem and offers the solutions/workarounds ( Workarounds — we all love it even knowing that we shouldn’t !! )</p>
<ul>
<li><strong>Using target=_blank in HTML  tag :</strong> This is more serious security flaw than it looks. You can learn more about it <a target="_blank" href="https://mathiasbynens.github.io/rel-noopener/">here.</a></li>
<li><strong>Redundancy in HTML code</strong>: There were many redundant tags/class names which were making the code look like junk.</li>
</ul>
<p>Best way to prevent these errors is to install the <code>es-lint</code> plug-in in whichever text-editor you are using.</p>
<hr>
<h2 id="heading-built-some-project-share-it">Built some project? — Share it</h2>
<p>I am trying to build a community of developers where people can share their ideas, knowledge, work with others and find other people with similar ideology to build things together. So, if you built some project and want to share it, post it on the channel.</p>
<ul>
<li>Gitter channel: <a target="_blank" href="https://gitter.im/weekend-devs/community">https://gitter.im/weekend-devs/community</a></li>
<li>Github Organization: <a target="_blank" href="https://github.com/weekend-developers">https://github.com/weekend-developers</a></li>
</ul>
<hr>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>I would like to take a moment to acknowledge the work of the people who gave me the inspiration and knowledge to complete this article.</p>
<ul>
<li><strong>Travis CI community:</strong> for providing awesome tools for free.</li>
<li><strong><em>My dearest friends:</em></strong> who helped me in correcting my mistakes.</li>
<li><strong>YOU:</strong> for sticking around, I hope you had a productive time. Keep exploring and building amazing things!</li>
</ul>
<hr>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*vNXcdsgZAeulGy1r" alt="Image" width="1600" height="1066" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@clemensvanlay?utm_source=medium&amp;utm_medium=referral" data-href="https://unsplash.com/@clemensvanlay?utm_source=medium&amp;utm_medium=referral" class="markup--anchor markup--figure-anchor" rel="photo-creator noopener noopener noopener" target="_blank"&gt;Clemens van Lay on &lt;a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral" data-href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral" class="markup--anchor markup--figure-anchor" rel="photo-source noopener noopener noopener" target="<em>blank)</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to set up continuous deployment in your home project the easy way ]]>
                </title>
                <description>
                    <![CDATA[ By Julius Continuous Deployment is a beautiful thing. Committing your project and seeing it being built and deployed without having to do anything is mesmerizing. And in this article, I want to show you how to get it done in your home project with ea... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-set-up-continuous-deployment-in-your-home-project-the-easy-way-41b84a467eed/</link>
                <guid isPermaLink="false">66c3547711526e205ba67893</guid>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 06 Feb 2019 22:49:13 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*pnP8tnza1D2UAqBJXsnpug.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Julius</p>
<p>Continuous Deployment is a beautiful thing. Committing your project and seeing it being built and deployed without having to do anything is mesmerizing.</p>
<p>And in this article, I want to show you how to get it done in your home project with ease.</p>
<p>To clear it up, here is a flowchart showing the differences between Continuous Delivery and Continuous Deployment.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/xEnnOKXV4Pipmzu6EXGwIrNllSB6L9Nk98xi" alt="Image" width="800" height="290" loading="lazy">
<em>Continuous Delivery vs. Continuous Deployment</em></p>
<p>Since most of the time no one but you depends on your home project, we’re going for a workflow with Continuous Deployment since you want to see your changes immediately deployed. If that’s not the case, you can change the workflow later.</p>
<p>You will learn about the following:</p>
<ul>
<li>How to make a Dockerfile</li>
<li>How to push your project to GitHub</li>
<li>Automatically building the docker image on Docker Hub</li>
<li>Automatically downloading and running the image with <a target="_blank" href="https://github.com/v2tec/watchtower">Watchtower</a></li>
</ul>
<p>Prerequisites:</p>
<ul>
<li>Some knowledge about Docker and the Dockerfile, though I will explain some of it along the way</li>
<li>Have <a target="_blank" href="https://git-scm.com/">git</a> installed</li>
<li>A <a target="_blank" href="https://hub.docker.com/">Docker Hub</a> account</li>
<li>A (Linux) server (either physical or virtual) running Docker</li>
</ul>
<p>For reference, <a target="_blank" href="https://github.com/juligreen/easy_CD_tutorial">this</a> is the example GitHub repository, and <a target="_blank" href="https://hub.docker.com/r/juligreen/easy_cd_tutorial">this</a> is the example docker hub repository that I’ll be using.</p>
<p>Thus this tutorial will only be useful if you intend to run your software with Docker (which I recommend as Docker is fantastic).</p>
<h4 id="heading-why-use-docker">Why use Docker?</h4>
<p>Docker enables you to have the same environment for development and production which eliminates <a target="_blank" href="https://en.wikipedia.org/wiki/Heisenbug">Heisenbugs</a> and the “it works on my machine” problem. Also, containers are isolated which gives us security benefits.<br>There’s more to it, but these two benefits make me always deliver my software in Docker containers.</p>
<h4 id="heading-setting-up-your-dockerfile">Setting up your Dockerfile</h4>
<p>First, we will make a Dockerfile for the project. This special file is always called “Dockerfile” without an extension and sits at the top directory of your project.</p>
<p>A Dockerfile starts with the <code>FROM</code> statement which tells Docker which base image you want to start with. You can imagine this as using a canvas with the background already drawn and only the central part (your program) missing.<br>Most of the time the image you want to pull is the base image of your programming language, which you can find at the before mentioned <a target="_blank" href="https://hub.docker.com/">Docker Hub</a>.</p>
<p>Next, we copy our project files into the docker container with the <code>COPY..</code> command. What does this do?</p>
<p>It takes the files from the first directory (the dot refers to the current directory of the file, which includes all your project files) and puts it in the current directory of your Docker container (remember your docker container is its own OS). Your files are now at the base directory there, which you may want to change.</p>
<p>Next, we need to install dependencies, which I will use <code>python pip</code> for, but any equivalent package management system depending on your language of choice will do. The critical thing to learn here is how to execute commands in the container with RUN.</p>
<pre><code>From python:<span class="hljs-number">3.7</span>COPY . .RUN pip install -r requirements.txt
</code></pre><p>Easy, isn’t it? Now we have to start our program in the container.</p>
<pre><code>CMD [<span class="hljs-string">"python"</span>, <span class="hljs-string">"./my_script.py"</span>]
</code></pre><p>The CMD statement is unique. Every Dockerfile has to have it as its last line because it starts the primary process in the container.</p>
<p>You have finished your Dockerfile! You can now manually build your image and container, but we’re going to skip that for now.</p>
<p>Now, we’ll create our repository on GitHub, but remember to leave “Initialize this repository with a README” unticked.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/p2vOXrhxde9j6cgaJr9xVaUzmeUPFRy2gn4v" alt="Image" width="742" height="760" loading="lazy"></p>
<p>Then you’d need to copy the remote URL.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/-eXorLpmcko2fgM90tBcb9tMftguLhpf1UbV" alt="Image" width="800" height="605" loading="lazy"></p>
<p>Open a cmd/shell in the root directory of your project.</p>
<p>You need to initialize your git repository, add your files, configure the remote, commit the files and push your project to GitHub.</p>
<pre><code>git initgit add *git remote add origin https:<span class="hljs-comment">//github.com/&lt;user&gt;/&lt;repository&gt;.gitgit commit -a -m "Make Dockerfile ready for CD"git push -u origin master</span>
</code></pre><p>Now, your GitHub Repository should look like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/k8CCf3yng-7yKMFCUyKwxs1NVJGmQQ8xPuyB" alt="Image" width="800" height="407" loading="lazy"></p>
<p>Congratulations, you’re about halfway done!</p>
<p>The next step is to connect GitHub to Docker Hub. For this, you go to the account settings.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7kSYmYk8hcF0-lzHuP1bYGf2U-Q6QTWVKtM8" alt="Image" width="800" height="418" loading="lazy"></p>
<p>Scroll down and connect your git host.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/SBZCVplxQiaLApLklpqfCruODRyHLpWC1pXa" alt="Image" width="800" height="777" loading="lazy"></p>
<p>Create your repository on docker hub now.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/FRgXa6dDUumrTAOHHiwjF1VrvOsHP8EPe5r3" alt="Image" width="800" height="294" loading="lazy"></p>
<p>Give the repo a name and click the GitHub icon (or Bitbucket, if that’s your thing). Now choose your organization (usually your username) and your project’s name. If you want to use your master image for the build and always push to latest, you can now click “Create &amp; Build” and watch your image being built for you. Otherwise, you have to edit the build settings.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZG12hUUr3GBIgVV7RjsivzjbTd4Pm2ycpcy9" alt="Image" width="698" height="832" loading="lazy"></p>
<p>Last steps! Now you need <a target="_blank" href="https://github.com/v2tec/watchtower">Watchtower</a> on your target machine.<br>Watchtower is a program that pulls your running docker images and checks for updates. If there are any updates, it gracefully shuts down the original container and creates a container from the new image with the same settings.</p>
<p>The best thing is that we can also install Watchtower with Docker!</p>
<p>Enter the following into your terminal:</p>
<pre><code>docker run -d --name watchtower -v /<span class="hljs-keyword">var</span>/run/docker.sock:<span class="hljs-regexp">/var/</span>run/docker.sock v2tec/watchtower
</code></pre><p>Then you need to run the Docker container for your project!</p>
<pre><code>docker run -d --name &lt;my-project&gt; &lt;username&gt;/&lt;my-project&gt;
</code></pre><p>The “-d” option makes your program run in the background, so the program doesn’t shut down if you close the terminal.</p>
<p>So to summarize, if you push a commit to your GitHub repository, Docker hub will automatically build a Docker image for you. This image then gets pulled by WatchTower and is run with all original options.</p>
<p>If you need help at any point don’t be afraid to ask, I’m happy to help.<br>If it is a technical problem, an issue on the <a target="_blank" href="https://github.com/juligreen/easy_CD_tutorial/issues">GitHub project</a> would be awesome!</p>
<h4 id="heading-but-what-about-tests">But what about tests?</h4>
<p>Good question!<br>You can use Travis CI to run your tests at the same time.<br>You can read about this <a target="_blank" href="https://docs.travis-ci.com/user/tutorial/">here</a>, but the gist of it is, that you add another file to your repository which has instructions for an external server to execute unit tests or any other instructions.</p>
<blockquote>
<p>But what if I only want my docker image to build if the tests pass?</p>
</blockquote>
<p>This breaks our workflow a bit.<br>We now can’t rely on docker hub to build our images anymore. Instead, it’s also going to be Travis CI that produces the image and then pushes it to your Docker Hub repository. Read about this <a target="_blank" href="https://docs.travis-ci.com/user/docker/">here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to simplify the deployment of containerized apps ]]>
                </title>
                <description>
                    <![CDATA[ By Omer Levi Hevroni I asked myself this question when I started to learn Kubernetes: how can we simplify the deployment of containerized apps? At first look, deploying containerized apps seems pretty simple. All you need is a bunch of YAML files, an... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-can-we-simplify-deployment-of-containarized-apps-a2effd01a662/</link>
                <guid isPermaLink="false">66c34ce00fa3812cdd5ea9e8</guid>
                
                    <category>
                        <![CDATA[ continuous deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Helm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kubernetes ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 16 Apr 2018 05:11:19 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*QzKmrPtCm5SvCklDccppkQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Omer Levi Hevroni</p>
<p>I asked myself this question when I started to learn <a target="_blank" href="https://kubernetes.io/">Kubernetes</a>: how can we simplify the deployment of containerized apps? At first look, deploying containerized apps seems pretty simple. All you need is a bunch of YAML files, and by using <code>[kubectl](https://kubernetes.io/docs/reference/generated/kubectl/kubectl/)</code> (the Kubernetes command line utility), you’ll have your service up and running in your Kubernetes cluster.</p>
<p>But, Although deploying one app is an easy task, how do you deploy hundreds of apps? At <a target="_blank" href="https://www.solutotlv.com">Soluto</a>, we have more than 100 live microservices and this number keeps growing. So as we started thinking about shifting workload to our Kubernetes cluster, we faced a few challenges:</p>
<p>First, Kubernetes deployment is actually more complex. There are many moving parts that you need to set up correctly: pod autoscaler, pod resources, ingress, and so on. Those parts require some experience with how Kubernetes works, and not setting it up correctly might cause issues in production. Ideally we’d have a way to simplify this, so developers can focus on writing their code and worry less about deployment.</p>
<p>Second, security is also a challenge. All services in production should have certain things, like Transport Layer Security (TLS). These are not necessarily complex things, but need to be taken care of nonetheless. We would like to pre-configure them so that any new deployment will be secured by default.</p>
<h3 id="heading-finding-a-solution">Finding a solution</h3>
<p>To solve these challenges and speed up and ease the adoption process, we looked for a way to create a template for Kubernetes. Something that any developer would be able to use, and would require just a few parameters (for example, the Docker image of the service) to get the service up and running in production.</p>
<p>On the other hand, we needed to be careful not to hide too much — developers must be able to understand what’s going on so they can handle production issues. We had to find the right level of abstraction that makes it easier to deploy to Kubernetes, without hiding too much detail.</p>
<p>With that in mind, we started to look for a solution. After trying a few things, we found <a target="_blank" href="https://helm.sh/">Helm</a>. Helm is a package manager for Kubernetes.You can use it to install any app on your cluster, and Helm will take care of getting all the required configuration files and installing them on your cluster. Helm also support updating deployments, rollbacks, and many other cool features. Each Helm package is called a “Chart”, and the charts are stored in a repository. With helm, installing <a target="_blank" href="https://github.com/kubernetes/charts/tree/master/stable/mongodb">Mongo</a>, for instance, is as easy as <code>helm install stable/mongodb</code>.</p>
<p>Sound like an excellent solution! We can define a chart for each type of service — like one for all our web APIs, which will handle things like load balancer and TLS — and the developer simply needs to specify the required parameters using Helm’s configuration files.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/4P0D8IGfVHiObVNHgAdPTrrhcNFOZh2irhoj" alt="Image" width="800" height="533" loading="lazy">
<em>Me and my teammate, when we found Helm</em></p>
<h3 id="heading-helm-lets-see-how-its-done">Helm: Let’s see how it’s done</h3>
<p>In order to use Helm, we first need to <a target="_blank" href="https://docs.helm.sh/using_helm/#installing-helm">install</a> it. Helm has two components: Helm client running on your computer, and Tiller, a server-side component running on your cluster. Then, we need to create the chart by using this simple Helm CLI command: <code>helm create web-api</code></p>
<p>After running this command, you’ll notice the creation of a new folder named “web-api”. Within this folder, you’ll find all the familiar Kubernetes configuration files: deployment, service, ingress, and so on. Now it’s time to customize a bit: we can add a <a target="_blank" href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/">horizontal pod autoscaler</a>, define the default resources the pod requires, and of course, enable TLS by default.</p>
<p>Everything is highly customizable based on the <a target="_blank" href="https://docs.helm.sh/chart_template_guide/">Go templating mechanism</a>. So anything we add can be overridden later by the developer, in case the default configuration doesn’t work as needed.</p>
<p>So now we have a chart — but how can we consume it? The chart has to exist in a <a target="_blank" href="https://github.com/kubernetes/helm/blob/master/docs/chart_repository.md">Helm repository</a>, which is basically a server with a few Zip archives (which are all the charts in the repository) and one index file that is consumed by the CLI. You can manually set up your repo using any storage service like Azure Blob or AWS S3, but the simplest option is <a target="_blank" href="https://github.com/kubernetes-helm/chartmuseum">Chart Museum</a>.</p>
<p>Chart museum is a Helm repository with a CRUD API to manage your charts. It supports basic authentication so you can restrict who can push new charts to your Helm repository. Helm doesn’t supply any museum-as-a-service solution, so you’re gonna have to roll your own. But it’s dead simple — <a target="_blank" href="https://hub.docker.com/r/chartmuseum/chartmuseum/">simply use its docker image.</a></p>
<p>Now we can build a CI/CD pipeline for our web-api chart, to ease the process of modifying it:</p>
<ul>
<li>Run some kind of tests, to make sure that the new version is not broken. I’ll discuss how in the next paragraph.</li>
<li>Pack the new chart, using Helm CLI.</li>
<li>Push the new package to our Chart Museum instance, using Chart Museum’s API.</li>
</ul>
<h3 id="heading-testing-it-out">Testing it out</h3>
<p>Now our chart is ready to be used by developers! But wait… how can we know that the chart actually works? And how can we make sure it will continue to work? This is why we need to write tests for our chart (like we write for anything else).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/WGGYmgftYuRQOqzlognwNV8yF4IFx6etjAF2" alt="Image" width="475" height="547" loading="lazy"></p>
<p>There are basically two things we want to test.</p>
<ol>
<li>We want to test our template — for example, if an ingress is supposed to exist with a TLS and specific rules (defined by the developer), we should test the generated template and make sure the ingress was created correctly.</li>
<li>We want to test that the files are valid Kubernetes configurations and that they work as expected.</li>
</ol>
<p>Testing the first thing is relatively simple — check out this <a target="_blank" href="https://github.com/omerlh/helm-chart-tests-demo">sample repo</a> to see just how simple it is.</p>
<p>This allows us to test the generated Kubernetes files, by using <code>[kubetest](https://github.com/garethr/kubetest)</code>. This is great, but can be complex and messy, especially when having a lot of branching in your template files.</p>
<p>A better solution is required — one that will allow us to do unit testing for the templates, without generating Kubernetes files. This wasn’t a problem until recently when we started to have a lot of branching in our templates, and we’re now looking for options.</p>
<p>The second thing — testing that Kubernetes files are valid — is a bit more tricky. For now, at Soluto we’re using Helm’s version mechanism: each chart has a version, and all of our services will use the latest stable version. When a new chart version is pushed, we can test this version on a specific service. If it works correctly, update the rest of the services. Another option is to test that using <code>minikube</code>, but it was too complex for our needs.</p>
<h3 id="heading-finally-deploying">Finally: Deploying!</h3>
<p>So now we have a CI/CD pipeline for our Helm charts, and we have prepared a Helm chart that the developers can use. Now, when a new developer wants to deploy a new service to production, all they have to do is:</p>
<ol>
<li>Add our repository to their local Helm using <code>helm repo add chartmuseum http://&lt;chart-museum-u</code>rl&gt;  </li>
<li>Create a new Helm config file and specify the required parameters (for example, docker image of the service)<br>3<code>. Run helm upgrade —install &lt;service-name&gt; chartmusuem/web-api -f&lt;path_</code>to_config_file&gt; and that’s it. The service is alive.</li>
</ol>
<p>And to make it even easier to understand, I’ve created a sample <a target="_blank" href="https://github.com/Soluto/kubernetes-deployment-demo">repository</a>. The repository contains all the things that I’ve discussed in this blog post: a generic chart for a web app that can be deployed with this chart and chart museum. Check it out to better understand what’s going on — and there is even a walkthrough to help you get started.</p>
<p>Thank you for reading along. If you have any questions, or you need help getting started with Helm, feel free to reach out either via the comments here or via <a target="_blank" href="https://twitter.com/intent/tweet?text=.%20%40omerlh%2C%20I%20have%20a%20question%20about%20%40Helm&amp;via=SolutoEng">Twitter</a>.</p>
<p>Happy Helming!</p>
<p>Originally posted on <a target="_blank" href="https://blog.solutotlv.com/?utm_source=medium">Soluto’s Blog</a></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
