<?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: Edward Chopuryan</title>
    <description>The latest articles on DEV Community by Edward Chopuryan (@edward93).</description>
    <link>https://dev.to/edward93</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%2F224072%2Ffab4199f-1581-40d8-b862-185c3fcd4270.png</url>
      <title>DEV Community: Edward Chopuryan</title>
      <link>https://dev.to/edward93</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edward93"/>
    <language>en</language>
    <item>
      <title>Jenkins + npm package is [not] a good idea</title>
      <dc:creator>Edward Chopuryan</dc:creator>
      <pubDate>Mon, 30 Sep 2019 18:04:00 +0000</pubDate>
      <link>https://dev.to/edward93/jenkins-npm-package-is-not-a-good-idea-1ifp</link>
      <guid>https://dev.to/edward93/jenkins-npm-package-is-not-a-good-idea-1ifp</guid>
      <description>&lt;h2&gt;
  
  
  Prologue
&lt;/h2&gt;

&lt;p&gt;Automating &lt;strong&gt;npm package&lt;/strong&gt; deployment (&lt;strong&gt;C&lt;/strong&gt;ontinues &lt;strong&gt;D&lt;/strong&gt;eployment) is a good practice but not an easy one especially the combination of &lt;strong&gt;jenkins&lt;/strong&gt; and &lt;strong&gt;npm package&lt;/strong&gt;. &lt;br&gt;
During my latest project I was developing an &lt;strong&gt;npm package&lt;/strong&gt; that was going to be used by multiple teams and projects across the entire company. After a week or two of development we decided that we are ready to publish our first version and that we are going to need a CI/CD pipeline to push the package into our local &lt;strong&gt;registery&lt;/strong&gt;. Our pipeline was very simple and had only 4 stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initialization&lt;/strong&gt; - In this stage we simply build our application: &lt;code&gt;npm ci&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt; - In this is stage we run the tests and check the coverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; - This builds the project and prepares it for a publish(&lt;code&gt;npm run build&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; - This stage simply runs the following command: &lt;code&gt;npm publish&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;If you are anything like me you are going to forget to update the version of your package and push your changes and since our &lt;strong&gt;Jenkins&lt;/strong&gt; doesn't check the version it will give a green light to merge your branch and when you do it is going to fail. Why? because we forgot to update the version and when &lt;code&gt;npm&lt;/code&gt; wants to perform &lt;strong&gt;publish&lt;/strong&gt; it fails. &lt;br&gt;
  I personally encountered this many times and it was getting very frustrating and expensive because I broke 2 keyboards, 3 mugs and someone's skull (apparently mine). Anyway there are many solutions to this problem here is one that I really liked and implemented personally.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Idea is to check the version before &lt;strong&gt;Jenkins&lt;/strong&gt; reaches that last &lt;strong&gt;Publish&lt;/strong&gt; stage.&lt;br&gt;
&lt;strong&gt;Jenkinsfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;   &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Version Check'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s2"&gt;"chmod 777 config/version_check.sh"&lt;/span&gt;
          &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s2"&gt;"config/version_check.sh"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;config/versoin_check.sh&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-exuo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;LOCAL_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;node &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"require('./package.json').version"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;REMOTE_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;npm view &lt;span class="nb"&gt;.&lt;/span&gt; version&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LOCAL_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REMOTE_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Package with v&lt;/span&gt;&lt;span class="nv"&gt;$LOCAL_VERSION&lt;/span&gt;&lt;span class="s2"&gt; already exists"&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This new stage is coming right after the very first &lt;strong&gt;Initialization&lt;/strong&gt; stage so now our &lt;code&gt;Jenkins pipeline&lt;/code&gt; has this &lt;strong&gt;5&lt;/strong&gt; stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initialization&lt;/strong&gt; - In this stage we simply build our application: &lt;code&gt;npm ci&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version Check&lt;/strong&gt; - &lt;em&gt;In this stage we are verifying our version&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Tests&lt;/strong&gt; - In this is stage we run the tests and check the coverage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; - This builds the project and prepares it for a publish(&lt;code&gt;npm run build&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; - This stage simply runs the following command: &lt;code&gt;npm publish&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script that performs the version check is quite simple just make sure that &lt;strong&gt;Jenkins&lt;/strong&gt; is using a container that has &lt;strong&gt;node&lt;/strong&gt; installed or use &lt;code&gt;node&lt;/code&gt; agent for this stage and don't forget to make the script &lt;strong&gt;executable&lt;/strong&gt; (&lt;code&gt;sh "chmod 777 config/version_check.sh"&lt;/code&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations &amp;amp; Further Improvements
&lt;/h2&gt;

&lt;p&gt;This solution is not perfect just like any other "solution". First things first it doesn't check all remote versions only the latest one which is not ideal we want to be sure our local &lt;strong&gt;version&lt;/strong&gt; is unique across all published versions. Fortunately it is possible to get all version numbers of published package and check against the list. &lt;/p&gt;

&lt;p&gt;Yet another issue is that our code doesn't perform any kind of &lt;strong&gt;validation&lt;/strong&gt; to make sure that our version number is compliant to &lt;a href="https://semver.org/"&gt;Semantic v2.0.0&lt;/a&gt; standards. Fortunately there are some good &lt;strong&gt;npm packages&lt;/strong&gt; to perform those validations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you
&lt;/h2&gt;

&lt;p&gt;Thank you for reading this article. Hope it can help someone and if you have any questions or suggestions let's talk about it in the comments below.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>npm</category>
      <category>jenkins</category>
    </item>
  </channel>
</rss>
