DEV Community

Cover image for Leveling Up CI/CD: Automated Versioning and the Leap to AWS
Zakariyau Mukhtar
Zakariyau Mukhtar

Posted on

Leveling Up CI/CD: Automated Versioning and the Leap to AWS

This week has been all about refining the continuous integration and continuous deployment (CI/CD) pipeline. After successfully containerizing a Node.js application and pushing it to Docker Hub, it was time to tackle a crucial DevOps practice: Automated Versioning.

Here is a breakdown of what I implemented this week, the hurdles I overcame, and what is next on the roadmap.

Demystifying Semantic Versioning (SemVer)

Before automating anything, it is essential to understand how application versions are structured. A standard version number is broken down into three parts:

  • Major Version: Contains big changes that are not backward-compatible.
  • Minor Version: Introduces new API features but remains backward-compatible.
  • Patch: Dedicated strictly to minor changes and bug fixes without altering the API.

Build tools come equipped with commands to increase these versions dynamically during the build process, which is exactly what I integrated into the Jenkins pipeline.

The Automated Versioning Pipeline

The goal for this module was straightforward: Increment Version $\rightarrow$ Build App $\rightarrow$ Build Image $\rightarrow$ Push to Docker Repo.

To achieve this, I updated the Jenkinsfile to run npm version patch --no-git-tag-version. This command dynamically extracts the new version (e.g., bumping 1.0.1 to 1.0.2), which I then stored as an environment variable (env.IMAGE_NAME) to tag the newly packaged Docker image automatically.

The "Local vs. Remote" Challenge

During implementation, I ran into a classic CI/CD hurdle. When the Jenkins pipeline ran the npm version command, the new version was only updated locally within the Jenkins workspace. It did not update the actual source code repository on GitHub. This meant every subsequent build would pull the old version number from the repo, causing an endless overwrite loop.

The Solution:
The fix required adding a dedicated Git stage to the end of the pipeline. By securely injecting GitHub credentials into the workspace, Jenkins now automatically stages the modified package.json and package-lock.json files and pushes the updated version directly back to the main branch.

Here is the stage that handles this synchronization:

stage('Updating to Github'){
    steps{
        script{
            echo 'Updating the Github repo with the latest version....'
            withCredentials([usernamePassword(credentialsId: 'github.credentials', passwordVariable: 'PASS', usernameVariable: 'USER')]) {
                sh 'git config user.email "jenkins@example.com"'
                sh 'git config user.name "jenkins"' 
                sh 'git remote set-url origin https://${USER}:${PASS}@github.com/AlAfiz/Devops-app.git'
                sh 'git add package.json package-lock.json'
                sh 'git commit -m "feat: update the github repo with the latest version"'
                sh 'git push origin HEAD:main'
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Note: I also made sure to implement a Clean Workspace step (rm -f *.tgz) at the very beginning of the pipeline to prevent old artifact tarballs from getting swallowed up in the new builds!

What's Next: Infrastructure as a Service (AWS)

With a robust, self-versioning pipeline now fully operational, I am officially shifting gears into a brand new module: AWS Services.

Understanding Infrastructure as a Service (IaaS) is the next major milestone. Over the coming weeks, the focus will be on:

  • Managing users and permissions with AWS IAM.
  • Understanding Regions and Availability Zones.
  • Configuring private networks using VPCs.
  • Creating virtual servers via EC2.
  • Connecting the Jenkins pipeline to continuously deploy directly to an EC2 instance!

The journey from a local environment to the cloud is underway. Stay tuned!

Top comments (0)