Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to go about implementing semantic versioning with bitbucket pipelines and branches?

I have a python app and I want to implement semantic versioning as such: MAJOR.MINOR.PATCH.BUILD. I want to automate it as much as possible through bitbucket pipelines.

I will answer my own question below to share with others how I did this due to the scarcity of blogposts/ resources out there.

like image 558
Ludo Avatar asked May 16 '18 12:05

Ludo


People also ask

How do I run a bitbucket pipeline on a specific branch?

Go to Repository settings -> Pipelines | Settings -> Enable Pipelines. Then you will have to push another change to the branch with the bitbucket-pipelines. yml and it should run the pipeline.

Does bitbucket have CI CD pipeline?

Bitbucket Pipelines is an integrated CI/CD service built into Bitbucket. It allows you to automatically build, test, and even deploy your code based on a configuration file in your repository.


Video Answer


1 Answers

All the relevant files are included below, but here is the gist of it. I have a master branch from which I make various feature branches before merging to master. I have marked every merge to master branch as a minor update. This is fully automated via the code below. Build number is also automated and updated with every new commit regardless of which branch I am on. Finally, patch numbers and major number updates are semi-automatic via a trigger in BB pipelines.

I store the version number in a version.txt file and every build I update the number and run a commit and push from within that build, but skip the build process for that secondary commit using [skip CI] or it would loop infinitely. Happy to explain anything further if need be.

Part of the version.sh script was sourced from an answer on linux - simplify semantic versioning script

This is what my bitbucket-pipelines.yml file looks like:

image: python:3.6

pipelines:
  default:
    - step:
        script: # Modify the commands below to build your repository.
          # Linting check
          - pip3 --version
          - pip3 install -r requirements.txt
          - pylint backend
          - bash version.sh build $BITBUCKET_BUILD_NUMBER $BB_AUTH_STRING

  branches:
    master:
      -step:
        name: Minor version update
        script:
          # Linting check
          - pip3 --version
          - pip3 install -r requirements.txt
          - pylint backend
          # Increase minor version number
          - bash version.sh minor $BITBUCKET_BUILD_NUMBER $BB_AUTH_STRING
      -step:
        trigger: manual
        name: Major version update
        script:
          - bash version.sh major $BITBUCKET_BUILD_NUMBER $BB_AUTH_STRING
      -step:
        trigger: manual
        name: Patch version update
        script:
          - bash version.sh patch $BITBUCKET_BUILD_NUMBER $BB_AUTH_STRING

and version.sh:

#!/bin/bash

#CONFIG
USER=""
REPO=""
USERNAME=""
EMAIL=""

major() {
if IFS=. read -r major rest <version.txt || [ -n "$major" ]; then
  echo "$((major + 1)).0.0.$1" >"version.txt"
else
  echo "ERROR: Unable to read version number from version.txt" >&2
  exit 1
fi
}

minor() {
if IFS=. read -r major minor patch build <version.txt || [ -n "$major" ]; then
  echo "$major.$((minor + 1)).0.$1" >"version.txt"
else
  echo "ERROR: Unable to read version number from version.txt" >&2
  exit 1
fi
}

# Need to substract one from minor because automatically runs
patch() {
if IFS=. read -r major minor patch build <version.txt || [ -n "$major" ]; then
  echo "$major.$((minor - 1)).$((patch + 1)).$1" >"version.txt"
else
  echo "ERROR: Unable to read version number from version.txt" >&2
  exit 1
fi
}

build() {
if IFS=. read -r major minor patch build <version.txt || [ -n "$major" ]; then
  echo "$major.$minor.$patch.$1" >"version.txt"
else
  echo "ERROR: Unable to read version number from version.txt" >&2
  exit 1
fi
}

update() {
echo "New version = $(<version.txt)"
git config --global push.default simple
git remote set-url origin https://${1}@bitbucket.org/${USER}/${REPO}.git
git config user.name $USERNAME
git config user.email $EMAIL
git config -l
git add version.txt
git commit -m "[skip CI]"
git push
}

case "$1" in
  major)
    major $2
    update $3
    ;;
  minor)
    minor $2 
    update $3
    ;;
  patch)
    patch $2
    update $3
    ;;
  build)
    build $2
    update $3
    ;;
  *)
    echo "Usage: bash version.sh {major|minor|patch|build} build_number bb_auth_string"
    exit 1
esac
exit 0

Finally version.txt is a simple text file with four numbers separated by a dot such as 4.3.2.1

Happy to take any suggestions on how to improve my method of doing this.

like image 147
Ludo Avatar answered Sep 28 '22 12:09

Ludo