<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Suman Sarkar</title>
    <description>The latest articles on DEV Community by Suman Sarkar (@sumansarkar).</description>
    <link>https://dev.to/sumansarkar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F708218%2Fffc96d04-9bcf-41c8-876f-f6cd1f347c6f.jpeg</url>
      <title>DEV Community: Suman Sarkar</title>
      <link>https://dev.to/sumansarkar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sumansarkar"/>
    <language>en</language>
    <item>
      <title>Gitlab CI/CD + NodeJs + pm2</title>
      <dc:creator>Suman Sarkar</dc:creator>
      <pubDate>Fri, 14 Jan 2022 16:16:59 +0000</pubDate>
      <link>https://dev.to/sumansarkar/gitlab-cicd-nodejs-pm2-4llh</link>
      <guid>https://dev.to/sumansarkar/gitlab-cicd-nodejs-pm2-4llh</guid>
      <description>&lt;p&gt;✋ Hi this is Suman Sarkar, a web-dev from Kolkata with 5 years of experience in programming and little to none experience with CI/CD. Today I'll talk about how to setup Gitlab CI/CD with self hosted runners.&lt;/p&gt;

&lt;h2&gt;
  
  
  👉 Things we will cover in this article
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;😕 What is CI/CD?&lt;/li&gt;
&lt;li&gt;👍 Setup a minimal expressjs API with pm2&lt;/li&gt;
&lt;li&gt;🧑‍💻 Setup our first ever Gitlab pipeline to install &amp;amp; restart our server whenever an update is pushed on the “dev” branch&lt;/li&gt;
&lt;li&gt;🏃 Install self-hosted runners on a linux server&lt;/li&gt;
&lt;li&gt;🔒 Register our local runner to Gitlab&lt;/li&gt;
&lt;li&gt;🔑 Add environment variables to Gitlab&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  😕 What is CI/CD?
&lt;/h2&gt;

&lt;p&gt;From my perspective CI/CD or Continuous Integration &amp;amp; Continuous Deployment are processes that you set up for your own convenience so that you don't have to do boring things manually over and over, it is basically automating your workflow when you push an update to your project. Most of us do git pull and then sort of restart the server in order to make the changes into effect, there might be additional steps like building or testing and few other procedures that are specific to your project. I’ll not cover these today, today I’ll only cover how to setup CI/CD for an expressjs application with pm2, Gitlab pipeline and self-hosted runners.&lt;/p&gt;

&lt;h2&gt;
  
  
  👍 Setup a minimal expressjs API with pm2
&lt;/h2&gt;

&lt;p&gt;We start with creating a directory for our Node JS Express API&lt;/p&gt;

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

&lt;span class="nb"&gt;mkdir &lt;/span&gt;node-cicd-pm2
&lt;span class="nb"&gt;cd &lt;/span&gt;node-cicd-pm2


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

&lt;/div&gt;

&lt;p&gt;Then we initialise our project with &lt;code&gt;npm init -y&lt;/code&gt;. This creates a &lt;strong&gt;package.json&lt;/strong&gt; file in our project folder with basic information for our project.&lt;br&gt;
Next we add our dependencies by running&lt;/p&gt;

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

npm i –save express dotenv


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

&lt;/div&gt;

&lt;p&gt;Lets create our very minimal server by creating our &lt;code&gt;index.js&lt;/code&gt; and pasting the below mentioned code.&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server is running on port http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here, we have required our dependencies express and dotenv then we have added a route that returns 'Hello World!'. We have also added a &lt;code&gt;.env&lt;/code&gt; file with only 1 variable.&lt;/p&gt;

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

PORT="3001"


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

&lt;/div&gt;

&lt;p&gt;and &lt;code&gt;ecosystem.config.js&lt;/code&gt; file with the following content&lt;/p&gt;

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

module.exports = {
    apps: [{
        name: "node-cicd-pm2",
        script: "./index.js"
    }]
}


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

&lt;/div&gt;

&lt;p&gt;This will be used later to start our server as a process.&lt;/p&gt;

