Things to know:

Releasing your first Open Source JavaScript plugin/software/etc can be a daunting task, especially if you want to do it properly and by the books.

I will try to share what I managed to gather these past few days, as I was banging my head against the keyboard with all these terminologies, cli tools and what not…

Disclaimer: This is NOT a super detailed, beginner friendly guide. This is more towards people who are at least a bit familiar with git and npm. If you are a newb, you should definitely  check out Atlassians or Githubs tutorials on how to use Git. Npm has some simple guides on, well.., npm as well.

Decent release strategy:

A decent and fairly common release practice is to follow semver versioning. I will not explain what semver is, there are more than enough articles about that. In short, that e.g2.3.1 version we see in almost all software these days, with the first one being a Major release, second a minor, third a patch.

Depending on your release type, its common practice to do GitHub releases with proper release notes. That helps people quickly get a grasp on changes to your codebase so that they can quickly get about updating/fixing/installing your code’s latest version.

Also a well maintained CHANGELOG.md is also a good way to know what is going on. But maintaining this is hard as f#$k… Well if you follow the conventional-commit spec its not that hard at all. This is where commitizen comes in handy. It helps you write good, well structured commit messages in a few standards, but we are interested in the Angular one.

Waaaait now, hold on … I dont use Angular! Who are you trying to fool??

Neither do I.. I’m a Vue.js guy, and thats exactly what I thought in the first place, pf.. Angular… But let me explain.

The Angular commit convention is s really nice way of structuring your commit messages so that CLI tools can later scan them and build well structured recaps of your work (what conventional-changelog is for). Those snippets get inserted into CHANGELOG.md or even automatically into a fresh GitHub Release notes, now how cool is that? You can find more info over at https://github.com/commitizen/cz-cli

Getting prepped:

You will need these tools installed on your pc, globally or locally its up to you, I installed them globally.

I will explain really briefly what each of them does:

git-flow – This is a really nice cli tool that helps you follow simple git branching convention. For each feature/release/hotfix you do a branch and work on that branch. Master branch is only for working, fully tested code, development branch is for your daily updates etc.. Done. Wasn’t that bad now was it? Well there is more, but you can look at the cheat sheet linked above to figure them out. Git-flow takes care of all the branching, merging, checking out etc… You just focus on code.

standard-version – This was a bit tricky. There is a whole family of tools called conventional-*insert-something-here* that helps you achieve а well structured changelog and package versioning based on the commit messages you have done.

But you mentioned standard-version… what is this conventional thing?

Ah yes.. you see, they have actually recently migrated to a new repository with more structured tool chain. There is:

  • conventional-changelog that just generates your changelog. Cool if you only need that. It can be called from node code and etc.
  • conventional-github-releaser which does what it says, takes your recent commit messages and does a github release with pretty summary for you.
  • conventional-changelog-cli that is just a command line tool that does what conventional-changelog does.
  • standard-version – A more all in one tool that generates changelog, tags your release, bumps npm/bower versions etc. As the author says, its like semantic-release but without pushing to the server. What is semantic-release? Well…. its for another time, lets start with these OK?
  • others – there are even more but… you can check em out your self.

commitizen – Commitizen is a really nice tool to help you write commit messages in a few standards.  We will focus on writing in the Angular convention, as stated in the first part of this post. Our posts will be comprised of a <type>(<scope>): <subject>. Type is the type of change we did, for example: feature, docs, fix etc… Scope is well.. the scope of the change, be it login, register, shop.. you get it. Its optional. Subject is the short description of the commit. Fore more, please read the Commitizen README or the Angular Contribute guide

Lets get things initialized:

First things first, we need a repo ready and the tools mentioned above installed.

Then we start initializing the tools.

Commitizen needs 1 command to init

commitizen init cz-conventional-changelog --save-dev --save-exact

then insert the lines bellow in your package.json

"config": {
   "commitizen": {
      "path": "cz-conventional-changelog"
   }
}

That is it. Commitizen is now ready. We can now do git-cz to commit instead of git commit. You can also assign an alias in your command line to gcz like I did. If you install it locally, you can add “commit”:”git-cz” so that your contributors can run npm run commit  or yarn commit

Git-flow is just as easy to initialize, just run the command bellow and follow the instructions. I left everything to default.

git flow init

standard-version  does not need any initialization.

Now add these lines in your package.json

   "scripts": {
       "commit": "git-cz",
       "release": "standard-version -a",
       "postrelease": "git push --follow-tags",
       "post-release": "conventional-github-releaser -p angular" 
   }

 

The workflow:

So our workflow is like this:

  1. Use git-flow to start working on features git flow feature start my-feature
  2. Code like you normally do, commit with git-cz. Try to follow the conventions.
  3. When you are done with a feature git flow feature finish my-feature
  4. If you think its time to do a release, just run npm run release and it will extract all your commit messages, structure them into `changelog.md`, make a git tag and push to git.

NOTE: If you DO NOT want to automatically push to git, remove the postrelease hook from the scripts. That will leave you to push when you feel like it. Just dont forget to push your tags --follow-tags

If you are just bugfixing, refactoring, just work on development branch, no need for a whole new branch. Using git-cz is still mandatory.

You can do releases without doing a git flow release start release-name and for minor ones I guess its fine because standard-version will take care of things. If you plan on doing a major one though, I think its good to do it in a new branch, like gitflow suggests, keeps things separated and clear, but there is a catch. Git-flow will try to tag the new release with the name that you give the release, that is not bad, its just that it will add an extra tag, cluttering your tags, because standard-version will add a new semantically versioned one as well. The cure is to do major releases with:

git flow release start release-name -n

-n just tells it to skip the tag.

NOTE: standard-version will do a major bump by it self ONLY if it detects a breaking-change

Bonus points:

You might want a script that runs and inserts your new pretty package version in some script banners, md files etc. This is where lifecycle hooks come in handy.

"standard-version": {
    "scripts": {
      "postchangelog": "node version.js &amp;&amp; git add -A"
    }
  }

What version.js does is, it scans my readme.md and other similar files and updates all my version references. Then stages then in git to be committed. I might have done it better, but it works for me at this point.

const fs = require('fs')
const pack = require('./package.json')

const readme = fs
  .readFileSync('./README.md', 'utf-8')
  .replace(
    /<small>[\d.]+.[\d]+<\/small>/,
    '<small>' + pack.version + '</small>'
  )
fs.writeFileSync('./README.md', readme)

You could also do a build on your files in the postbump hook, this way your build process can read the latest package version and implement it in your scripts.

 "standard-version": {
    "scripts": {
      "postchangelog": "node version.js && git add README.md",
      "postbump": "node build.js" // or use webpack, rollup, what ever you decide. Delete this comment if you copy/paste.
    }
  }

A cool nifty feature is also to do an automatic release on GitHub. This is done with the conventional-github-releaser. What it does is it just does an http request to GitHub with your credentials via a token, it creates a release on your latest tag with the release notes the same as the ones that just got inserted in the CHANGELOG.md. For more info on how that works, you can look at the conventional-github-releaser page.

Validate-commit-message – is a cool way to validate your commit messages, if for example your contributors don’t use commitizen (git-cz). It uses githooks to validate, but it recommends using Husky which is another helper. Yes I know, another one …but well, if you are into JS, you should be used to this about now. I am not going into details here, its fairly easy to figure out things for your self.