angularbitbucketbitbucket-pipelines

Bitbucket Append build number to package.json during pipeline execution


I've an Angular project on a Bitbucket repository. I created this pipeline that deploys the application on AWS S3 and invalidate the CloudFront distribution. Everything works fine. I would like to add the build number to the published version in order to know not just the version of the application but also the build that generated it.

image: cypress/browsers:node14.17.0-chrome88-ff89
options:
  max-time: 120

pipelines:
  branches:   
    master:
      - step:
          runs-on:
            - 'self.hosted'
            - 'linux'
          size: 4x
          caches:
            - node          
          script:
            - npm install
            - npm install -g @angular/cli
            - npm run build-stage --progress=false
          artifacts:
            - dist/**
      - step:
          runs-on:
            - 'self.hosted'
            - 'linux'
          size: 4x
          name: Deploy on AWS S3 and CloudFront invalidation
          deployment: staging
          script:
            - pipe: atlassian/aws-s3-deploy:1.1.0
              variables:
                AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
                AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY               
                S3_BUCKET: 'xxxxxxx/dist'
                LOCAL_PATH: 'dist'
                DELETE_FLAG: 'true'
                DEBUG: 'true'
            - pipe: atlassian/aws-cloudfront-invalidate:0.6.0
              variables:
                AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
                AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY                
                DISTRIBUTION_ID: "xxxxxxx"
                PATHS: "/*"

definitions:
  caches:
    npm: $HOME/.npm
    cypress: $HOME/.cache/Cypress

and this is the initial part of my package.json:

{
  "name": "myApp",
  "version": "22.01.36"
}

I'd like the final version shown to the user is 22.01.36bxx (where xx is the Bitbucket build number). I think I just need a replacement in the package.json file. Do you have some suggestion to accomplish the "mission"?


Solution

  • The Bitbucket Pipelines yml file is just running Bash/shell commands on a Linux Docker machine. So you can use the normal Bash commands, like and , to do a "find and replace" inside a JSON text file.

    1. Generate the correct Regular Expression

    We need to write an expression that will search the text in a file for "version": "dd.dd.dd" and replace it with "version": "dd.dd.ddb123" , where "d" is a digit from 0-9.

    Use https://regex101.com to write and test a regex that does this. Here's a working expression and demo and an explanation: https://regex101.com/r/sRviUF/2

    Explanation:

    2. Write a Bash command to run the Regular Expression on a file, to search and replace

    Test and practice on a Linux or MacOS Terminal. Try the Linux Bash Shell on Windows 10, or use an online Linux Terminal or something similar.

    You will discover that the sed command cannot handle regexes with positive lookahead or negative lookahead, so we have to use perl instead. We also need to simulate the BITBUCKET_BUILD_NUMBER environment variable that is available on the Docker machine when the Pipeline is running.

    # Simulate the Bitbucket Pipelines build number in our local Terminal
    export BITBUCKET_BUILD_NUMBER=123
    
    # Create a JSON text file to test with
    # https://stackoverflow.com/questions/4662938/create-text-file-and-fill-it-using-bash
    
    cat > package.json <<EOF
    {
      "name": "myApp",
      "version": "22.01.36"
    }
    EOF
    
    # Copy the file to a backup
    cp package.json copy-package.json
    
    # Run the regex using Perl with inline replace. Use a fixed string "123" for the build number
    # https://stackoverflow.com/questions/12176026/whats-wrong-with-my-lookahead-regex-in-gnu-sed
    perl -pi -e 's/("version".*:.*"\d.*(?="))/${1}b123/g' package.json
    
    # Restore from the backup and test again
    cp copy-package.json package.json
    
    # Run the regex using Perl with inline replace. Use an environment variable for the build number
    # https://unix.stackexchange.com/questions/581295/using-bash-variable-in-perl-command-in-bash
    perl -pi -e 's/("version".*:.*"\d.*(?="))/${1}b$ENV{BITBUCKET_BUILD_NUMBER}/g' package.json
    
    # Verify the file is changed correctly
    cat package.json
    
    {
      "name": "myApp",
      "version": "22.01.36b123"
    }
    

    3. Add the Bash commands to the YML script

    pipelines:
      branches:
        master:
          - step:
              ...
              script:
                - npm install
                - npm install -g @angular/cli
                - npm run build-stage --progress=false
    
                # Get the path of the first 'package.json' which is closest to the root folder
                # https://stackoverflow.com/questions/5917576/sort-a-text-file-by-line-length-including-spaces
                - JSON_FILE_PATH=$(find "$(pwd -P)" -name package.json | awk '{ print length, $0 }' | sort -n -s | cut -d" " -f2- | head -1)
                - echo "BITBUCKET_BUILD_NUMBER = $BITBUCKET_BUILD_NUMBER"
                - echo "JSON_FILE_PATH = $JSON_FILE_PATH"
    
                # Debug: Print the original package.json
                - cat "$JSON_FILE_PATH"
    
                # Delete any existing 'bNNN' in the version string of package.json
                - perl -pi -e 's/b\d*"/"/g' "$JSON_FILE_PATH"
    
                # Modify the package.json to insert the $BITBUCKET_BUILD_NUMBER into the version string
                - perl -pi -e 's/("version".*:.*"\d.*(?="))/${1}b$ENV{BITBUCKET_BUILD_NUMBER}/g' "$JSON_FILE_PATH"
    
                # Debug: Print the modified package.json
                - cat "$JSON_FILE_PATH"
    
                # Possibly needed - Commit the modified package.json to Git
                - git commit -am "Add the BITBUCKET_BUILD_NUMBER into the 'version' in package.json [skip ci]"
                - git push