&lt;p&gt;Now, we start our server by running &lt;code&gt;node index.js&lt;/code&gt; and visit &lt;a href="http://localhost:3001/" rel="noopener noreferrer"&gt;http://localhost:3001/&lt;/a&gt;. It works on my machine! 😈&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F544hed6gwezrqpsrjv5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F544hed6gwezrqpsrjv5i.png" alt="Gitlab CI/CD + NodeJs + pm2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🏃 Setup our first ever Gitlab pipeline
&lt;/h2&gt;

&lt;p&gt;We start with creating a file specifically named &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;. This is an YML file, if you don't like YML, bad news for you, but you can just copy paste and get things done. &lt;br&gt;
Now, paste the following code. I'll explain this in detail.&lt;/p&gt;

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

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build_stage&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy_stage&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Lets talk about stages, stage are the necessary steps that you can group and describe. We have 2 stages build_stage and deploy_stage. Though we are not building anything here but I like to call it the build stage where we'll install the dependencies. We will cover the deploy stage later.&lt;/p&gt;

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

&lt;span class="na"&gt;.base-rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_BRANCH&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dev"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"push"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_TAG&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Rules are to describe exactly when your pipeline should run. Here we are specifying that we want to run our pipeline whenever something is pushed onto dev branch by specifying &lt;strong&gt;when&lt;/strong&gt; to &lt;strong&gt;always&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;$CI_PIPELINE_SOURCE&lt;/strong&gt; is a special(pre-defined) env. variable provided by Gitlab. It describes the mode our change. These can be the following values push, web, schedule, api, external, chat, webide, merge_request_event, external_pull_request_event, parent_pipeline, trigger, or pipeline. For the same of this article I'll not cover all of them, I am not familiar with most of them anyway.&lt;br&gt;
You can read more about the variables &lt;a href="https://docs.gitlab.com/ee/ci/variables/predefined_variables.html" rel="noopener noreferrer"&gt;here on Gitlab&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up we have caches. The way every stage works is, it cleans or deletes everything a it has produce during its lifetime. In the build stage we will create a &lt;strong&gt;node_modules&lt;/strong&gt; folder which will contain our project's dependencies. When the &lt;strong&gt;build_stage&lt;/strong&gt; is finished we don't want it to be deleted. We want it to passed to the &lt;strong&gt;deploy_stage&lt;/strong&gt;&lt;/p&gt;

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

&lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;global_cache&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_REF_SLUG&lt;/span&gt;
  &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull-push&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;package-lock.json&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We have created a global cache policy here. The policy is pull-push meaning that the stages using this cache policy can pull from global cache and can push to it as well. In order to create new caches with every update, we must provide a slug or an unique identifier. Here we are using &lt;strong&gt;$CI_COMMIT_REF_SLUG&lt;/strong&gt; variable for that. Notice how we are specifying that we only want to cache &lt;code&gt;node_modules&lt;/code&gt; directory and &lt;code&gt;package-lock.json&lt;/code&gt; since these are the outputs that are generate with &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's now define our &lt;strong&gt;build_stage&lt;/strong&gt;&lt;/p&gt;

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

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build_stage&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.base-rules&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*global_cache&lt;/span&gt;
    &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;local_runner&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The build_stage extends the base_rule so that it will run only when something is pushed on the &lt;code&gt;dev&lt;/code&gt; branch.&lt;br&gt;
In this stage we don't want to pull anything from the global-cache, we just want to push the &lt;code&gt;node_modules&lt;/code&gt; directory and &lt;code&gt;package-lock.json&lt;/code&gt; file in the global-cache. We will cover &lt;strong&gt;tags&lt;/strong&gt; later int this article.&lt;/p&gt;

&lt;p&gt;Later we have the &lt;strong&gt;deploy_stage&lt;/strong&gt;&lt;/p&gt;

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

&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_stage&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.base-rules&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pm2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ecosystem.config.js"&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*global_cache&lt;/span&gt;
    &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;local_runner&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In this stage we are pulling the cache from global-cache and then starting our server with &lt;code&gt;pm2 start&lt;/code&gt; command. By pulling the cache we get our &lt;code&gt;node_modules&lt;/code&gt; directory with our project dependencies.&lt;/p&gt;

&lt;p&gt;If you have followed correctly, you should end up with a file with these content&lt;/p&gt;

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

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build_stage&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy_stage&lt;/span&gt;

