diff --git a/be/be-acp/ci-uat-acp-backend.Jenkinsfile b/be/be-acp/ci-uat-acp-backend.Jenkinsfile new file mode 100644 index 0000000..cb89f8a --- /dev/null +++ b/be/be-acp/ci-uat-acp-backend.Jenkinsfile @@ -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-acp' + + ENV = 'uat' + 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 + + TELEGRAM_CHAT_ID = -4678013464 + TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_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}\"" + } + 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 -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\"" + } + } + } +} + +//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: """ + + + + + +""" + + // 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 + } + } diff --git a/be/be-portal/ci-uat-portal-backend.Jenkinsfile b/be/be-portal/ci-uat-portal-backend.Jenkinsfile new file mode 100644 index 0000000..8cdaaa4 --- /dev/null +++ b/be/be-portal/ci-uat-portal-backend.Jenkinsfile @@ -0,0 +1,391 @@ +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-portal' + + ENV = 'uat' + 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 + + TELEGRAM_CHAT_ID = -4678013464 + TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_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}\"" + } + script { + try { + build job: "${TRIGGER_JOB_NAME}", parameters:[ + string(name: 'ENV', value: env.ENV), + 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}" + throw e + } + } + } + + 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 -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\"" + } + } + } + } +} + +//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: """ + + + + + +""" + + // 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 + } + } diff --git a/be/be-resource/ci-uat-resource-backend.Jenkinsfile b/be/be-resource/ci-uat-resource-backend.Jenkinsfile new file mode 100644 index 0000000..6dd534b --- /dev/null +++ b/be/be-resource/ci-uat-resource-backend.Jenkinsfile @@ -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 + + TELEGRAM_CHAT_ID = -4678013464 + TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_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}\"" + } + 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 -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\"" + } + } + } +} + +//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: """ + + + + + +""" + + // 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 + } + }