npm version control using semantic-release and bitbucket cloud

Natalie P
coding spaghetti
Published in
7 min readJan 28, 2019

Goal: to have semantic version and npm publish handled automatically via my bitbucketpipeline

After creating a bitbucket code repo, and successfully publishing it to npm using npm publish I wanted to have the semantic version and publising done automatically when I commit.

Tools I used included:

  • commitizen, cz-conventional-changelog
  • semantic-release, @semantic-release/changelog, @semantic-release/commit-analyzer, @semantic-release/git,
    @semantic-release/npm, @semantic-release/release-notes-generator
  • bitbucket pipelines

Semantic Version

Semantic version, also known as SemVer, is where your version number is in the form of MAJOR.MINOR.PATCH ex: 2.3.6

MAJOR version when you make incompatible API changes,

MINOR version when you add functionality in a backwards-compatible manner, and

PATCH version when you make backwards-compatible bug fixes.

If you make a breaking change your MAJOR number should increase.

If you make a feature change that won’t break your user’s functionality if download the change then only the MINOR number should increase.

If you are making bug fixes then the patch number will increase.

Document changes do not affect your version number.

commitizen

commitizen with cz-conventional-changelog questions

commitizen is a git commit tool, that allows you to use a prompt that will end up writing your commit message and description for you.

cz-conventional-changelog, is a template of the questions you’ll be asked when you make a commit. You can install other available templates.

To get started install commitizen globally on your computer:

npm install -g commitizen

git cz and git commit will now both do the same thing, the only difference is that if you have a project with a commitizen compatable changelog npm package, it will go through the changelog prompt

If you use npm 5.2+:

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

this adds some script to your package.json

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

then manually add to your package.json

"scripts": {
"commit": "git-cz"
},

now when you run npm run commit it will do follow the template prompt of your changelog and generate a git commit message. You could justs run git-cz, but npm run commit is easier to remember.

So the flow would be to add the files you want for commit, run git-cz, and git push

git add . 
npm run commit
... //go through your changeloggit push

What you’ll get if you used the cz-conventional-changelog :

cz-conventional-changelog commit output

Your commit message will have this format type(scope):short description

Your commit will then have the following description:

long description
BREAKING CHANGE: breaking change description
issue number link

Note: BREAKING CHANGE only shows up if answered yes to a breaking change.

Note: Issue number only appears, if you answered that yes to the question Does this change affect any open issues? and then passed the issueId.

Since I’m using bitbucket, my issue id auto creates a link to my Jira ticket https://<domain>.atlassian.net/browse/<ticketId>. When I click the link, it will automatically open the appropriate issue ticket in a modal.

Now that we’ve ensured a commit standard, we can use semantic release to read through your commit messages and update our package version number and publish to NPM.

Semantic Release

Documentation for semantic-release can be found here.

npm install --save-dev semantic-release

install other required packages

npm install --save-dev @semantic-release/commit-analyzer @semantic-release/release-notes-generator @semantic-release/npm @semantic-release/changelog @semantic-release/git

Add the following to your package.json

"release": {
"repositoryUrl": "https://auth@bitbucket.org/<BITBUCKET_REPO_OWNER>/<BITBUCKET_REPO_SLUG>.git",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
"@semantic-release/changelog",
"@semantic-release/git"
]
},

note: you need to change <BITBUCKET_REPO_OWNER> and <BITBUCKET_REPO_SLUG> to match your project repo. (If you try and clone your repository, the last two sections of your path make up the repo owner and the repo slug.)

Ex: git clone https://username@bitbucket.org/blahblah/sampleproject.git

the BITBUCKET_REPO_OWNER is blahblah and BITBUCKET_REPO_SLUG is sampleproject

We now need to setup our credentials to:

  1. enable bitbucket piplines for our repo
  2. allow bitbucket to publish to its own repo
  3. to publish to npm

Semantic-release configuration documentation is found here. We’ll need to set variables for BB_TOKEN, NPM_TOKEN .

Setting up Bitbucket Pipeline

create a bitbucket-pipelines.yml