&lt;span class="na"&gt;.base-rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_BRANCH&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dev"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"push"'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_TAG&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;

&lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;global_cache&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CI_COMMIT_REF_SLUG&lt;/span&gt;
  &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull-push&lt;/span&gt;
  &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules/&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;package-lock.json&lt;/span&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build_stage&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.base-rules&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--version"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm i&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*global_cache&lt;/span&gt;
    &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;local_runner&lt;/span&gt;

&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy_stage&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.base-rules&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pm2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ecosystem.config.js"&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*global_cache&lt;/span&gt;
    &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;local_runner&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  💻 Install self-hosted runners on a linux server
&lt;/h2&gt;

&lt;p&gt;A little bit of background on runners, runners are like workers who does something that a computer should do. Like executing any commands or installing your project dependencies. Behind the scene they are docker containers provided by Gitlab. By default Gitlab uses a Ruby container but you can specify your container type. In this article though we will not use Gitlab's runners, we will install our own runner which is an open-source application made by Gitlab and maintained by the dev community. Self hosted runners are completely free so you don't have to worry about money 🤑.&lt;/p&gt;

&lt;p&gt;Installing the runner on your server is easy, you just have to run few commands. Visit this &lt;a href="https://docs.gitlab.com/runner/install/" rel="noopener noreferrer"&gt;page&lt;/a&gt; for instruction related to your OS environment. I'm running Ubuntu 20.10 so I'll follow with GNU/Linux Binary guide.. If you are using any debian machine then follow me.. Fire up your terminal and run the following commands..&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; /usr/local/bin/gitlab-runner &lt;span class="s2"&gt;"https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64"&lt;/span&gt;
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x /usr/local/bin/gitlab-runner
&lt;span class="nb"&gt;sudo &lt;/span&gt;useradd &lt;span class="nt"&gt;--comment&lt;/span&gt; &lt;span class="s1"&gt;'GitLab Runner'&lt;/span&gt; &lt;span class="nt"&gt;--create-home&lt;/span&gt; gitlab-runner &lt;span class="nt"&gt;--shell&lt;/span&gt; /bin/bash
&lt;span class="nb"&gt;sudo &lt;/span&gt;gitlab-runner &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gitlab-runner &lt;span class="nt"&gt;--working-directory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/gitlab-runner
&lt;span class="nb"&gt;sudo &lt;/span&gt;gitlab-runner start
&lt;span class="nb"&gt;sudo &lt;/span&gt;gitlab-runner status



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

&lt;/div&gt;

&lt;p&gt;Step by step we get the binary, give it executable permissions, create a user called &lt;strong&gt;gitlab-runner&lt;/strong&gt; to run the runners process and then start our gitlab-runner service. The gitlab-runner user is created for security purpose so that it doesn't run as root user. It is generally advised by people who are smarter than me and have was more knowledge about operating systems 😅.&lt;br&gt;
Now, after the last command you should see something like this&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47x27khsncbgu1cjqb3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47x27khsncbgu1cjqb3v.png" alt="Gitlab CI/CD + NodeJs + pm2 - Gitlab runner service is running"&gt;&lt;/a&gt; Again, it worked on my machine so I'm good! 😅. We are not done with this step though.. We have to login as the &lt;strong&gt;gitlab-runner&lt;/strong&gt; user and install node,  npm and pm2. I could not find any reference to what is the default password of gitlab-runner user so I will just reset it using the passwd command.&lt;/p&gt;

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

passwd gitlab-runner


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

&lt;/div&gt;

&lt;p&gt;Setup your new password and login as the gitlab-runner user by running &lt;code&gt;su gitlab-runner&lt;/code&gt;&lt;br&gt;
For install node I'm using &lt;strong&gt;nvm&lt;/strong&gt;. Just follow the same process mentioned below and you should have everything you need.&lt;/p&gt;

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

curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc


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

&lt;/div&gt;

&lt;p&gt;this should install nvm in you machine.&lt;br&gt;
Next, we install node and pm2 globally,&lt;/p&gt;

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

nvm install 16.13.2
npm i -g pm2


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  🔒 Register our local runner to Gitlab
&lt;/h2&gt;

