Compare commits

...

39 Commits

Author SHA1 Message Date
thienqb123456 186eada028 Thienvv - bỏ telegram , đổi sang slack 2025-05-26 15:30:18 +07:00
thienqb123456 282e6436c8 Thienvv - 2025-05-26 14:59:53 +07:00
thienqb123456 4f3efba232 Thienvv - bo tele 2025-05-26 10:00:04 +07:00
thienqb123456 f39fa26ba8 sua cicd 2025-03-28 19:25:51 +07:00
thienqb123456 57bc24c792 Thienvv - tach branch part 6 2025-03-13 08:47:24 +07:00
thienqb123456 80f0a992b4 Thienvv - tach branch part 5 2025-03-12 20:27:43 +07:00
thienqb123456 33e24203f0 Thienvv - tach branch part 4 2025-03-12 20:05:05 +07:00
thienqb123456 3f3e4fa53b Thienvv - tach branch part 3 2025-03-12 17:44:33 +07:00
thienqb123456 b61ee6a5e0 Thienvv - tach branch part 2 2025-03-12 17:09:38 +07:00
thienqb123456 f21f26115f Thienvv - tach branch part 1 2025-03-12 17:04:57 +07:00
thienqb123456 f9f21ba937 fixaa 2025-03-05 20:08:26 +07:00
thienqb123456 4b2f75c5a5 Thienvv - beta -> prod 2025-03-05 19:59:37 +07:00
thienqb123456 5ad8047ce4 Thienvv - sua cd backend2 2025-03-05 18:39:50 +07:00
thienqb123456 35a3d78ef1 Thienvv - sua cd backend 2025-03-05 18:33:19 +07:00
thienqb123456 5388c2ca6f xx 2025-03-05 17:42:25 +07:00
thienqb123456 949a18af95 fix0 2025-03-05 17:10:47 +07:00
thienqb123456 ef47b28f63 Thienvv - sửa cid theo ansible mới 2025-03-05 17:08:40 +07:00
thienqb123456 c422a0caff resource 2025-03-04 17:18:05 +07:00
thienqb123456 bdcdbf0c2f Thienvv - 2025-03-04 11:47:28 +07:00
thienqb123456 b4832fdb97 sửa cd be-portal 2025-03-03 16:22:48 +07:00
thienqb123456 87de8b0ee2 Thienv - tach nhan p7 2025-03-01 02:07:21 +07:00
thienqb123456 705b70d189 Thienv - tach nhan p6 2025-03-01 01:54:14 +07:00
thienqb123456 31f82f9e5e Thienv - tach nhan p5 2025-03-01 01:51:10 +07:00
thienqb123456 4785b99e76 Thienv - tach nhan p4 2025-03-01 01:32:01 +07:00
thienqb123456 02c34eb722 Thienv - tach nhan p3 2025-03-01 01:24:07 +07:00
thienqb123456 e979c36b0c Thienv - tach nhan p2' 2025-03-01 01:19:52 +07:00
thienqb123456 20d6065d36 Thienv - tach nhanh' 2025-03-01 01:16:40 +07:00
thienqb123456 1044024e65 Thienvv - tiep 2025-02-28 18:23:34 +07:00
thienqb123456 69b50258c1 ud 2025-02-28 17:47:45 +07:00
thienqb123456 27c4b620e4 update 2025-02-28 17:24:42 +07:00
thienqb123456 2b0143e2f9 Thienvv - thêm biểu tưởng thành công/thất bại khi bắn message về tele 2025-02-11 16:56:33 +07:00
thienqb123456 976f9ff37e thienvv 2025-01-15 15:13:40 +07:00
thienqb123456 722580786c thienvv 2025-01-15 15:11:54 +07:00
thienqb123456 1e2a845a27 mt beta 2025-01-15 14:58:49 +07:00
thienqb123456 f642dec5f5 beta enc 2025-01-15 14:40:30 +07:00
thienqb123456 70b7590269 thienvv- 2025-01-14 14:59:04 +07:00
thienqb123456 df992aa54e Thienvv - fe acp,portal mt beta 2025-01-14 14:54:01 +07:00
thienqb123456 e5f1d5c4c4 Thienvv - 2025-01-11 19:35:07 +07:00
thienqb123456 11caa6f492 ci-cd api resource 2025-01-11 19:28:13 +07:00
15 changed files with 2053 additions and 165 deletions
+35 -22
View File
@@ -1,30 +1,47 @@
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['prod', 'uat'], description: 'Choose Environment')
choice(name: 'ENV', choices: ['uat', 'production'], description: 'Choose Environment')
string(name: 'CI_JOB_BUILD_NUMBER', defaultValue: '', description: 'Build number of CI Job')
}
environment {
PROJECT_NAME = 'acp'
CI_JOB_NAME = 'CI_BE_ACP' // tên của job build code
CI_JOB_METADATA_FILENAME = "${PROJECT_NAME}_metadata.json" // tên file metadata đã được lưu từ ci job
CI_UAT_JOB_NAME = 'CI-UAT-BE-ACP' // tên của job build code mt uat
CI_PRODUCTION_JOB_NAME = 'CI-PRODUCTION-BE-ACP' // tên của job build code mt production
GIT_PAT_CREDENTIALS_ID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v2'
CI_JOB_METADATA_FILENAME = "${PROJECT_NAME}_${params.ENV}_metadata.json" // tên file metadata đã được lưu từ ci job
NEXUS_CREDENTIALS = credentials('Nexus_credential')
ANSIBLE_SSH_CONNECTION = 'root@103.166.183.172 -p 24700'
GIT_PAT_CREDENTIALS_ID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v3'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v2'
ANSIBLE_INVENTORY_PATH = "inventory/${params.ENV}.ini"
ANSIBLE_PLAYBOOK_PATH = 'playbooks/deploy_be.yml'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v3'
ANSIBLE_PLAYBOOK_PATH = 'playbooks/backend/deploy_acp_backend.yml'
SLACK_TOKEN = credentials('SLACK_TOKEN')
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
}
stages {
stage('Set up') {
steps {
script {
if (params.ENV == 'uat') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/uat/hosts.ini'
env.CI_JOB_NAME = CI_UAT_JOB_NAME
} else if (params.ENV == 'production') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/production/hosts.ini'
env.CI_JOB_NAME = CI_PRODUCTION_JOB_NAME
}
echo "ANSIBLE_INVENTORY_PATH is set to: ${env.ANSIBLE_INVENTORY_PATH}"
echo "CI_JOB_NAME is set to: ${env.CI_JOB_NAME}"
}
}
}
stage('Retrieve Artifact Metadata From CI Job') {
steps {
script {
@@ -63,8 +80,6 @@ pipeline {
env.ANSIBLE_FOLDER_PATH,
env.ANSIBLE_INVENTORY_PATH,
env.ANSIBLE_PLAYBOOK_PATH,
params.ENV,
env.PROJECT_NAME,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME,
env.NEXUS_CREDENTIALS_USR,
@@ -79,14 +94,16 @@ pipeline {
}
success {
script {
def message = "Deploy thành công : API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thành công : API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "Deploy thất bại: API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thất bại: API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
@@ -188,8 +205,6 @@ def triggerAnsible(
String ansibleansibleFolderPath,
String inventoryPath,
String playbookPath,
String deployENV,
String projectName,
String nexusUrl,
String nexusArtifactName,
String nexusUsername,
@@ -201,9 +216,7 @@ def triggerAnsible(
ssh ${sshAnsibleConnection} "
cd ${ansibleansibleFolderPath} &&
ansible-playbook -i ${inventoryPath} ${playbookPath} \\
-e 'deploy_env=${deployENV} \\
project_name=${projectName} \\
nexus_url=${nexusUrl} \\
-e 'nexus_url=${nexusUrl} \\
artifact_name=${nexusArtifactName} \\
nexus_username=${nexusUsername} \\
nexus_password=${nexusPassword}' -vvvv
@@ -0,0 +1,378 @@
pipeline {
agent any
options { disableConcurrentBuilds(abortPrevious: true) }
environment {
GIT_CREDENTIALSID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129'
GIT_URL = 'http://work.gct.com.vn/anhln/ACP_2025.git'
GIT_BRANCH_NAME = 'production-acp'
ENV = 'production'
PROJECT_NAME = 'acp'
METADATA_FILENAME = "${PROJECT_NAME}_${env.ENV}_metadata.json"
TRIGGER_JOB_NAME = 'CD_BE_ACP'
NUGET_CONFIG_PATH = 'NuGet.config'
APPLICATIONCORE_PATH = 'Packages'
JENKINS_BUILD_FOLDER_PATH = 'Acp.WebApi'
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-${env.ENV}-publish"
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_${env.ENV}_publish.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-acp-backend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = 'acp-backend-api'
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH_NAME as String)
}
}
stage('Clear Nuget caches') {
steps {
// Xóa cache của NuGet
clearNuGetCaches()
}
}
stage('Setup Nuget.Config') {
steps {
// Thiết lập tệp NuGet.config
setupNuGetConfig(env.APPLICATIONCORE_PATH as String)
}
}
stage('Restore') {
steps {
// Gọi hàm để thực hiện restore
restoreNuGetPackages(env.JENKINS_BUILD_FOLDER_PATH as String , env.NUGET_CONFIG_PATH as String)
}
}
stage('Clean & Build') {
steps {
script {
cleanProject(env.JENKINS_BUILD_FOLDER_PATH as String)
buildProject(env.JENKINS_BUILD_FOLDER_PATH as String)
}
}
}
stage('Publish') {
steps {
publishProject(env.JENKINS_BUILD_FOLDER_PATH as String, env.JENKINS_PUBLISH_FOLDER_PATH as String)
}
}
stage('Package (Compress Publish Files)') {
steps {
compressItems(env.COMPRESSED_FILE_PATH, env.JENKINS_PUBLISH_FOLDER_PATH)
}
}
stage('Upload to Nexus') {
steps {
script {
String groupPath = env.GROUP_ID.replace('.', '/')
env.NEXUS_URL = "${env.NEXUS_REPO_URL}/${groupPath}/${env.ARTIFACT_ID}/${env.VERSION}"
env.NEXUS_ARTIFACT_NAME = "${env.ARTIFACT_ID}-${env.FULL_VERSION}.${env.PACKAGING}"
String nexusUploadUrl = "${env.NEXUS_URL}/${env.NEXUS_ARTIFACT_NAME}"
uploadToNexus(
env.NEXUS_CREDENTIALS_USR,
env.NEXUS_CREDENTIALS_PSW,
env.COMPRESSED_FILE_PATH,
nexusUploadUrl)
}
}
}
stage('Create Metadata File') {
steps {
createMetadataFile(
env.METADATA_FILENAME,
env.GROUP_ID,
env.ARTIFACT_ID,
env.VERSION,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME)
echo "metadataFileName: ${env.METADATA_FILENAME}"
archiveArtifacts artifacts: "${env.METADATA_FILENAME}", allowEmptyArchive: false
}
}
}
post {
always {
echo 'Pipeline execution finished.'
}
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "✅Build thành công : API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "❌Build thất bại: API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
}
//Thienvv- hàm checkout git
void checkoutFromGit(String gitUrl, String credentialsId, String branch) {
try {
echo 'Start checkoutFromGit'
checkout([$class : 'GitSCM',
userRemoteConfigs: [[url: gitUrl, credentialsId: credentialsId]],
branches : [[name: "*/${branch}"]]])
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv- clear nuget caches
void clearNuGetCaches() {
try {
// Xóa cache của NuGet
Integer result = sh(script: 'dotnet nuget locals all --clear', returnStatus: true)
echo "result:${result}"
// Kiểm tra trạng thái trả về
if (result == 0) {
echo 'NuGet caches cleared successfully.'
} else {
error "Failed to clear NuGet caches with status: ${result}"
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - Hàm set up file Nuget.config để restore các package dependencies
void setupNuGetConfig(String applicationCorePath) {
try {
writeFile file: 'NuGet.config', text: """<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="Package source" value="${applicationCorePath}" />
</packageSources>
</configuration>"""
// Kiểm tra xem tệp đã được ghi thành công
if (fileExists('NuGet.config')) {
echo 'NuGet.config has been created successfully.'
} else {
error 'Failed to create NuGet.config.'
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
// Thienvv - Định nghĩa hàm để restore các gói NuGet
// Thienvv - Định nghĩa hàm để restore các gói NuGet
void restoreNuGetPackages(String restorePath, String nugetConfigPath) {
echo 'Starting NuGet packages restore...'
try {
if (!fileExists(restorePath)) {
error "restorePath is not exist : ${restorePath}"
}
if (!fileExists(nugetConfigPath)) {
error "nugetConfigPath is not exist : ${nugetConfigPath}"
}
// Thực hiện restore các gói NuGet cần thiết
Integer result = sh(script: "dotnet restore ${restorePath} --configfile ${nugetConfigPath}", returnStatus: true)
// Kiểm tra kết quả trả về
if (result == 0) {
echo 'NuGet packages restored successfully.'
} else {
error "Restore NuGet packages failed with exit code: ${result}. Check NuGet config and restore path."
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - clean project dotnet
void cleanProject(String buildPath) {
echo 'Start cleanProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet clean ${buildPath}", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Clean Project successfully'
} else {
error 'Clean Projectfailed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - build project dotnet
void buildProject(String buildPath) {
echo 'Start buildProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet build ${buildPath} -c Release", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Build Project successfully'
} else {
error 'Build Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - package/publish project dotnet
void publishProject(String buildPath, String publishFolderPath) {
echo 'Start publishProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet publish ${buildPath} -c Release -o ${publishFolderPath}",
returnStatus: true)
echo "result : ${result}"
if (result == 0) {
echo 'Publish Project successfully'
} else {
error 'Publish Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - nén file
void compressItems(String compressedFilePath, String parentFolderPath) {
echo "Starting compression of the entire folder into a zip file : ${compressedFilePath}"
try {
if (fileExists(compressedFilePath)) {
echo "Old ZIP file exists. Deleting: ${compressedFilePath}"
sh "rm -f ${compressedFilePath}"
} else {
echo 'No old ZIP file found.'
}
if (!fileExists(parentFolderPath)) {
error "parentFolderPath is not exist : ${parentFolderPath}"
}
dir(parentFolderPath) {
// Thực hiện lệnh zip để nén tất cả các file trong thư mục
Integer result = sh(script: "zip -r ${compressedFilePath} * ", returnStatus: true)
// Kiểm tra kết quả
if (result == 0) {
echo "Compression completed successfully: ${compressedFilePath}"
} else {
error "Compression failed with exit code: ${result}."
}
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
void uploadToNexus(String nexusUsername, String nexusPassword, String compressedFilePath, String uploadUrl) {
echo "Starting upload ${compressedFilePath} To Nexus"
try {
// Truyền các biến môi trường vào lệnh sh mà không lộ ra trong log
String result = sh(script: """
curl -u ${nexusUsername}:${nexusPassword} --upload-file ${compressedFilePath} ${uploadUrl} -w '%{http_code}'
""", returnStdout: true).trim()
if (result == '200' || result == '201') {
echo 'uploadToNexus successfully'
} else {
error "uploadToNexus failed, HTTP status: ${result}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
def createMetadataFile(
String metadataFileName,
String groupId,
String artifactId,
String version,
String nexusUrl,
String nexusArtifactName) {
echo 'Starting create metadata file'
try {
// Tạo metadata
metadata = [
groupId: groupId,
artifactId: artifactId,
version: version,
nexusUrl: nexusUrl,
nexusArtifactName: nexusArtifactName
]
// Ghi metadata vào file JSON
writeJSON file: "${metadataFileName}", json: metadata
if (!fileExists(metadataFileName)) {
error "metadataFileName is not exist : ${metadataFileName}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
@@ -4,24 +4,25 @@ pipeline {
environment {
GIT_CREDENTIALSID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129'
GIT_URL = 'http://work.gct.com.vn/anhln/ACP_2025.git'
GIT_BRANCH = 'main'
GIT_BRANCH_NAME = 'uat-acp'
ENV = 'uat'
PROJECT_NAME = 'acp'
METADATA_FILENAME = "${PROJECT_NAME}_metadata.json"
METADATA_FILENAME = "${PROJECT_NAME}_${env.ENV}_metadata.json"
TRIGGER_JOB_NAME = 'CD_BE_ACP'
NUGET_CONFIG_PATH = 'NuGet.config'
APPLICATIONCORE_PATH = 'Packages'
JENKINS_BUILD_FOLDER_PATH = 'Acp.WebApi'
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-publish"
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-${env.ENV}-publish"
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_publish.zip" // tên file nén
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_${env.ENV}_publish.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = 'https://nexus.gct.com.vn/repository/acp-backend'
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-acp-backend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = 'acp-backend-api'
PACKAGING = 'zip'
@@ -30,15 +31,15 @@ pipeline {
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH as String)
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH_NAME as String)
}
}
@@ -124,13 +125,14 @@ pipeline {
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "Build thành công : API - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thành công : API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
try {
def buildResult = build job: "${TRIGGER_JOB_NAME}", parameters:[
string(name: 'ENV', value: 'uat'),
string(name: 'ENV', value: env.ENV),
string(name: 'CI_JOB_BUILD_NUMBER', value: env.BUILD_NUMBER)
],
propagate: false
@@ -146,8 +148,9 @@ pipeline {
}
failure {
script {
def message = "Build thất bại: API - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thất bại: API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
+40 -21
View File
@@ -1,14 +1,15 @@
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['prod', 'uat'], description: 'Choose Environment')
choice(name: 'ENV', choices: ['uat', 'production'], description: 'Choose Environment')
choice(name: 'PORTAL_NAME', choices: ['ktdt', 'hnt'], description: 'Choose Portal')
string(name: 'CI_JOB_BUILD_NUMBER', defaultValue: '', description: 'Build number of CI Job')
}
environment {
PROJECT_NAME = 'portal'
CI_JOB_NAME = 'CI_BE_PORTAL' // tên của job CI
CI_JOB_METADATA_FILENAME = "${PROJECT_NAME}_metadata.json" // tên file metadata đã được lưu từ ci job
CI_UAT_JOB_NAME = 'CI-UAT-BE-PORTAL' // tên của job build code mt uat
CI_PRODUCTION_JOB_NAME = 'CI-PRODUCTION-BE-PORTAL' // tên của job build code mt production
CI_JOB_METADATA_FILENAME = "${PROJECT_NAME}_${params.ENV}_metadata.json" // tên file metadata đã được lưu từ ci job
NEXUS_CREDENTIALS = credentials('Nexus_credential')
@@ -16,17 +17,39 @@ pipeline {
GIT_PAT_CREDENTIALS_ID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v2'
GIT_ANSIBLE_BRANCH = 'v3'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v2'
ANSIBLE_INVENTORY_PATH = "inventory/${params.ENV}.ini"
ANSIBLE_PLAYBOOK_PATH = 'playbooks/deploy_be.yml'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v3'
SLACK_TOKEN = credentials('SLACK_TOKEN')
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
}
stages {
stage('Set up') {
steps {
script {
if (params.ENV == 'uat') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/uat/hosts.ini'
env.CI_JOB_NAME = CI_UAT_JOB_NAME
} else if (params.ENV == 'production') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/production/hosts.ini'
env.CI_JOB_NAME = CI_PRODUCTION_JOB_NAME
}
echo "ANSIBLE_INVENTORY_PATH is set to: ${env.ANSIBLE_INVENTORY_PATH}"
echo "CI_JOB_NAME is set to: ${env.CI_JOB_NAME}"
if (params.PORTAL_NAME == 'ktdt') {
env.ANSIBLE_PLAYBOOK_PATH = 'playbooks/backend/deploy_ktdt_portal_backend.yml'
} else if (params.PORTAL_NAME == 'hnt') {
env.ANSIBLE_PLAYBOOK_PATH = 'playbooks/backend/deploy_hnt_portal_backend.yml'
}
echo "ANSIBLE_PLAYBOOK_PATH is set to: ${env.ANSIBLE_PLAYBOOK_PATH}"
}
}
}
stage('Retrieve Artifact From CI Job') {
steps {
script {
@@ -65,8 +88,6 @@ pipeline {
env.ANSIBLE_FOLDER_PATH,
env.ANSIBLE_INVENTORY_PATH,
env.ANSIBLE_PLAYBOOK_PATH,
params.ENV,
env.PROJECT_NAME,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME,
env.NEXUS_CREDENTIALS_USR,
@@ -81,14 +102,16 @@ pipeline {
}
success {
script {
def message = "Deploy thành công : API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thành công : API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "Deploy thất bại: API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thất bại: API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
@@ -189,8 +212,6 @@ def triggerAnsible(
String ansibleansibleFolderPath,
String inventoryPath,
String playbookPath,
String deployENV,
String projectName,
String nexusUrl,
String nexusArtifactName,
String nexusUsername,
@@ -202,9 +223,7 @@ def triggerAnsible(
ssh ${sshAnsibleConnection} "
cd ${ansibleansibleFolderPath} &&
ansible-playbook -i ${inventoryPath} ${playbookPath} \\
-e 'deploy_env=${deployENV} \\
project_name=${projectName} \\
nexus_url=${nexusUrl} \\
-e 'nexus_url=${nexusUrl} \\
artifact_name=${nexusArtifactName} \\
nexus_username=${nexusUsername} \\
nexus_password=${nexusPassword}' -vvvv
@@ -0,0 +1,380 @@
pipeline {
agent any
options { disableConcurrentBuilds(abortPrevious: true) }
environment {
GIT_CREDENTIALSID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129'
GIT_URL = 'http://work.gct.com.vn/anhln/ACP_2025.git'
GIT_BRANCH_NAME = 'production-portal'
ENV = 'production'
PROJECT_NAME = 'portal'
METADATA_FILENAME = "${PROJECT_NAME}_${env.ENV}_metadata.json"
TRIGGER_JOB_NAME = 'CD_BE_PORTAL'
NUGET_CONFIG_PATH = 'NuGet.config'
APPLICATIONCORE_PATH = 'Packages'
JENKINS_BUILD_FOLDER_PATH = 'Portal.WebApi'
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-${env.ENV}-publish"
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_${env.ENV}_publish.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-portal-backend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = 'portal-backend-api'
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH_NAME as String)
}
}
stage('Clear Nuget caches') {
steps {
// Xóa cache của NuGet
clearNuGetCaches()
}
}
stage('Setup Nuget.Config') {
steps {
// Thiết lập tệp NuGet.config
setupNuGetConfig(env.APPLICATIONCORE_PATH as String)
}
}
stage('Restore') {
steps {
// Gọi hàm để thực hiện restore
restoreNuGetPackages(env.JENKINS_BUILD_FOLDER_PATH as String , env.NUGET_CONFIG_PATH as String)
}
}
stage('Clean & Build') {
steps {
script {
cleanProject(env.JENKINS_BUILD_FOLDER_PATH as String)
buildProject(env.JENKINS_BUILD_FOLDER_PATH as String)
}
}
}
stage('Publish') {
steps {
publishProject(env.JENKINS_BUILD_FOLDER_PATH as String, env.JENKINS_PUBLISH_FOLDER_PATH as String)
}
}
stage('Package (Compress Publish Files)') {
steps {
compressItems(env.COMPRESSED_FILE_PATH, env.JENKINS_PUBLISH_FOLDER_PATH)
}
}
stage('Upload to Nexus') {
steps {
script {
String groupPath = env.GROUP_ID.replace('.', '/')
env.NEXUS_URL = "${env.NEXUS_REPO_URL}/${groupPath}/${env.ARTIFACT_ID}/${env.VERSION}"
env.NEXUS_ARTIFACT_NAME = "${env.ARTIFACT_ID}-${env.FULL_VERSION}.${env.PACKAGING}"
String nexusUploadUrl = "${env.NEXUS_URL}/${env.NEXUS_ARTIFACT_NAME}"
uploadToNexus(
env.NEXUS_CREDENTIALS_USR,
env.NEXUS_CREDENTIALS_PSW,
env.COMPRESSED_FILE_PATH,
nexusUploadUrl)
}
}
}
stage('Create Metadata File') {
steps {
createMetadataFile(
env.METADATA_FILENAME,
env.GROUP_ID,
env.ARTIFACT_ID,
env.VERSION,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME)
echo "metadataFileName: ${env.METADATA_FILENAME}"
archiveArtifacts artifacts: "${env.METADATA_FILENAME}", allowEmptyArchive: false
}
}
}
post {
always {
echo 'Pipeline execution finished.'
}
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "✅Build thành công : API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
failure {
script {
def message = "❌Build thất bại: API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
}
}
//Thienvv- hàm checkout git
void checkoutFromGit(String gitUrl, String credentialsId, String branch) {
try {
echo 'Start checkoutFromGit'
checkout([$class : 'GitSCM',
userRemoteConfigs: [[url: gitUrl, credentialsId: credentialsId]],
branches : [[name: "*/${branch}"]]])
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv- clear nuget caches
void clearNuGetCaches() {
try {
// Xóa cache của NuGet
Integer result = sh(script: 'dotnet nuget locals all --clear', returnStatus: true)
echo "result:${result}"
// Kiểm tra trạng thái trả về
if (result == 0) {
echo 'NuGet caches cleared successfully.'
} else {
error "Failed to clear NuGet caches with status: ${result}"
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - Hàm set up file Nuget.config để restore các package dependencies
void setupNuGetConfig(String applicationCorePath) {
try {
writeFile file: 'NuGet.config', text: """<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="Package source" value="${applicationCorePath}" />
</packageSources>
</configuration>"""
// Kiểm tra xem tệp đã được ghi thành công
if (fileExists('NuGet.config')) {
echo 'NuGet.config has been created successfully.'
} else {
error 'Failed to create NuGet.config.'
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
// Thienvv - Định nghĩa hàm để restore các gói NuGet
void restoreNuGetPackages(String restorePath, String nugetConfigPath) {
echo 'Starting NuGet packages restore...'
try {
if (!fileExists(restorePath)) {
error "restorePath is not exist : ${restorePath}"
}
if (!fileExists(nugetConfigPath)) {
error "nugetConfigPath is not exist : ${nugetConfigPath}"
}
// Thực hiện restore các gói NuGet cần thiết
Integer result = sh(script: "dotnet restore ${restorePath} --configfile ${nugetConfigPath}", returnStatus: true)
// Kiểm tra kết quả trả về
if (result == 0) {
echo 'NuGet packages restored successfully.'
} else {
error "Restore NuGet packages failed with exit code: ${result}. Check NuGet config and restore path."
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - clean project dotnet
void cleanProject(String buildPath) {
echo 'Start cleanProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet clean ${buildPath}", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Clean Project successfully'
} else {
error 'Clean Projectfailed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - build project dotnet
void buildProject(String buildPath) {
echo 'Start buildProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet build ${buildPath} -c Release", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Build Project successfully'
} else {
error 'Build Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - package/publish project dotnet
void publishProject(String buildPath, String publishFolderPath) {
echo 'Start publishProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet publish ${buildPath} -c Release -o ${publishFolderPath}",
returnStatus: true)
echo "result : ${result}"
if (result == 0) {
echo 'Publish Project successfully'
} else {
error 'Publish Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - nén file
void compressItems(String compressedFilePath, String parentFolderPath) {
echo "Starting compression of the entire folder into a zip file : ${compressedFilePath}"
try {
if (fileExists(compressedFilePath)) {
echo "Old ZIP file exists. Deleting: ${compressedFilePath}"
sh "rm -f ${compressedFilePath}"
} else {
echo 'No old ZIP file found.'
}
if (!fileExists(parentFolderPath)) {
error "parentFolderPath is not exist : ${parentFolderPath}"
}
dir(parentFolderPath) {
// Thực hiện lệnh zip để nén tất cả các file trong thư mục
Integer result = sh(script: "zip -r ${compressedFilePath} * ", returnStatus: true)
// Kiểm tra kết quả
if (result == 0) {
echo "Compression completed successfully: ${compressedFilePath}"
} else {
error "Compression failed with exit code: ${result}."
}
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
void uploadToNexus(String nexusUsername, String nexusPassword, String compressedFilePath, String uploadUrl) {
echo "Starting upload ${compressedFilePath} To Nexus"
try {
// Truyền các biến môi trường vào lệnh sh mà không lộ ra trong log
String result = sh(script: """
curl -u ${nexusUsername}:${nexusPassword} --upload-file ${compressedFilePath} ${uploadUrl} -w '%{http_code}'
""", returnStdout: true).trim()
if (result == '200' || result == '201') {
echo 'uploadToNexus successfully'
} else {
error "uploadToNexus failed, HTTP status: ${result}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
def createMetadataFile(
String metadataFileName,
String groupId,
String artifactId,
String version,
String nexusUrl,
String nexusArtifactName) {
echo 'Starting create metadata file'
try {
// Tạo metadata
metadata = [
groupId: groupId,
artifactId: artifactId,
version: version,
nexusUrl: nexusUrl,
nexusArtifactName: nexusArtifactName
]
// Ghi metadata vào file JSON
writeJSON file: "${metadataFileName}", json: metadata
if (!fileExists(metadataFileName)) {
error "metadataFileName is not exist : ${metadataFileName}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
@@ -4,42 +4,41 @@ pipeline {
environment {
GIT_CREDENTIALSID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129'
GIT_URL = 'http://work.gct.com.vn/anhln/ACP_2025.git'
GIT_BRANCH = 'main'
GIT_BRANCH_NAME = 'uat-portal'
ENV = 'uat'
PROJECT_NAME = 'portal'
METADATA_FILENAME = "${PROJECT_NAME}_${env.ENV}_metadata.json"
TRIGGER_JOB_NAME = 'CD_BE_PORTAL'
METADATA_FILENAME = "${PROJECT_NAME}_metadata.json"
NUGET_CONFIG_PATH = 'NuGet.config'
APPLICATIONCORE_PATH = 'Packages'
JENKINS_BUILD_FOLDER_PATH = 'Portal.WebApi'
JENKINS_PUBLISH_FOLDER_PATH = 'publish'
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-${env.ENV}-publish"
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_publish.zip" // tên file nén
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_${env.ENV}_publish.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${PROJECT_NAME}-backend"
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-portal-backend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = "${PROJECT_NAME}-backend-api"
ARTIFACT_ID = 'portal-backend-api'
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH as String)
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH_NAME as String)
}
}
@@ -126,15 +125,20 @@ pipeline {
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "Build thành công : API - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thành công : API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
def portalNames = ['ktdt', 'hnt']
try {
build job: "${TRIGGER_JOB_NAME}", parameters:[
string(name: 'ENV', value: 'uat'),
for (portal in portalNames) {
build job: "${TRIGGER_JOB_NAME}", parameters:[
string(name: 'ENV', value: env.ENV),
string(name: 'PORTAL_NAME', value: portal),
string(name: 'CI_JOB_BUILD_NUMBER', value: env.BUILD_NUMBER)
], propagate: false
}
}
catch (Exception e) {
echo "[ERROR] Failed to trigger job: ${TRIGGER_JOB_NAME}. Error: ${e.message}"
@@ -146,8 +150,8 @@ pipeline {
failure {
failure {
script {
def message = "Build thất bại: API - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thất bại: API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
@@ -0,0 +1,246 @@
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['uat', 'production'], description: 'Choose Environment')
choice(name: 'PORTAL_NAME', choices: ['ktdt', 'hnt'], description: 'Choose Portal')
string(name: 'CI_JOB_BUILD_NUMBER', defaultValue: '', description: 'Build number of CI Job')
}
environment {
PROJECT_NAME = 'resource'
CI_UAT_JOB_NAME = 'CI-UAT-BE-RESOURCE' // tên của job build code mt uat
CI_PRODUCTION_JOB_NAME = 'CI-PRODUCTION-BE-RESOURCE' // tên của job build code mt production
CI_JOB_METADATA_FILENAME = "${PROJECT_NAME}_${params.ENV}_metadata.json" // tên file metadata đã được lưu từ ci job
NEXUS_CREDENTIALS = credentials('Nexus_credential')
ANSIBLE_SSH_CONNECTION = 'root@103.166.183.172 -p 24700'
GIT_PAT_CREDENTIALS_ID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v3'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v3'
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Set up') {
steps {
script {
if (params.ENV == 'uat') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/uat/hosts.ini'
env.CI_JOB_NAME = CI_UAT_JOB_NAME
} else if (params.ENV == 'production') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/production/hosts.ini'
env.CI_JOB_NAME = CI_PRODUCTION_JOB_NAME
}
echo "ANSIBLE_INVENTORY_PATH is set to: ${env.ANSIBLE_INVENTORY_PATH}"
echo "CI_JOB_NAME is set to: ${env.CI_JOB_NAME}"
if (params.PORTAL_NAME == 'ktdt') {
env.ANSIBLE_PLAYBOOK_PATH = 'playbooks/backend/deploy_ktdt_resource_backend.yml'
} else if (params.PORTAL_NAME == 'hnt') {
env.ANSIBLE_PLAYBOOK_PATH = 'playbooks/backend/deploy_hnt_resource_backend.yml'
}
echo "ANSIBLE_PLAYBOOK_PATH is set to: ${env.ANSIBLE_PLAYBOOK_PATH}"
}
}
}
stage('Retrieve Artifact Metadata From CI Job') {
steps {
script {
def ciJobBuildNumber = params.CI_JOB_BUILD_NUMBER
echo "Retrieving artifact from CI_JOB_BUILD_NUMBER: ${ciJobBuildNumber}"
def metadata = retrieveArtifactMetadataFromCIJOB(env.CI_JOB_NAME, ciJobBuildNumber, CI_JOB_METADATA_FILENAME)
env.NEXUS_URL = metadata.nexusUrl
echo "env.NEXUS_URL : ${env.NEXUS_URL}"
env.NEXUS_ARTIFACT_NAME = metadata.nexusArtifactName
echo "env.NEXUS_ARTIFACT_NAME : ${env.NEXUS_ARTIFACT_NAME}"
}
}
}
stage('Checkout Ansible Code Git ') {
steps {
script {
checkoutFromGit(
env.ANSIBLE_SSH_CONNECTION,
env.GIT_ANSIBLE_URL,
env.GIT_PAT_CREDENTIALS_ID,
env.GIT_ANSIBLE_BRANCH,
env.ANSIBLE_FOLDER_PATH
)
}
}
}
stage('Deploy with Ansible') {
steps {
triggerAnsible(
env.ANSIBLE_SSH_CONNECTION,
env.ANSIBLE_FOLDER_PATH,
env.ANSIBLE_INVENTORY_PATH,
env.ANSIBLE_PLAYBOOK_PATH,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME,
env.NEXUS_CREDENTIALS_USR,
env.NEXUS_CREDENTIALS_PSW)
}
}
}
post {
always {
echo 'Pipeline execution finished.'
}
success {
script {
def message = "✅Deploy thành công : API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}- Portal_Name ${params.PORTAL_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "❌Deploy thất bại: API - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
}
//Thienvv- hàm checkout git code ansible về máy ansible
def checkoutFromGit(
String ansibleSSHConnection,
String gitUrl,
String gitAnsibleCredentialsId,
String branch,
String ansibleFolderPath) {
try {
// kiểm tra đã tồn tại code ansible trên thư mục của máy ansible
Boolean repoExists = sh(
script: """
ssh -v ${ansibleSSHConnection} \\
' [ -d ${ansibleFolderPath}/.git ] && echo '1' || echo '0' '
""",
returnStdout: true
).trim() == '1'
withCredentials([usernamePassword(
credentialsId: gitAnsibleCredentialsId,
usernameVariable: 'GIT_USERNAME',
passwordVariable: 'GIT_PAT')]) {
if (repoExists) { // nếu tồn tại source code ansible rồi thì pull về
echo "Repository already exists on ${ansibleFolderPath}. Pulling latest changes..."
Integer result = sh(script: """
ssh -v ${ansibleSSHConnection} \\
'cd ${ansibleFolderPath} && \\
git reset --hard && \\
git clean -fd && \\
git fetch origin && \\
git checkout ${branch} && \\
git pull origin ${branch} -vvvv '
""", returnStatus: true)
if (result == 0) {
echo 'Pull ansible code successfully'
} else {
error "Pull ansible code failed, status: ${result}"
}
} else { //nếu chưa tồn tại code ansible
Integer result = sh(script: """
ssh -v ${ansibleSSHConnection} \\
'git clone --branch ${branch} http://${GIT_USERNAME}@${gitUrl} ${ansibleFolderPath} -vvvv '
""", returnStatus: true)
if (result == 0) {
echo 'Clone ansible code successfully'
} else {
error "Clone ansible code failed, status: ${result}"
}
}
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Hàm lấy artifact metadata file từ CI job
def retrieveArtifactMetadataFromCIJOB(String ciJobName, String ciJobBuildNumber, String metadataFilename) {
try {
def selector = null
if (ciJobBuildNumber != '') { // nếu ciJobBuildNumber khác rỗng thì
selector = [$class: 'SpecificBuildSelector', buildNumber: ciJobBuildNumber] // selector = ciJobBuildNumber
} else { //còn nếu ciJobBuildNumber = rỗng thì
selector = lastSuccessful() //selector = build thành công gần nhất
}
// Sao chép artifact từ dự án khác
copyArtifacts projectName: ciJobName,
selector: selector,
filter: metadataFilename,
target: '.'
// Kiểm tra sự tồn tại của file metadata
if (!fileExists(metadataFilename)) {
error "File ${metadataFilename} not found after copyArtifacts!"
} else {
echo "File ${metadataFilename} successfully copied."
}
// Đọc dữ liệu từ file JSON
def metadata = readJSON file: metadataFilename
return metadata
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
def triggerAnsible(
String sshAnsibleConnection,
String ansibleansibleFolderPath,
String inventoryPath,
String playbookPath,
String nexusUrl,
String nexusArtifactName,
String nexusUsername,
String nexusPassword) {
try {
Integer result = sh(
script: """
ssh ${sshAnsibleConnection} "
cd ${ansibleansibleFolderPath} &&
ansible-playbook -i ${inventoryPath} ${playbookPath} \\
-e ' nexus_url=${nexusUrl} \\
artifact_name=${nexusArtifactName} \\
nexus_username=${nexusUsername} \\
nexus_password=${nexusPassword}' -vvvv
"
""",
returnStatus: true
)
if (result == 0) {
echo 'triggerAnsible successfully'
} else {
error "triggerAnsible failed, status: ${result}"
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
@@ -0,0 +1,379 @@
pipeline {
agent any
options { disableConcurrentBuilds(abortPrevious: true) }
environment {
GIT_CREDENTIALSID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129'
GIT_URL = 'http://work.gct.com.vn/anhln/ACP_2025.git'
GIT_BRANCH_NAME = 'production-resource'
ENV = 'production'
PROJECT_NAME = 'resource'
METADATA_FILENAME = "${PROJECT_NAME}_${env.ENV}_metadata.json"
TRIGGER_JOB_NAME = 'CD-BE-RESOURCE'
NUGET_CONFIG_PATH = 'NuGet.config'
APPLICATIONCORE_PATH = 'Packages'
JENKINS_BUILD_FOLDER_PATH = 'Resource.WebApi'
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-${env.ENV}-publish"
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_${env.ENV}_publish.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-resource-backend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = 'resource-backend-api'
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH_NAME as String)
}
}
stage('Clear Nuget caches') {
steps {
// Xóa cache của NuGet
clearNuGetCaches()
}
}
stage('Setup Nuget.Config') {
steps {
// Thiết lập tệp NuGet.config
setupNuGetConfig(env.APPLICATIONCORE_PATH as String)
}
}
stage('Restore') {
steps {
// Gọi hàm để thực hiện restore
restoreNuGetPackages(env.JENKINS_BUILD_FOLDER_PATH as String , env.NUGET_CONFIG_PATH as String)
}
}
stage('Clean & Build') {
steps {
script {
cleanProject(env.JENKINS_BUILD_FOLDER_PATH as String)
buildProject(env.JENKINS_BUILD_FOLDER_PATH as String)
}
}
}
stage('Publish') {
steps {
publishProject(env.JENKINS_BUILD_FOLDER_PATH as String, env.JENKINS_PUBLISH_FOLDER_PATH as String)
}
}
stage('Package (Compress Publish Files)') {
steps {
compressItems(env.COMPRESSED_FILE_PATH, env.JENKINS_PUBLISH_FOLDER_PATH)
}
}
stage('Upload to Nexus') {
steps {
script {
String groupPath = env.GROUP_ID.replace('.', '/')
env.NEXUS_URL = "${env.NEXUS_REPO_URL}/${groupPath}/${env.ARTIFACT_ID}/${env.VERSION}"
env.NEXUS_ARTIFACT_NAME = "${env.ARTIFACT_ID}-${env.FULL_VERSION}.${env.PACKAGING}"
String nexusUploadUrl = "${env.NEXUS_URL}/${env.NEXUS_ARTIFACT_NAME}"
uploadToNexus(
env.NEXUS_CREDENTIALS_USR,
env.NEXUS_CREDENTIALS_PSW,
env.COMPRESSED_FILE_PATH,
nexusUploadUrl)
}
}
}
stage('Create Metadata File') {
steps {
createMetadataFile(
env.METADATA_FILENAME,
env.GROUP_ID,
env.ARTIFACT_ID,
env.VERSION,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME)
echo "metadataFileName: ${env.METADATA_FILENAME}"
archiveArtifacts artifacts: "${env.METADATA_FILENAME}", allowEmptyArchive: false
}
}
}
post {
always {
echo 'Pipeline execution finished.'
}
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "✅Build thành công : API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
// sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "❌Build thất bại: API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
// sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
}
//Thienvv- hàm checkout git
void checkoutFromGit(String gitUrl, String credentialsId, String branch) {
try {
echo 'Start checkoutFromGit'
checkout([$class : 'GitSCM',
userRemoteConfigs: [[url: gitUrl, credentialsId: credentialsId]],
branches : [[name: "*/${branch}"]]])
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv- clear nuget caches
void clearNuGetCaches() {
try {
// Xóa cache của NuGet
Integer result = sh(script: 'dotnet nuget locals all --clear', returnStatus: true)
echo "result:${result}"
// Kiểm tra trạng thái trả về
if (result == 0) {
echo 'NuGet caches cleared successfully.'
} else {
error "Failed to clear NuGet caches with status: ${result}"
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - Hàm set up file Nuget.config để restore các package dependencies
void setupNuGetConfig(String applicationCorePath) {
try {
writeFile file: 'NuGet.config', text: """<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="Package source" value="${applicationCorePath}" />
</packageSources>
</configuration>"""
// Kiểm tra xem tệp đã được ghi thành công
if (fileExists('NuGet.config')) {
echo 'NuGet.config has been created successfully.'
} else {
error 'Failed to create NuGet.config.'
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
// Thienvv - Định nghĩa hàm để restore các gói NuGet
// Thienvv - Định nghĩa hàm để restore các gói NuGet
void restoreNuGetPackages(String restorePath, String nugetConfigPath) {
echo 'Starting NuGet packages restore...'
try {
if (!fileExists(restorePath)) {
error "restorePath is not exist : ${restorePath}"
}
if (!fileExists(nugetConfigPath)) {
error "nugetConfigPath is not exist : ${nugetConfigPath}"
}
// Thực hiện restore các gói NuGet cần thiết
Integer result = sh(script: "dotnet restore ${restorePath} --configfile ${nugetConfigPath}", returnStatus: true)
// Kiểm tra kết quả trả về
if (result == 0) {
echo 'NuGet packages restored successfully.'
} else {
error "Restore NuGet packages failed with exit code: ${result}. Check NuGet config and restore path."
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - clean project dotnet
void cleanProject(String buildPath) {
echo 'Start cleanProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet clean ${buildPath}", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Clean Project successfully'
} else {
error 'Clean Projectfailed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - build project dotnet
void buildProject(String buildPath) {
echo 'Start buildProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet build ${buildPath} -c Release", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Build Project successfully'
} else {
error 'Build Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - package/publish project dotnet
void publishProject(String buildPath, String publishFolderPath) {
echo 'Start publishProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet publish ${buildPath} -c Release -o ${publishFolderPath}",
returnStatus: true)
echo "result : ${result}"
if (result == 0) {
echo 'Publish Project successfully'
} else {
error 'Publish Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - nén file
void compressItems(String compressedFilePath, String parentFolderPath) {
echo "Starting compression of the entire folder into a zip file : ${compressedFilePath}"
try {
if (fileExists(compressedFilePath)) {
echo "Old ZIP file exists. Deleting: ${compressedFilePath}"
sh "rm -f ${compressedFilePath}"
} else {
echo 'No old ZIP file found.'
}
if (!fileExists(parentFolderPath)) {
error "parentFolderPath is not exist : ${parentFolderPath}"
}
dir(parentFolderPath) {
// Thực hiện lệnh zip để nén tất cả các file trong thư mục
Integer result = sh(script: "zip -r ${compressedFilePath} * ", returnStatus: true)
// Kiểm tra kết quả
if (result == 0) {
echo "Compression completed successfully: ${compressedFilePath}"
} else {
error "Compression failed with exit code: ${result}."
}
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
void uploadToNexus(String nexusUsername, String nexusPassword, String compressedFilePath, String uploadUrl) {
echo "Starting upload ${compressedFilePath} To Nexus"
try {
// Truyền các biến môi trường vào lệnh sh mà không lộ ra trong log
String result = sh(script: """
curl -u ${nexusUsername}:${nexusPassword} --upload-file ${compressedFilePath} ${uploadUrl} -w '%{http_code}'
""", returnStdout: true).trim()
if (result == '200' || result == '201') {
echo 'uploadToNexus successfully'
} else {
error "uploadToNexus failed, HTTP status: ${result}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
def createMetadataFile(
String metadataFileName,
String groupId,
String artifactId,
String version,
String nexusUrl,
String nexusArtifactName) {
echo 'Starting create metadata file'
try {
// Tạo metadata
metadata = [
groupId: groupId,
artifactId: artifactId,
version: version,
nexusUrl: nexusUrl,
nexusArtifactName: nexusArtifactName
]
// Ghi metadata vào file JSON
writeJSON file: "${metadataFileName}", json: metadata
if (!fileExists(metadataFileName)) {
error "metadataFileName is not exist : ${metadataFileName}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
@@ -0,0 +1,392 @@
pipeline {
agent any
options { disableConcurrentBuilds(abortPrevious: true) }
environment {
GIT_CREDENTIALSID = 'd3de261f-8f1e-470b-b6d1-2fb4965e0129'
GIT_URL = 'http://work.gct.com.vn/anhln/ACP_2025.git'
GIT_BRANCH_NAME = 'uat-resource'
ENV = 'uat'
PROJECT_NAME = 'resource'
METADATA_FILENAME = "${PROJECT_NAME}_${env.ENV}_metadata.json"
TRIGGER_JOB_NAME = 'CD-BE-RESOURCE'
NUGET_CONFIG_PATH = 'NuGet.config'
APPLICATIONCORE_PATH = 'Packages'
JENKINS_BUILD_FOLDER_PATH = 'Resource.WebApi'
JENKINS_PUBLISH_FOLDER_PATH = "${PROJECT_NAME}-${env.ENV}-publish"
COMPRESSED_FILE_NAME = "${PROJECT_NAME}_${env.ENV}_publish.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-resource-backend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = 'resource-backend-api'
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH_NAME as String)
}
}
stage('Clear Nuget caches') {
steps {
// Xóa cache của NuGet
clearNuGetCaches()
}
}
stage('Setup Nuget.Config') {
steps {
// Thiết lập tệp NuGet.config
setupNuGetConfig(env.APPLICATIONCORE_PATH as String)
}
}
stage('Restore') {
steps {
// Gọi hàm để thực hiện restore
restoreNuGetPackages(env.JENKINS_BUILD_FOLDER_PATH as String , env.NUGET_CONFIG_PATH as String)
}
}
stage('Clean & Build') {
steps {
script {
cleanProject(env.JENKINS_BUILD_FOLDER_PATH as String)
buildProject(env.JENKINS_BUILD_FOLDER_PATH as String)
}
}
}
stage('Publish') {
steps {
publishProject(env.JENKINS_BUILD_FOLDER_PATH as String, env.JENKINS_PUBLISH_FOLDER_PATH as String)
}
}
stage('Package (Compress Publish Files)') {
steps {
compressItems(env.COMPRESSED_FILE_PATH, env.JENKINS_PUBLISH_FOLDER_PATH)
}
}
stage('Upload to Nexus') {
steps {
script {
String groupPath = env.GROUP_ID.replace('.', '/')
env.NEXUS_URL = "${env.NEXUS_REPO_URL}/${groupPath}/${env.ARTIFACT_ID}/${env.VERSION}"
env.NEXUS_ARTIFACT_NAME = "${env.ARTIFACT_ID}-${env.FULL_VERSION}.${env.PACKAGING}"
String nexusUploadUrl = "${env.NEXUS_URL}/${env.NEXUS_ARTIFACT_NAME}"
uploadToNexus(
env.NEXUS_CREDENTIALS_USR,
env.NEXUS_CREDENTIALS_PSW,
env.COMPRESSED_FILE_PATH,
nexusUploadUrl)
}
}
}
stage('Create Metadata File') {
steps {
createMetadataFile(
env.METADATA_FILENAME,
env.GROUP_ID,
env.ARTIFACT_ID,
env.VERSION,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME)
echo "metadataFileName: ${env.METADATA_FILENAME}"
archiveArtifacts artifacts: "${env.METADATA_FILENAME}", allowEmptyArchive: false
}
}
}
post {
always {
echo 'Pipeline execution finished.'
}
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "✅Build thành công : API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
try {
def buildResult = build job: "${TRIGGER_JOB_NAME}", parameters:[
string(name: 'ENV', value: env.ENV),
string(name: 'CI_JOB_BUILD_NUMBER', value: env.BUILD_NUMBER)
],
propagate: false
if (buildResult.result != 'SUCCESS') {
echo "[WARNING] Job 2 failed with result: ${buildResult.result}"
}
}
catch (Exception e) {
echo "[ERROR] Failed to trigger job: ${TRIGGER_JOB_NAME}. Error: ${e.message}"
throw e
}
}
}
failure {
script {
def message = "❌Build thất bại: API - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
}
//Thienvv- hàm checkout git
void checkoutFromGit(String gitUrl, String credentialsId, String branch) {
try {
echo 'Start checkoutFromGit'
checkout([$class : 'GitSCM',
userRemoteConfigs: [[url: gitUrl, credentialsId: credentialsId]],
branches : [[name: "*/${branch}"]]])
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv- clear nuget caches
void clearNuGetCaches() {
try {
// Xóa cache của NuGet
Integer result = sh(script: 'dotnet nuget locals all --clear', returnStatus: true)
echo "result:${result}"
// Kiểm tra trạng thái trả về
if (result == 0) {
echo 'NuGet caches cleared successfully.'
} else {
error "Failed to clear NuGet caches with status: ${result}"
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - Hàm set up file Nuget.config để restore các package dependencies
void setupNuGetConfig(String applicationCorePath) {
try {
writeFile file: 'NuGet.config', text: """<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<add key="Package source" value="${applicationCorePath}" />
</packageSources>
</configuration>"""
// Kiểm tra xem tệp đã được ghi thành công
if (fileExists('NuGet.config')) {
echo 'NuGet.config has been created successfully.'
} else {
error 'Failed to create NuGet.config.'
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
// Thienvv - Định nghĩa hàm để restore các gói NuGet
// Thienvv - Định nghĩa hàm để restore các gói NuGet
void restoreNuGetPackages(String restorePath, String nugetConfigPath) {
echo 'Starting NuGet packages restore...'
try {
if (!fileExists(restorePath)) {
error "restorePath is not exist : ${restorePath}"
}
if (!fileExists(nugetConfigPath)) {
error "nugetConfigPath is not exist : ${nugetConfigPath}"
}
// Thực hiện restore các gói NuGet cần thiết
Integer result = sh(script: "dotnet restore ${restorePath} --configfile ${nugetConfigPath}", returnStatus: true)
// Kiểm tra kết quả trả về
if (result == 0) {
echo 'NuGet packages restored successfully.'
} else {
error "Restore NuGet packages failed with exit code: ${result}. Check NuGet config and restore path."
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - clean project dotnet
void cleanProject(String buildPath) {
echo 'Start cleanProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet clean ${buildPath}", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Clean Project successfully'
} else {
error 'Clean Projectfailed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - build project dotnet
void buildProject(String buildPath) {
echo 'Start buildProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet build ${buildPath} -c Release", returnStatus: true)
echo "result:${result}"
if (result == 0) {
echo 'Build Project successfully'
} else {
error 'Build Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - package/publish project dotnet
void publishProject(String buildPath, String publishFolderPath) {
echo 'Start publishProject'
try {
if (!fileExists(buildPath)) {
error "buildPath is not exist : ${buildPath}"
}
Integer result = sh(script: "dotnet publish ${buildPath} -c Release -o ${publishFolderPath}",
returnStatus: true)
echo "result : ${result}"
if (result == 0) {
echo 'Publish Project successfully'
} else {
error 'Publish Project failed'
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
//Thienvv - nén file
void compressItems(String compressedFilePath, String parentFolderPath) {
echo "Starting compression of the entire folder into a zip file : ${compressedFilePath}"
try {
if (fileExists(compressedFilePath)) {
echo "Old ZIP file exists. Deleting: ${compressedFilePath}"
sh "rm -f ${compressedFilePath}"
} else {
echo 'No old ZIP file found.'
}
if (!fileExists(parentFolderPath)) {
error "parentFolderPath is not exist : ${parentFolderPath}"
}
dir(parentFolderPath) {
// Thực hiện lệnh zip để nén tất cả các file trong thư mục
Integer result = sh(script: "zip -r ${compressedFilePath} * ", returnStatus: true)
// Kiểm tra kết quả
if (result == 0) {
echo "Compression completed successfully: ${compressedFilePath}"
} else {
error "Compression failed with exit code: ${result}."
}
}
} catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
void uploadToNexus(String nexusUsername, String nexusPassword, String compressedFilePath, String uploadUrl) {
echo "Starting upload ${compressedFilePath} To Nexus"
try {
// Truyền các biến môi trường vào lệnh sh mà không lộ ra trong log
String result = sh(script: """
curl -u ${nexusUsername}:${nexusPassword} --upload-file ${compressedFilePath} ${uploadUrl} -w '%{http_code}'
""", returnStdout: true).trim()
if (result == '200' || result == '201') {
echo 'uploadToNexus successfully'
} else {
error "uploadToNexus failed, HTTP status: ${result}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
def createMetadataFile(
String metadataFileName,
String groupId,
String artifactId,
String version,
String nexusUrl,
String nexusArtifactName) {
echo 'Starting create metadata file'
try {
// Tạo metadata
metadata = [
groupId: groupId,
artifactId: artifactId,
version: version,
nexusUrl: nexusUrl,
nexusArtifactName: nexusArtifactName
]
// Ghi metadata vào file JSON
writeJSON file: "${metadataFileName}", json: metadata
if (!fileExists(metadataFileName)) {
error "metadataFileName is not exist : ${metadataFileName}"
}
}
catch (Exception e) {
echo "[ERROR] Unexpected error: ${e.message}"
throw e
}
}
+28 -21
View File
@@ -1,32 +1,43 @@
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['prod', 'uat'], description: 'Choose Environment')
choice(name: 'ENV', choices: ['uat', 'production'], description: 'Choose Environment')
string(name: 'CI_JOB_BUILD_NUMBER', defaultValue: '', description: 'Build number of CI Job')
}
environment {
PROJECT_NAME = 'acp'
CI_JOB_NAME_UAT = 'CI-UAT-FE-ACP' // tên của job build code môi trường uat
CI_JOB_NAME_PROD = 'CI-PROD-FE-ACP' // tên của job build code môi trường prod
CI_JOB_NAME_PRODUCTION = 'CI-PRODUCTION-FE-ACP' // tên của job build code môi trường beta
CI_JOB_METADATA_FILENAME = "${params.ENV}_${PROJECT_NAME}_metadata.json" // tên file metadata đã được lưu từ job build code
GIT_PAT_CREDENTIALS_ID = 'b03f36c4-bba3-4764-94ca-b620651b2a68' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v2'
GIT_ANSIBLE_BRANCH = 'v3'
NEXUS_CREDENTIALS = credentials('Nexus_credential')
ANSIBLE_SSH_CONNECTION = 'root@103.166.183.172 -p 24700'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v2'
ANSIBLE_INVENTORY_PATH = "inventory/${params.ENV}.ini"
ANSIBLE_PLAYBOOK_PATH = 'playbooks/deploy_fe.yml'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v3'
ANSIBLE_PLAYBOOK_PATH = 'playbooks/frontend/deploy_acp_frontend.yml'
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Set up') {
steps {
script {
if (params.ENV == 'uat') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/uat/hosts.ini'
} else if (params.ENV == 'production') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/production/hosts.ini'
}
echo "ANSIBLE_INVENTORY_PATH is set to: ${env.ANSIBLE_INVENTORY_PATH}"
}
}
}
stage('Retrieve Artifact Metadata From CI Job') {
steps {
script {
@@ -34,8 +45,8 @@ pipeline {
case 'uat':
env.CI_JOB_NAME = env.CI_JOB_NAME_UAT
break
case 'prod':
env.CI_JOB_NAME = env.CI_JOB_NAME_PROD
case 'production':
env.CI_JOB_NAME = env.CI_JOB_NAME_PRODUCTION
break
default:
error "Unsupported environment: ${params.ENV}"
@@ -79,8 +90,6 @@ pipeline {
env.ANSIBLE_FOLDER_PATH,
env.ANSIBLE_INVENTORY_PATH,
env.ANSIBLE_PLAYBOOK_PATH,
params.ENV,
env.PROJECT_NAME,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME,
env.NEXUS_CREDENTIALS_USR,
@@ -95,14 +104,16 @@ pipeline {
}
success {
script {
def message = "Deploy thành công : FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thành công : FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "Deploy thất bại: FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thất bại: FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
@@ -204,8 +215,6 @@ def triggerAnsible(
String ansibleansibleFolderPath,
String inventoryPath,
String playbookPath,
String deployENV,
String projectName,
String nexusUrl,
String nexusArtifactName,
String nexusUsername,
@@ -217,9 +226,7 @@ def triggerAnsible(
ssh ${sshAnsibleConnection} "
cd ${ansibleansibleFolderPath} &&
ansible-playbook -i ${inventoryPath} ${playbookPath} \\
-e 'deploy_env=${deployENV} \\
project_name=${projectName} \\
nexus_url=${nexusUrl} \\
-e 'nexus_url=${nexusUrl} \\
artifact_name=${nexusArtifactName} \\
nexus_username=${nexusUsername} \\
nexus_password=${nexusPassword}' -vvvv
@@ -7,14 +7,14 @@ pipeline {
GIT_BRANCH = 'main'
PROJECT_NAME = 'acp'
ENV = 'prod'
ENV = 'production'
TRIGGER_JOB_NAME = 'CD_FE_ACP'
METADATA_FILENAME = "${env.ENV}_${PROJECT_NAME}_metadata.json"
NUXT_BUILD_FOLDER_PATH = "${env.WORKSPACE}"
OUTPUT_FOLDER_PATH = "${env.ENV}-${PROJECT_NAME}-output" //thư mục .output (sau khi build xong)
COMMAND_NUXT_INSTALL = 'npm install' //command install dependencies
COMMAND_NUXT_BUILD = "NITRO_OUTPUT=${OUTPUT_FOLDER_PATH} yarn linux-builder:production" // command build MT prod
COMMAND_NUXT_BUILD = "NITRO_OUTPUT=${OUTPUT_FOLDER_PATH} yarn linux-builder:beta" // command build MT prod
COMPRESSED_FILE_NAME = "${env.ENV}_${PROJECT_NAME}_output.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${COMPRESSED_FILE_NAME}"
@@ -29,8 +29,8 @@ pipeline {
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
@@ -103,8 +103,9 @@ pipeline {
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
try {
@@ -125,8 +126,9 @@ pipeline {
}
failure {
script {
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
+6 -6
View File
@@ -29,8 +29,7 @@ pipeline {
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
@@ -106,8 +105,8 @@ pipeline {
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
try {
@@ -128,8 +127,9 @@ pipeline {
}
failure {
script {
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
+38 -25
View File
@@ -1,32 +1,51 @@
pipeline {
agent any
parameters {
choice(name: 'ENV', choices: ['prod', 'uat'], description: 'Choose Environment')
choice(name: 'ENV', choices: ['uat', 'production'], description: 'Choose Environment')
choice(name: 'PORTAL_NAME', choices: ['ktdt', 'hnt'], description: 'Choose SITE NAME')
string(name: 'CI_JOB_BUILD_NUMBER', defaultValue: '', description: 'Build number of CI Job')
}
environment {
PROJECT_NAME = 'portal'
CI_JOB_NAME_UAT = 'CI-UAT-FE-PORTAL' // tên của job build code môi trường uat
CI_JOB_NAME_PROD = 'CI-PROD-FE-PORTAL' // tên của job build code môi trường prod
CI_JOB_NAME_PRODUCTION = 'CI-PRODUCTION-FE-PORTAL' // tên của job build code môi trường prod
CI_JOB_METADATA_FILENAME = "${params.ENV}_${PROJECT_NAME}_metadata.json" // tên file metadata đã được lưu từ job build code
GIT_PAT_CREDENTIALS_ID = 'b03f36c4-bba3-4764-94ca-b620651b2a68' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v2'
CI_JOB_METADATA_FILENAME = "${env.ENV}_${env.PROJECT_NAME}_${params.PORTAL_NAME}_metadata.json" // tên file metadata đã được lưu từ job build code
NEXUS_CREDENTIALS = credentials('Nexus_credential')
ANSIBLE_SSH_CONNECTION = 'root@103.166.183.172 -p 24700'
ANSIBLE_FOLDER_PATH = '/srv/ansible_v2'
ANSIBLE_INVENTORY_PATH = "inventory/${params.ENV}.ini"
ANSIBLE_PLAYBOOK_PATH = 'playbooks/deploy_fe_portal.yml'
GIT_PAT_CREDENTIALS_ID = 'b03f36c4-bba3-4764-94ca-b620651b2a68' // Id của Personal Access Token lưu trên jenkins
GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git'
GIT_ANSIBLE_BRANCH = 'v3'
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
ANSIBLE_FOLDER_PATH = '/srv/ansible_v3'
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Set up') {
steps {
script {
if (params.ENV == 'uat') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/uat/hosts.ini'
} else if (params.ENV == 'production') {
env.ANSIBLE_INVENTORY_PATH = 'inventory/production/hosts.ini'
}
echo "ANSIBLE_INVENTORY_PATH is set to: ${env.ANSIBLE_INVENTORY_PATH}"
if (params.PORTAL_NAME == 'ktdt') {
env.ANSIBLE_PLAYBOOK_PATH = 'playbooks/frontend/deploy_ktdt_portal_frontend.yml'
} else if (params.PORTAL_NAME == 'hnt') {
env.ANSIBLE_PLAYBOOK_PATH = 'playbooks/frontend/deploy_hnt_portal_frontend.yml'
}
echo "ANSIBLE_PLAYBOOK_PATH is set to: ${env.ANSIBLE_PLAYBOOK_PATH}"
}
}
}
stage('Retrieve Artifact Metadata From CI Job') {
steps {
script {
@@ -34,8 +53,8 @@ pipeline {
case 'uat':
env.CI_JOB_NAME = env.CI_JOB_NAME_UAT
break
case 'prod':
env.CI_JOB_NAME = env.CI_JOB_NAME_PROD
case 'production':
env.CI_JOB_NAME = env.CI_JOB_NAME_PRODUCTION
break
default:
error "Unsupported environment: ${params.ENV}"
@@ -79,8 +98,6 @@ pipeline {
env.ANSIBLE_FOLDER_PATH,
env.ANSIBLE_INVENTORY_PATH,
env.ANSIBLE_PLAYBOOK_PATH,
params.ENV,
env.PROJECT_NAME,
env.NEXUS_URL,
env.NEXUS_ARTIFACT_NAME,
env.NEXUS_CREDENTIALS_USR,
@@ -95,14 +112,14 @@ pipeline {
}
success {
script {
def message = "Deploy thành công : FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thành công : FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
failure {
script {
def message = "Deploy thất bại: FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Deploy thất bại: FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
@@ -204,8 +221,6 @@ def triggerAnsible(
String ansibleansibleFolderPath,
String inventoryPath,
String playbookPath,
String deployENV,
String projectName,
String nexusUrl,
String nexusArtifactName,
String nexusUsername,
@@ -217,9 +232,7 @@ def triggerAnsible(
ssh ${sshAnsibleConnection} "
cd ${ansibleansibleFolderPath} &&
ansible-playbook -i ${inventoryPath} ${playbookPath} \\
-e 'deploy_env=${deployENV} \\
project_name=${projectName} \\
nexus_url=${nexusUrl} \\
-e 'nexus_url=${nexusUrl} \\
artifact_name=${nexusArtifactName} \\
nexus_username=${nexusUsername} \\
nexus_password=${nexusPassword}' -vvvv
@@ -1,43 +1,67 @@
pipeline {
agent any
options { disableConcurrentBuilds(abortPrevious: true) }
parameters {
choice(name: 'PORTAL_NAME', choices: ['ktdt', 'hnt'], description: 'Choose PORTAL NAME')
}
environment {
GIT_CREDENTIALSID = 'b03f36c4-bba3-4764-94ca-b620651b2a68'
GIT_URL = 'http://work.gct.com.vn/anhln/PORTAL_2025.git'
GIT_BRANCH = 'main'
ENV = 'prod'
GIT_KTDT_BRANCH = 'beta_kinhtedothi'
GIT_HNT_BRANCH = 'beta_hanoitimes'
ENV = 'production'
PROJECT_NAME = 'portal'
TRIGGER_JOB_NAME = 'CD-FE-PORTAL'
METADATA_FILENAME = "${env.ENV}_${env.PROJECT_NAME}_metadata.json"
METADATA_FILENAME = "${env.ENV}_${env.PROJECT_NAME}_${params.PORTAL_NAME}_metadata.json"
NUXT_BUILD_FOLDER_PATH = "${env.WORKSPACE}"
OUTPUT_FOLDER_PATH = ".output" //thư mục .output (sau khi build xong)
COMMAND_NUXT_INSTALL = 'npm install' //command install dependencies
COMMAND_NUXT_BUILD = "yarn build:production" // command build MT prod
OUTPUT_FOLDER_PATH = "${env.ENV}-${env.PROJECT_NAME}-${params.PORTAL_NAME}-output" //thư mục .output
COMPRESSED_FILE_NAME = "${env.ENV}_${env.PROJECT_NAME}_output.zip" // tên file nén
COMMAND_NUXT_INSTALL = 'npm install' //command install dependencies
COMMAND_NUXT_BUILD = "NITRO_OUTPUT=${env.OUTPUT_FOLDER_PATH} yarn build:beta" // command build
COMPRESSED_FILE_NAME = "${env.ENV}_${env.PROJECT_NAME}_${params.PORTAL_NAME}_output.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${env.COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-${env.PROJECT_NAME}-frontend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = "${env.ENV}-${env.PROJECT_NAME}-frontend"
ARTIFACT_ID = "${env.ENV}-${env.PROJECT_NAME}-${params.PORTAL_NAME}-frontend"
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
}
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Configure GIT_BRANCH') {
steps {
script {
switch (params.PORTAL_NAME) {
case 'ktdt':
env.GIT_BRANCHO = env.GIT_KTDT_BRANCH
break
case 'hnt':
env.GIT_BRANCHO = env.GIT_HNT_BRANCH
break
default:
error "Unsupported PORTAL_NAME: ${params.PORTAL_NAME}"
}
}
echo "Branch được thiết lập là: ${env.GIT_BRANCHO}"
}
}
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH as String)
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCHO as String)
}
}
@@ -106,13 +130,14 @@ pipeline {
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME}- \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
try {
def buildResult = build job: "${TRIGGER_JOB_NAME}", parameters:[
string(name: 'ENV', value: env.ENV),
string(name: 'PORTAL_NAME', value: params.PORTAL_NAME),
string(name: 'CI_JOB_BUILD_NUMBER', value: env.BUILD_NUMBER)
],
propagate: false
@@ -128,8 +153,8 @@ pipeline {
}
failure {
script {
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME} - \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}
+42 -15
View File
@@ -1,42 +1,67 @@
pipeline {
agent any
options { disableConcurrentBuilds(abortPrevious: true) }
parameters {
choice(name: 'PORTAL_NAME', choices: ['ktdt', 'hnt'], description: 'Choose PORTAL NAME')
}
environment {
GIT_CREDENTIALSID = 'b03f36c4-bba3-4764-94ca-b620651b2a68'
GIT_URL = 'http://work.gct.com.vn/anhln/PORTAL_2025.git'
GIT_BRANCH = 'main'
GIT_KTDT_BRANCH = 'uat_kinhtedothi'
GIT_HNT_BRANCH = 'uat_hanoitimes'
ENV = 'uat'
PROJECT_NAME = 'portal'
TRIGGER_JOB_NAME = 'CD-FE-PORTAL'
METADATA_FILENAME = "${env.ENV}_${env.PROJECT_NAME}_metadata.json"
METADATA_FILENAME = "${env.ENV}_${env.PROJECT_NAME}_${params.PORTAL_NAME}_metadata.json"
NUXT_BUILD_FOLDER_PATH = "${env.WORKSPACE}"
OUTPUT_FOLDER_PATH = ".output" //thư mục .output (sau khi build xong)
COMMAND_NUXT_INSTALL = 'npm install' //command install dependencies
COMMAND_NUXT_BUILD = "yarn build" // command build MT uat
OUTPUT_FOLDER_PATH = "${env.ENV}-${env.PROJECT_NAME}-${params.PORTAL_NAME}-output" //thư mục .output
COMPRESSED_FILE_NAME = "${env.ENV}_${env.PROJECT_NAME}_output.zip" // tên file nén
COMMAND_NUXT_INSTALL = 'npm install' //command install dependencies
COMMAND_NUXT_BUILD = "NITRO_OUTPUT=${env.OUTPUT_FOLDER_PATH} yarn build" // command build MT uat
COMPRESSED_FILE_NAME = "${env.ENV}_${env.PROJECT_NAME}_${params.PORTAL_NAME}_output.zip" // tên file nén
COMPRESSED_FILE_PATH = "${env.WORKSPACE }/${env.COMPRESSED_FILE_NAME}"
NEXUS_CREDENTIALS = credentials('Nexus_credential')
NEXUS_REPO_URL = "https://nexus.gct.com.vn/repository/${env.ENV}-${env.PROJECT_NAME}-frontend"
GROUP_ID = 'vn.kinhtedothi'
ARTIFACT_ID = "${env.ENV}-${env.PROJECT_NAME}-frontend"
ARTIFACT_ID = "${env.ENV}-${env.PROJECT_NAME}-${params.PORTAL_NAME}-frontend"
PACKAGING = 'zip'
VERSION = '1.0.0' // Phiên bản cơ bản
TIMESTAMP = new Date().format('yyyyMMdd.HH', TimeZone.getTimeZone('UTC'))
FULL_VERSION = "${env.VERSION}-${env.TIMESTAMP}-${env.BUILD_NUMBER}" // Tạo phiên bản hoàn chỉnh
TELEGRAM_CHAT_ID = -4678013464
TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN')
SLACK_TOKEN = credentials('SLACK_TOKEN')
}
stages {
stage('Configure GIT_BRANCH') {
steps {
script {
switch (params.PORTAL_NAME) {
case 'ktdt':
env.GIT_BRANCHO = env.GIT_KTDT_BRANCH
break
case 'hnt':
env.GIT_BRANCHO = env.GIT_HNT_BRANCH
break
default:
error "Unsupported PORTAL_NAME: ${params.PORTAL_NAME}"
}
}
echo "Branch được thiết lập là: ${env.GIT_BRANCHO}"
}
}
stage('Checkout') {
steps {
// Checkout mã nguồn từ Gitea
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCH as String)
checkoutFromGit(env.GIT_URL as String, env.GIT_CREDENTIALSID as String, env.GIT_BRANCHO as String)
}
}
@@ -105,14 +130,16 @@ pipeline {
success {
echo "Job '${env.JOB_NAME}' completed successfully. Attempting to trigger Job '${TRIGGER_JOB_NAME}'..."
script {
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thành công : FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} - Portal_Name ${params.PORTAL_NAME} \n ${currentBuild.fullDisplayName}\n${env.BUILD_URL} \n Đang tiến hành Deploy...!"
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
script {
try {
def buildResult = build job: "${TRIGGER_JOB_NAME}", parameters:[
string(name: 'ENV', value: env.ENV),
string(name: 'CI_JOB_BUILD_NUMBER', value: env.BUILD_NUMBER)
string(name: 'PORTAL_NAME', value: params.PORTAL_NAME),
string(name: 'CI_JOB_BUILD_NUMBER', value: env.BUILD_NUMBER),
],
propagate: false
if (buildResult.result != 'SUCCESS') {
@@ -127,8 +154,8 @@ pipeline {
}
failure {
script {
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\""
def message = "Build thất bại: FRONTEND - Môi trường ${env.ENV} - Dự án ${env.PROJECT_NAME} - Site ${params.PORTAL_NAME} \n ${currentBuild.fullDisplayName}\n Kiểm tra tại đây ${env.BUILD_URL}."
sh """curl -X POST -H 'Content-type: application/json' --data '{"text":"${message}"}' https://hooks.slack.com/services/T08TS987F4N/B08TS9SC2QN/${SLACK_TOKEN}"""
}
}
}