<?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: Josh Aguilar</title>
    <description>The latest articles on DEV Community by Josh Aguilar (@joshaguilar).</description>
    <link>https://dev.to/joshaguilar</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%2F349322%2Fac7fe40c-4d66-4634-95ac-23b671d2edc3.jpeg</url>
      <title>DEV Community: Josh Aguilar</title>
      <link>https://dev.to/joshaguilar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joshaguilar"/>
    <language>en</language>
    <item>
      <title>Fully automating npm package releases</title>
      <dc:creator>Josh Aguilar</dc:creator>
      <pubDate>Thu, 12 Mar 2020 05:34:27 +0000</pubDate>
      <link>https://dev.to/joshaguilar/fully-automating-npm-package-releases-3k7e</link>
      <guid>https://dev.to/joshaguilar/fully-automating-npm-package-releases-3k7e</guid>
      <description>&lt;p&gt;&lt;a href="https://i.giphy.com/media/CmFMWpEa4IFtS/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/CmFMWpEa4IFtS/giphy.gif" alt="Automation"&gt;&lt;/a&gt;&lt;/p&gt;
An "automated" npm release



&lt;h1&gt;
  
  
  Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Conventional commits&lt;/li&gt;
&lt;li&gt;Enforcing conventional commits&lt;/li&gt;
&lt;li&gt;Automating with semantic-release&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;One of the challenges when trying to automate npm package releases is &lt;a href="https://semver.org/"&gt;semantic versioning&lt;/a&gt;. It is quite common for developers to "manually" decide what the next version bump should be, which makes the decision biased and &lt;a href="http://sentimentalversioning.org/"&gt;sentimental&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The obvious way to remove that subjective bias is to automate the version bump and, to do this, we will need machine readable information in the codebase to help determine the next version. Enter conventional commits!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conventional commits &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;As described in the conventional commits website, it is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A specification for adding human and machine readable meaning to commit messages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It provides a set of rules for creating a commit history that can be easily used by automated tools such as a CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;Conventional commits should use the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;type&amp;gt;(optional scope): &amp;lt;description&amp;gt;

[optional body]

[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's a more concrete example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat(server): upgrade json parsing library

BREAKING CHANGE: replacing the library introduces a breaking change
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For now, all you need to know to get started are these conventions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fix&lt;/code&gt; commit type - indicates a bugfix and corresponds to a PATCH update&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;feat&lt;/code&gt; commit type - indicates an introduced feature and corresponds to a MINOR update&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BREAKING CHANGE:&lt;/code&gt; footer comment - indicates a breaking change  and corresponds to a MAJOR update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can learn more about the full specification for conventional commits on the &lt;a href="https://www.conventionalcommits.org/"&gt;Conventional Commits&lt;/a&gt; website.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enforcing conventional commits &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;There are many tools available to help with enforcing conventional commits in your codebase. In this example, we'll be using &lt;a href="https://github.com/typicode/husky"&gt;husky&lt;/a&gt; and &lt;a href="https://github.com/conventional-changelog/commitlint"&gt;commitlint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Install husky and commitlint by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; husky @commitlint/config-conventional @commitlint/cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then add the following configuration to your project's &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"commit-msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commitlint -E HUSKY_GIT_PARAMS"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now if you try adding a commit message that doesn't conform to the conventional commits spec, you will get an error message, and the commit will fail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s1"&gt;'some random commit'&lt;/span&gt;
husky &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; commit-msg &lt;span class="o"&gt;(&lt;/span&gt;node v12.16.1&lt;span class="o"&gt;)&lt;/span&gt;
⧗ input: some random commit
✖ subject may not be empty &lt;span class="o"&gt;[&lt;/span&gt;subject-empty]
✖ &lt;span class="nb"&gt;type &lt;/span&gt;may not be empty &lt;span class="o"&gt;[&lt;/span&gt;type-empty]
 
✖ found 2 problems, 0 warnings
ⓘ Get &lt;span class="nb"&gt;help&lt;/span&gt;: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Automating with semantic-release &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Now that your codebase is using conventional commits, you have a commit history that is machine readable, which means you can start automating your version updates and release.&lt;/p&gt;

&lt;p&gt;Again, there are numerous tools out there that help facilitate this, but we've chosen &lt;a href="https://github.com/semantic-release/semantic-release"&gt;semantic-release&lt;/a&gt; and &lt;a href="https://help.github.com/en/actions"&gt;GitHub Actions&lt;/a&gt; as an example.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;semantic-release&lt;/strong&gt; automates the whole package release workflow including: determining the next version number, generating the release notes and publishing the package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Feel free to read more about these tools in the official documentation as the following examples are very basic.&lt;/p&gt;

&lt;p&gt;To get started, install semantic-release first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; semantic-release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, add the following to the scripts section of your &lt;code&gt;package.json&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"semantic-release"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"semantic-release"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can test if versioning works by running semantic-release in dry-run mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run semantic-release &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, let's set up our Github Action workflow. Add a new directory in your project's codebase called &lt;code&gt;.github/workflows&lt;/code&gt;. In this directory, add a new YAML file, &lt;code&gt;build.yml&lt;/code&gt; with the following contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;audit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Git checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12.x&lt;/span&gt;

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

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

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Package&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;github.ref == 'refs/heads/master'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run semantic-release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will create a GitHub Action workflow called &lt;code&gt;Build&lt;/code&gt; which will be triggered every time you push a commit to GitHub. The workflow will go through the following steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spin up a docker container with Ubuntu.&lt;/li&gt;
&lt;li&gt;Install Node.js&lt;/li&gt;
&lt;li&gt;Check out the git repo.&lt;/li&gt;
&lt;li&gt;Install the npm dependencies for the project.&lt;/li&gt;
&lt;li&gt;Run tests.&lt;/li&gt;
&lt;li&gt;Execute semantic-release if the current branch is &lt;code&gt;master&lt;/code&gt;. This step will essentially do the following tasks.

&lt;ul&gt;
&lt;li&gt;Automatically determine the next version using information gathered from commit messages&lt;/li&gt;
&lt;li&gt;Bump the version up in package.json&lt;/li&gt;
&lt;li&gt;Publish the package to the registry&lt;/li&gt;
&lt;li&gt;Create a new tag/release on GitHub&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There you have it! Your npm release is now fully automated!&lt;/p&gt;

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

&lt;p&gt;As we mentioned before, one of the biggest challenges with automating semantic versioning is finding a way to have machine readable information that automation tools can use to determine version updates.&lt;/p&gt;

&lt;p&gt;We established that Conventional Commits would be able to address this by providing a structure that would allow both humans and machines to objectively determine the "extent" of the changes included in the new version.&lt;/p&gt;

&lt;p&gt;You can use whatever tools best suit your project but here are some that have proven to be quite useful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/typicode/husky"&gt;husky&lt;/a&gt; for commit hooks&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/conventional-changelog/commitlint"&gt;commitlint&lt;/a&gt; for enforcing conventional commit messages&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/semantic-release/semantic-release"&gt;semantic-release&lt;/a&gt; for full automation of versioning and releasing of npm packages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope this post was helpful! I'm also keen to hear your ideas on the topic so feel free to comment.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>javascript</category>
      <category>node</category>
      <category>semver</category>
    </item>
  </channel>
</rss>