&lt;p&gt;We are almost done with our setup..&lt;br&gt;
Now, we need to register our runner to Gitlab, to do this go to Setting &amp;gt; CI/CD in your repository and expand the "Runners" section.&lt;br&gt;
At the left side you should see "Specific runners" section.&lt;br&gt;
The token should look something like this "fy7f3BqhVzLq3Mr-xxxx"&lt;br&gt;
In your local machine or wherever you have installed you runner just run &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

sudo gitlab-runner register


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

&lt;/div&gt;

&lt;p&gt;This should prompt you to specify an instance URL. Type &lt;code&gt;https://gitlab.com&lt;/code&gt; and press enter.&lt;br&gt;
Then paste the registration token that you found on Gitlab and press enter, next provide a description for your runner&lt;br&gt;
the most important step, providing a tag for your runner or tags. In the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file I had mention the tags as &lt;strong&gt;local_runner&lt;/strong&gt; so I will put that here. You can add multiple tags separated by comma but that's not mandatory. Tags will identify the runners to do their job. At last choose &lt;strong&gt;shell&lt;/strong&gt; as the executor. The End? Not yet! :'(&lt;/p&gt;

&lt;h2&gt;
  
  
  🔑 Add environment variables to Gitlab
&lt;/h2&gt;

&lt;p&gt;Now we need to add env variable to Gitlab CI/CD section so that the we can provide a &lt;strong&gt;PORT&lt;/strong&gt; to our application. This is important because .env file is not commited to your version control. We add our env variable PORT under Setting &amp;gt; CI/CD &amp;gt; Variables section and we add the variable as protected. Next, super important - we need to make our dev branch as protected branch. Otherwise it won't fine the variables. You can do this from Settings &amp;gt; Repository &amp;gt; Protected branches section in your repo.&lt;/p&gt;

&lt;p&gt;✅ That is it, we are done with our pipeline setup. If everything is done correctly, when you commit a change on your dev branch it should trigger a pipeline with 2 job and you runner should start the pm2 process at 3001 port.&lt;/p&gt;

&lt;p&gt;Thanks for reading this article 🧑‍💻 If you face any problems, let me know in the comments down below! 🙂 &lt;br&gt;
Happy hacking!&lt;/p&gt;

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

</description>
      <category>webdev</category>
      <category>devops</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>How to use JsDoc annotations with VsCode for intellisense - PART 1 👨‍💻😎</title>
      <dc:creator>Suman Sarkar</dc:creator>
      <pubDate>Sun, 19 Sep 2021 16:08:54 +0000</pubDate>
      <link>https://dev.to/sumansarkar/how-to-use-jsdoc-annotations-with-vscode-for-intellisense-7co</link>
      <guid>https://dev.to/sumansarkar/how-to-use-jsdoc-annotations-with-vscode-for-intellisense-7co</guid>
      <description>&lt;h3&gt;
  
  
  The Problem 🤦‍♂️
&lt;/h3&gt;

&lt;p&gt;For many of us JavaScript devs, we love the fact that TypeScript exists. It has type hinting, type checking, helps with intellisense and many more. As a JavaScript developer you can start using TypeScript right now. But there is a catch that you cannot use TS in your favourite project without re-writing it and making it compatible for TS. But what if you want these goddies without going through the struggle of re-writing your entire application?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution 👨
&lt;/h3&gt;

&lt;p&gt;We can utilise JsDoc with VSCode to get all these feature without going through the hassle. For those of you who are not familiar with JsDoc and VsCode, JsDoc is an API documentation generator for JavaScript and VSCode or Visual Studio Code is microsoft's lighter version of it's legendary IDE Visual Studio. VSCode has excellent support for many programming languages and if you do not like using products that are managed by Microsoft then you will be happy to realise that VSCode is open source but if you still do not want any customisation made by Microsoft then you can use Code OSS&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's get started already 💁‍♂️
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/param"&gt;@param&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Now, Lets write it using JSDoc specs&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthalava.com%2Fuploads%2F1630747772.gif" alt="thalava.com - Sum of array with JSDoc"&gt;&lt;br&gt;
Excelente! 👍 You have typehinting in VSCode with the help of JsDoc. 

&lt;p&gt;&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/typedef"&gt;@typedef&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, lets write another example with custom data types. Here we'll work with moment JS&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Here, we are using @typedef to define custom type definations, in this case type Moment which is provided in the "moment" library and using it in the @param annotation to get type hinting. Notice when I type startDate, it suggest methods coming with a moment object.&lt;br&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthalava.com%2Fuploads%2F1630755623.gif" alt="thalava.com - Custom type defination using @typedef"&gt;

&lt;h3&gt;
  
  
  How do I create a custom type? 🤷‍♂️
&lt;/h3&gt;

&lt;p&gt;Its easy, you just have to know a little bit of TypeScript. Let me show you the directory structure.. It looks like this&lt;/p&gt;

&lt;p&gt;src&lt;br&gt;
 ┣ controllers&lt;br&gt;
 ┃ ┗ post.controller.js&lt;br&gt;
 ┗ models&lt;br&gt;
 ┃ ┣ post.model.d.ts&lt;br&gt;
 ┃ ┗ post.model.js&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The controller method is utilising PostModel and PostDocument type definations and suggesting the properties that are available.&lt;br&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthalava.com%2Fuploads%2F1630757699.gif" alt="thalava.com - Making custom types @typedef"&gt;&lt;br&gt;
The interfaces defined in post.model.d.ts defines your types and helps with suggestions. This is very useful because in mongoose static methods and schema properties does not appear normally in suggesions. So from now on you can import any type in your project and utilise it's definations.

&lt;p&gt;Note: In the example of moment js we saw that type definations were provided in the library itself but in case if it is not then chances are you will find the type definations in the npm repository. For example you can install type definations for the bcrypt library on @types/bcrypt&lt;/p&gt;

&lt;h3&gt;
  
  
  Enforcing correct types 🙅‍♂️
&lt;/h3&gt;

&lt;p&gt;In the moment JS example we passed 2 argument to getDiff function. How do we make sure that when executing this function we only pass 2 moment js object and not anything else. Well, there are 2 ways&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;@ts-check&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;@ts-check enables errors in your JavaScript files. In order to use it in a JavaScript file, you need to add it at the top of the file.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthalava.com%2Fuploads%2F1630759304.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthalava.com%2Fuploads%2F1630759304.png" alt="thalava.com - @ts-check"&gt;&lt;/a&gt;&lt;br&gt;
Notice how on line #17 VSCode is complaining that the type of the first argument passed is not correct.&lt;/p&gt;

&lt;h3&gt;
  
  
  VSCode Implicit Project Config ⚙
&lt;/h3&gt;

&lt;p&gt;You can enable this globally as well in your JS project by toggling &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"js/ts.implicitProjectConfig.checkJs": true&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is it, now you can utilise JSDoc and VSCode together for type hinting. Thanks for reading tutorial. We are hoping to update more tutorials like these very soon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools used in this tutorial
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Visual Studio Code (IDE)&lt;/li&gt;
&lt;li&gt;JsDoc (API documentation generator)&lt;/li&gt;
&lt;li&gt;Peek (Screen recorder)&lt;/li&gt;
&lt;li&gt;VSCode theme - GitHub Dark Default&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Part 2
&lt;/h3&gt;

&lt;p&gt;Part 2 of this tutorial is updated here - &lt;a href="https://thalava.com/how-to-use-jsdoc-annotations-with-vscode-for-intellisense-part-2" rel="noopener noreferrer"&gt;How to use JsDoc annotations with VsCode for intellisense - PART 2 👨‍💻😎&lt;/a&gt;&lt;br&gt;
In part 2 we discuss about &lt;em&gt;@callback&lt;/em&gt;, &lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/class"&gt;@class&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;@constructor&lt;/em&gt;, &lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/private"&gt;@private&lt;/a&gt;&lt;/em&gt; and &lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/public"&gt;@public&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  From author
&lt;/h3&gt;

&lt;p&gt;Before you leave, I just want to thank you for reading this article 🖤. Me and my friend started working on our own blog &lt;a href="//thalava.com"&gt;thalava.com&lt;/a&gt;&lt;br&gt;
Please visit our blog for more tutorials. We are excited to share more tutorials.&lt;br&gt;
Thanks again, love from &lt;a href="//thalava.com"&gt;thalava.com&lt;/a&gt; 🖤&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
