This content originally appeared on DEV Community and was authored by cuongnp
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:
- Developer Commits Code: Developers commit their changes to the repository.
- Add Tag to Trigger CI/CD: To run the CI/CD pipeline, developers add a specific tag to their commit.
- CI/CD Pipeline Execution: The pipeline runs, building the project based on the tag.
- Push Build Artifact: The built artifacts are committed yo the deploy repository as a new commit.
- Slack Notification: A notification is sent to Slack upon successful deployment.
Prerequisites
- ReactJS project
- Define two build types in package.json:
build-dev
andbuild-qc
- Two repositories: develop and deploy
- Two branches in the deploy repo:
feature/develop_deploy
andfeature/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)-.*$/'
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-
orbuild-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)-.*$/'
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 runsnpm run build:dev
. - If the tag starts with
build-qc
, it runsnpm run build:qc
. - Otherwise, it prints a message saying no specific build command is found for the tag.
- If the tag starts with
-
-
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 patternbuild-dev-
orbuild-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)-.*/'
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
andopenssh-client
. - Sets up SSH for secure communication.
- Adds the SSH private key.
- Configures Git with user email and name.
- Installs necessary packages:
-
script: Executes the deployment commands:
- Installs
curl
. - Clones the deploy repository.
- Checks out the branch
feature/develop_deploy
orfeature/testing_deploy
. - Copies the build artifacts to the repository.
- Commits and pushes the changes.
- Sends a Slack notification upon successful deployment.
- Installs
-
rules: This job runs only if the commit tag matches the pattern
build-dev-
orbuild-qc-
.
Pipeline 🚀🚀🚀
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
- 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!
This content originally appeared on DEV Community and was authored by cuongnp
cuongnp | Sciencx (2024-07-23T01:42:36+00:00) Implementing CI/CD for ReactJS Projects: Gitlab + Slack. Retrieved from https://www.scien.cx/2024/07/23/implementing-ci-cd-for-reactjs-projects-gitlab-slack/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.