DEV Community

Cover image for Implementing CI/CD for ReactJS Projects: Gitlab + Slack
cuongnp
cuongnp

Posted on

Implementing CI/CD for ReactJS Projects: Gitlab + Slack

Scenario Overview

In my project, I have two primary servers: one for the development team and another for the Quality Control (QC) team. Each time a developer commits code, they need to build the project and commit the build files as a new commit on their branch. The build command used varies depending on the target environment, affecting the endpoints within the project.

To streamline this process, I set up a CI/CD pipeline using GitLab CI/CD, which automates the build and deployment steps and pushes the new commit to a dedicated deploy repository. Here's a step-by-step breakdown of the implemented workflow:

  1. Developer Commits Code: Developers commit their changes to the repository.
  2. Add Tag to Trigger CI/CD: To run the CI/CD pipeline, developers add a specific tag to their commit.
  3. CI/CD Pipeline Execution: The pipeline runs, building the project based on the tag.
  4. Push Build Artifact: The built artifacts are committed yo the deploy repository as a new commit.
  5. Slack Notification: A notification is sent to Slack upon successful deployment.

General idea

Prerequisites

  • ReactJS project
  • Define two build types in package.json: build-dev and build-qc
  • Two repositories: develop and deploy
  • Two branches in the deploy repo: feature/develop_deploy and feature/testing_develop
  • Slack channel webhook URL

Let's dive into it!

CI/CD Configuration

1. Install Stage

install_dependencies:
  stage: install
  image: node:latest
  script:
    - npm install --legacy-peer-deps
  rules:
    - if: '$CI_COMMIT_TAG =~ /^build-(dev|qc)-.*$/'
Enter fullscreen mode Exit fullscreen mode

Purpose: This stage installs all the necessary dependencies required for the project.

  • image: node: Specifies the Docker image to be used for this stage. Here, I use the latest Node.js image.
  • script: Contains the commands to be executed in this stage. In this case, it runs npm install --legacy-peer-deps to install the Node.js dependencies, allowing for compatibility with older peer dependencies.
  • rules: This specifies when the job should run. It uses a regular expression to check if the commit tag matches the pattern build-dev- or build-qc-, meaning this job runs only if such tags are present.

2. Build Stage

build_project:
  stage: build
  image: node:latest
  script:
    - echo "CI_COMMIT_TAG=$CI_COMMIT_TAG" 
    - >
      if [[ "$CI_COMMIT_TAG" == "build-dev"* ]]; then
        npm run build:dev
      elif [[ "$CI_COMMIT_TAG" == "build-qc"* ]]; then
        npm run build:qc
      else
        echo "No specific build command for this tag."
      fi
  artifacts:
    paths:
      - build/
    expire_in: 1 hour
  rules:
    - if: '$CI_COMMIT_TAG =~ /^build-(dev|qc)-.*$/'
Enter fullscreen mode Exit fullscreen mode

Purpose: This stage builds the project based on the environment specified by the tag.

  • image: node: Uses the latest Node.js image.
  • script: Executes the following commands:
    • echo "CI_COMMIT_TAG=$CI_COMMIT_TAG": Prints the commit tag to verify the tag.
    • The conditional block checks the tag:
      • If the tag starts with build-dev, it runs npm run build:dev.
      • If the tag starts with build-qc, it runs npm run build:qc.
      • Otherwise, it prints a message saying no specific build command is found for the tag.
  • artifacts: Specifies the files to be preserved after the job is done. Here, it keeps the build/ directory for 1 hour.
  • rules: Similar to the install stage, this job runs only if the commit tag matches the pattern build-dev- or build-qc-.

3: Deploy Stage

deploy_project:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk update && apk add git openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > private_key
    - chmod 600 private_key
    - ls -l private_key  # Verify the permissions
    - echo "$SSH_PRIVATE_KEY" | wc -c  # Check the length of the SSH_PRIVATE_KEY
    - ssh-add private_key
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
    - git config --global user.email "your email" 
    - git config --global user.name "your username" 
  script:
    - apk add --no-cache curl # Install curl
    - echo "Deploying the project... $CI_COMMIT_TAG"
    - BRANCH_NAME="feature/develop_deploy" # Default branch name
    - 'if [[ "$CI_COMMIT_TAG" == *qc* ]]; then BRANCH_NAME="feature/testing_deploy"; fi'

    - mkdir tmp_repo && cd tmp_repo
    - git clone deploy-repo .
    - echo "Checking out to $BRANCH_NAME"
    - git checkout $BRANCH_NAME  # Corrected to use the variable
    - cp -r ../build/* .
    - git add .
    - git diff --quiet --exit-code || git commit -m "Deploying artifacts from CI - $CI_COMMIT_TAG"
    - git push || echo "No changes to push."
    - >
      curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"Deployment of $CI_COMMIT_TAG completed successfully.\"}" "YOUR WEBHOOK URL"
  rules:
    - if: '$CI_COMMIT_TAG =~ /^build-(dev|qc)-.*/'

Enter fullscreen mode Exit fullscreen mode

Purpose: This stage deploys the built project to a remote repository and notifies the team via Slack.

  • image: alpine: Uses a lightweight Alpine Linux image.
  • before_script: Prepares the environment for deployment:
    • Installs necessary packages: git and openssh-client.
    • Sets up SSH for secure communication.
    • Adds the SSH private key.
    • Configures Git with user email and name.
  • script: Executes the deployment commands:
    • Installs curl.
    • Clones the deploy repository.
    • Checks out the branch feature/develop_deploy or feature/testing_deploy.
    • Copies the build artifacts to the repository.
    • Commits and pushes the changes.
    • Sends a Slack notification upon successful deployment.
  • rules: This job runs only if the commit tag matches the pattern build-dev- or build-qc-.

Pipeline 🚀🚀🚀

Result-Gitlab

Slack notification 🔈🔈🔈

slack-notification

Note

If you face the following error:

Agent pid 23
$ echo "$SSH_PRIVATE_KEY" | tr -d '\r' > private_key
$ cat private_key
$ ssh-add private_key
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'private_key' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.

Cleaning up project directory and file based variables

Enter fullscreen mode Exit fullscreen mode

Variable

  • Go to the setting of Gitlab -> CICD -> Variables -> Uncheck [Protect variable]

Final thought

This is just a simple idea for CI/CD. It can be improved further, so please leave your comments if you have any suggestions for improvement. Thanks for reading!

Top comments (0)