npm version control using semantic-release and bitbucket cloud
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 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:
- enable bitbucket piplines for our repo
- allow bitbucket to publish to its own repo
- 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.
{client_id} will refer to the oauth client key you will create below.
Give repository read and write permissions:
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:
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
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
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.