touch bitbucket-pipelines.yml

See documentation bitbucket pipeline configurations options here. Npm for bitbucket documenations are available here (you will be able to find a default bitbucket-pipelines.yml).

My bitbucket-pipelines.yml looks like:

image: node:latest

pipelines:
branches:
master:
- step:
caches:
- node
script:
# Get an oauth access token using the client credentials, parsing out the token with jq.
- apt-get update && apt-get install -y curl jq
- >
export BB_TOKEN=$(curl -s -X POST -u "${CLIENT_ID}:${CLIENT_SECRET}" \
https://bitbucket.org/site/oauth2/access_token \
-d grant_type=client_credentials -d scopes="repository"| jq --raw-output '.access_token')
# Configure git to use the oauth token. This well happen when setting env variable BB_TOKEN
- npm install
- rm -rf ./build && npm run build
# if you have test script in your package.json
- npm run test
- npx semantic-release --debug

once you commit the bitbucket-pipelines.yml file you will be able to go-to settings>pipelines and enable your bitbucket pipeline.

Note: my package.json contains a build script for webpack and publishes to ./build hence the reason i run rm -rf ./build && npm run build

"scripts": {
"build": "webpack --mode production"
},

Bitbucket Cloud Publishing to Own Repo using Semantic-Release

I spent hours googling how to get this to work with semantic-release.

According to this article your pipeline is supposedly able to publish to itself, however I was unable to.

I tried using the project SSH key, and access key (also known as deployment key). The difference between the two is nicely shown here.

Your project access key (also known as the deployment key) does not have write abilities, even if you give all the permissions possible. You’ll get “repository access denied. access via a deployment key is read-only.”

Also there are no personal access tokens in bitbucket cloud. See here.

I ended up having to use access tokens mentioned under Oauth.

Create an OAuth by going to your avatar > Bitbucket settings > OAuth and click Add consumer.

Give your Oauth a name, copy and paste https://bitbucket.org/site/oauth2/authorize?client_id={client_id}&response_type=token into the Callback URL exactly as is with the brackets and all.

setting 0Auth pipeline callback url

{client_id} will refer to the oauth client key you will create below.

Give repository read and write permissions:

Bitbucket Consumer Oauth Permission Settings

If you open your OAuth consumer details you will find your consumer key and secret. Here is one I generated as an example of what you expect to see:

Bitbucket Consumer OAuth Key and Secret

Add it to your bitbucket pipeline variables.

Under bitbucket Settings > pipelines > repository variable where CLIENT_ID is the value from key and CLIENT_SECRET is the value from secret

Make sure to lock your values, so they aren’t visible.

This value gets passed to BB_TOKEN needed by semantic-release via the script shown before in bitbucket-pipelines.yml. This was the code that did that:

export BB_TOKEN=$(curl -s -X POST -u "${CLIENT_ID}:${CLIENT_SECRET}" \
https://bitbucket.org/site/oauth2/access_token \
-d grant_type=client_credentials -d scopes="repository"| jq --raw-output '.access_token')

Create npm token

To publish to npm you’ll need to create and npm token using npm-token. Run:

npm token create

example npm token create output

Copy the token variable and add it your Settings > pipelines > repository variable with the name NPM_TOKEN. Make sure to lock your value, so no one can see it’s value.

Setup Finished

So now when you run npm run commit and push your changes, you will

  • have a standard git commit message
  • get bitbucket pipelines to run semantic-release
  • If semantic -release see’s the words BREAKING CHANGE, it will increase the MAJOR number of your package.json
  • it will push the change to your repo using your Oauth credentials and then publish to npm
semantic-release commit example

Note: I noticed I often forgot to pull changes when committing, so I modified my commit script in package.json to check if my branch was behind, if so, it would give me a warning instead of running git-cz

"commit": "changed=0 \ngit remote update && git status -uno | grep -q 'Your branch is behind' && changed=1\nif [ $changed = 1 ]; then\n    echo \"***WARNING***\n pull latest\";\nelse\n git-cz\nfi",

Viola you’ve got automated package management versioning and commit setup.

--

--