added files
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.stages.deployJar
|
||||
|
||||
|
||||
def run(Map config){
|
||||
// get required variables from config
|
||||
def automation_repo_name = config.run_automation.repo_name
|
||||
def branch = config.run_automation.branch
|
||||
def deployObj = new deployJar()
|
||||
|
||||
//deploy service(farmiso) on specified machine
|
||||
deployObj.run(config)
|
||||
|
||||
|
||||
checkoutAutomationRepo(automation_repo_name, branch)
|
||||
|
||||
runAutomationSuite(automation_repo_name)
|
||||
|
||||
}
|
||||
|
||||
def checkoutAutomationRepo(String automation_repo_name, String branch){
|
||||
try{
|
||||
stage('Checkout automation repo'){
|
||||
sh "rm -rf ${automation_repo_name}; git clone git@github.com:Meesho/${automation_repo_name}.git -b ${branch}"
|
||||
echo "automation repo cloned"
|
||||
}
|
||||
}
|
||||
catch( Exception e) {
|
||||
env.msg = "Error cloning automation repo. Please check console output for more details."
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def runAutomationSuite(String automation_repo_name){
|
||||
try{
|
||||
stage('Run Automation Suite'){
|
||||
dir("$automation_repo_name"){
|
||||
run_cmd = "mvn test" //specific to Farmiso as of now.
|
||||
sh "$run_cmd"
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e) {
|
||||
env.msg = "Error running automation suite. Please check console output for more details."
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
finally{
|
||||
//publish HTML test report
|
||||
dir("$automation_repo_name"){
|
||||
archiveArtifacts artifacts: "test-output/*.*"
|
||||
|
||||
|
||||
publishHTML (target: [
|
||||
allowMissing: false,
|
||||
alwaysLinkToLastBuild: false,
|
||||
keepAll: true,
|
||||
reportDir: 'test-output',
|
||||
reportFiles: 'index.html',
|
||||
reportName: "Farmiso-Test-Automation-Report"
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.stages.deployArgoCD
|
||||
import com.meesho.stages.buildObjHelper
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
|
||||
def run(Map config) {
|
||||
def btObj = new buTeamMapping()
|
||||
def helperObj = new buildObjHelper()
|
||||
def buildObj = helperObj.run(config.dockerBuildVersion)
|
||||
def (tag , deployArgo) = buildObj.buildDckr(config)
|
||||
release(config, tag, deployArgo)
|
||||
}
|
||||
|
||||
def release(Map config, String tag, boolean deployArgo) {
|
||||
//TODO: move params to run function and move argoCD call there as well.
|
||||
def btObj = new buTeamMapping()
|
||||
def repo_name = config.repo_name
|
||||
def branch_name = "${env.BRANCH_NAME}"
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
env.TAG = tag
|
||||
|
||||
log.info("tag is ${tag}")
|
||||
|
||||
def bu = btObj.get_bu_initials(config.bu)
|
||||
def notify_channel = config.notify_channel && config.notify_channel != '' ? config.notify_channel : 'canary-status'
|
||||
validate('bu', bu, config.bu)
|
||||
validate('team', team, config.team)
|
||||
def build_user = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
|
||||
env.deployArgo = deployArgo
|
||||
// Calling Ringmaster
|
||||
if (build_user != "ringmaster-bot" && build_user!="turbo-turtle" && build_user != "toolchain-jenkins"){
|
||||
if (env.cicd_environment == 'ftr') {
|
||||
log.warning("**********!!!!!! Deployments in '${env.cicd_environment}' env are not supported !!!!!!**********")
|
||||
log.info("****** To deploy in Staging, Please merge the changes to your 'develop'/'development' branch and deploy ******")
|
||||
return
|
||||
}
|
||||
if (deployArgo) {
|
||||
def argoCd_obj = new deployArgoCD()
|
||||
def deployment_order = config.deployment_order
|
||||
def dockerBuildVersion = config.dockerBuildVersion
|
||||
argoCd_obj.run(repo_name, deployment_order, tag, team, dockerBuildVersion, notify_channel)
|
||||
} else {
|
||||
log.info("Skipping ArgoCD deployment for ${repo_name}")
|
||||
}
|
||||
|
||||
if (config.distribution_id) {
|
||||
stage(stageName('Refreshing CDN file')) {
|
||||
def folder_name = config.chunk_base_path ?: repo_name.split('_')[-1]
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws cloudfront create-invalidation --distribution-id ${config.distribution_id} --paths \"/${folder_name}/remoteEntry.js\"")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
// echo "Skipping - CDN Invalidation"
|
||||
sh(script:"gcloud config set project ${env.GCPLBProject};gcloud compute url-maps invalidate-cdn-cache '${config.distribution_id}' --path \"/${folder_name}/remoteEntry.js\" --project='${env.GCPLBProject}' --async")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def validate(String name, String value, String printValue) {
|
||||
if (value == null) {
|
||||
log.error("Incorrect ${name} name ${printValue}")
|
||||
currentBuild.result = env.FAILURE
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.utilities.addSSHKey
|
||||
import com.meesho.utilities.gitActions
|
||||
import com.meesho.utilities.constructParam
|
||||
import com.meesho.utilities.dockerUtilities
|
||||
|
||||
|
||||
def buildDckr(Map config) {
|
||||
env.GOPRIVATE = 'github.com/Meesho'
|
||||
def buTeamMappingObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dockerParamObj = new getDockerParams()
|
||||
def addSshKeyObj = new addSSHKey()
|
||||
def dockerUtilObj = new dockerUtilities()
|
||||
|
||||
def team = buTeamMappingObj.get_team_initials(config.team)
|
||||
def modules = config.modules ?: ['module_less']
|
||||
def repoName = config.repo_name
|
||||
def dockerRepository = "${env.cicd_environment}/${team}/${repoName.toLowerCase()}"
|
||||
def tag = dockerParamObj.getTag(repoName)
|
||||
def dockerBindings = [:]
|
||||
def version = config.dockerBuildVersion.split('-')[-1]
|
||||
def constructParamObj = new constructParam()
|
||||
def repoType = config.repo_type ?: 'microservice'
|
||||
boolean skipSonarAndQualityGate = constructParamObj.skipSonarCheckForGo(config)
|
||||
echo "skipSonarAndQualityGate: ${skipSonarAndQualityGate}"
|
||||
String goVersion = config.goVersion ?: version
|
||||
boolean shouldDeployArgo = (config.deployArgo ?: false).toBoolean()
|
||||
boolean isConfigOnlyChange = false
|
||||
|
||||
// Ensure goVersion is in x.x.x format
|
||||
echo "goVersion: ${goVersion}"
|
||||
if (goVersion.split('\\.').size() == 2) {
|
||||
goVersion += '.0'
|
||||
}
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
tag = dockerParamObj.getTag(repoName)
|
||||
boolean allImagesExist = true
|
||||
|
||||
for (module in modules) {
|
||||
def moduleName = (module instanceof LinkedHashMap) ? module.keySet()[0] : module
|
||||
def modulePath = (moduleName == 'module_less') ? dockerRepository : "${dockerRepository}/${moduleName}"
|
||||
//TODO: building everything if one is missing -> create list of modules unbuild will only build those
|
||||
if (!dockerUtilObj.imageExists(env.registry, modulePath, tag)) {
|
||||
log.info("Toolchain: Image missing for ${moduleName} at ${modulePath}:${tag}. Proceeding with build.")
|
||||
allImagesExist = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if (allImagesExist) {
|
||||
log.info("Toolchain: All images found in registry for tag ${tag}. Skipping build step.")
|
||||
return [tag, shouldDeployArgo]
|
||||
}
|
||||
}
|
||||
stage(stageName('Check Config Changes and Get Latest Image Tag')) {
|
||||
(isConfigOnlyChange, shouldDeployArgo) = is_config_only_change_and_should_deploy_argo(repoName, shouldDeployArgo)
|
||||
log.info("Is just application config change? $isConfigOnlyChange")
|
||||
def param = new constructParam()
|
||||
if (env.CHANGE_ID && repoType == 'microservice') {
|
||||
def shouldValidateConfig = param.ValidateCacConfigForRepo(false, repoName)
|
||||
if (shouldValidateConfig) {
|
||||
log.info('************ Validate Config for CAC application.yml files ************')
|
||||
dir("$repoName") {
|
||||
writeFile file: 'validate_configs.py', text: libraryResource('com/meesho/validate_configs_v2.py')
|
||||
sh 'python3 validate_configs.py'
|
||||
}
|
||||
} else {
|
||||
log.info('************ Skipping Validation of CAC Config ************')
|
||||
}
|
||||
} else {
|
||||
log.info("Skipping Validation of CAC Config for ${repoType} repo type")
|
||||
log.info('************ Skipping Validation of CAC Config ************')
|
||||
}
|
||||
|
||||
if (isConfigOnlyChange) {
|
||||
log.info('Skipping the build, since it is just application config change')
|
||||
log.info('Getting latest image tag from GAR')
|
||||
def firstModule = modules[0]
|
||||
def firstModuleName = (firstModule instanceof LinkedHashMap) ? firstModule.keySet()[0] : firstModule
|
||||
def moduleDockerRepository = (firstModuleName == 'module_less') ? dockerRepository : "${dockerRepository}/${firstModuleName}"
|
||||
try {
|
||||
def latest_image = sh(
|
||||
script: "gcloud container images list-tags ${env.registry}/${moduleDockerRepository} --format='value(tags)' | sed '/^\$/d' | awk -F'-' '{print \$NF}' | sort | tail -1",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
echo "latest_image: ${latest_image}"
|
||||
if (latest_image == '') {
|
||||
log.info("No existing images found for ${env.registry}/${moduleDockerRepository}. Using generated tag: ${tag}")
|
||||
} else {
|
||||
tag = sh(
|
||||
script: "gcloud container images list-tags ${env.registry}/${moduleDockerRepository} --format='value(tags)' | tr ',' '\n' | grep ${latest_image}",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
}
|
||||
} catch (Exception e) {
|
||||
env.msg = 'Error getting latest docker image from GAR'
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error("${env.msg}\n${e.toString()}")
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
return [tag, shouldDeployArgo]
|
||||
}
|
||||
log.info('Proceeding with the build')
|
||||
}
|
||||
|
||||
stage(stageName('Scanning Sonar and Quality Gate')) {
|
||||
dir(repoName) {
|
||||
sonar_scan(repoName, skipSonarAndQualityGate, goVersion)
|
||||
}
|
||||
}
|
||||
if (currentBuild.result == 'UNSTABLE')
|
||||
{ return [tag, false] }
|
||||
|
||||
if (repoType != 'microservice') {
|
||||
log.info("Skipping Docker build for ${repoType} repo type")
|
||||
return [tag, shouldDeployArgo]
|
||||
}
|
||||
|
||||
stage(stageName('Building docker images')) {
|
||||
try {
|
||||
sh(script: 'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
|
||||
} catch (Exception e) {
|
||||
env.msg = "[Failure] Can't login to gcloud docker registry."
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error("${env.msg}. Error: ${e.toString()}")
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
dockerBindings['version'] = (version == 'go') ? '1.24.4' : version
|
||||
dockerBindings['base_dir'] = config.base_dir ?: false
|
||||
dockerBindings['build_registry'] = env.buildRegistry
|
||||
dockerBindings['go_proxy'] = env.goProxyUrl
|
||||
dockerBindings['repo_name'] = repoName
|
||||
if (config.containsKey('copy_file')) {
|
||||
String recursive = config.copy_file.recursive ? ' -r' : ''
|
||||
dir(repoName) {
|
||||
dir('copied_files') {
|
||||
sh(script: "gsutil cp${recursive} ${config.copy_file.path} .")
|
||||
}
|
||||
}
|
||||
dockerBindings['copy_file'] = true
|
||||
dockerBindings['copy_target'] = config.copy_file.target ?: '/app/'
|
||||
dockerBindings['base_dir'] = config.base_dir ?: false
|
||||
} else {
|
||||
dockerBindings['copy_file'] = false
|
||||
}
|
||||
|
||||
try {
|
||||
dir(repoName) {
|
||||
addSshKeyObj.create()
|
||||
if (!fileExists('Dockerfile')) {
|
||||
def moduleBuilds = [:]
|
||||
for (m in modules) {
|
||||
def moduleRef = m
|
||||
def moduleName = (moduleRef instanceof LinkedHashMap) ? moduleRef.keySet()[0] : moduleRef
|
||||
moduleBuilds["build-${moduleName}"] = {
|
||||
def localBindings = dockerBindings.clone()
|
||||
localBindings['module_property'] = (moduleRef instanceof LinkedHashMap) ? moduleRef[moduleName] : [:]
|
||||
localBindings['kafka'] = (localBindings['module_property'].kafka) ? '-kafka' : ''
|
||||
localBindings['module'] = moduleName
|
||||
constructObj.renderTemplate(localBindings, 'go-Dockerfile', "Dockerfile-${moduleName}")
|
||||
sh "cat Dockerfile-${moduleName}"
|
||||
def moduleDockerRepository = (moduleRef == 'module_less') ? dockerRepository : "${dockerRepository}/${moduleName}"
|
||||
sh(script: 'tar -cf only-mods.tar $(git ls-files "go.mod" "go.sum" "**/go.mod" "**/go.sum" 2>/dev/null || find . -name go.mod -o -name go.sum)')
|
||||
sh(script: "set +x && docker build --tag ${env.registry}/${moduleDockerRepository}:${tag} -f Dockerfile-${moduleName} .")
|
||||
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
|
||||
dockerUtilObj.retryDockerPush("docker push ${env.registry}/${moduleDockerRepository}:${tag}")
|
||||
} else {
|
||||
log.info("Skipping Docker Push - ${env.cicd_environment} env")
|
||||
}
|
||||
sh(script: "rm -rf Dockerfile-${moduleName}")
|
||||
}
|
||||
}
|
||||
parallel moduleBuilds
|
||||
} else {
|
||||
sh 'cat Dockerfile'
|
||||
def moduleDockerRepository = dockerRepository // default for repo root
|
||||
if (modules && modules[0] != 'module_less') {
|
||||
def firstModule = modules[0]
|
||||
def firstModuleName = (firstModule instanceof LinkedHashMap) ? firstModule.keySet()[0] : firstModule
|
||||
moduleDockerRepository = dockerRepository + '/' + firstModuleName
|
||||
}
|
||||
def pushOrNot = (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') ? '--push' : ''
|
||||
if (!pushOrNot) {
|
||||
log.info("Skipping Docker Push - ${env.cicd_environment} env")
|
||||
}
|
||||
sh(script: "docker build --tag ${env.registry}/${moduleDockerRepository}:${tag} ${pushOrNot} .")
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
env.msg = 'Error in building DockerFile Or Pushing To ECR'
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error("${env.msg}. Error: ${e.toString()}")
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
return [tag, shouldDeployArgo]
|
||||
}
|
||||
}
|
||||
|
||||
def is_config_only_change_and_should_deploy_argo(String repoName, boolean deployArgo) {
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
return [false, deployArgo]
|
||||
}
|
||||
def gitObj = new gitActions()
|
||||
def configFiles = []
|
||||
boolean shouldDeployArgoResult = deployArgo
|
||||
boolean isConfigOnlyChange = false
|
||||
|
||||
def changedFiles = env.CHANGE_ID ?
|
||||
gitObj.fetchDiffFilesForPullRequest(repoName, env.CHANGE_TARGET) :
|
||||
gitObj.fetchDiffFilesForPushRequest(repoName)
|
||||
|
||||
if (!changedFiles) {
|
||||
return [isConfigOnlyChange, shouldDeployArgoResult]
|
||||
}
|
||||
|
||||
for (file in changedFiles.split('\n')) {
|
||||
if (!file.startsWith('configs/')) {
|
||||
isConfigOnlyChange = false
|
||||
return [isConfigOnlyChange, shouldDeployArgoResult]
|
||||
}
|
||||
isConfigOnlyChange = true
|
||||
configFiles << file
|
||||
}
|
||||
|
||||
if (configFiles && deployArgo && isConfigOnlyChange) {
|
||||
def hasEnvironmentConfig = configFiles.any { it.contains(env.cicd_environment) }
|
||||
if (!hasEnvironmentConfig) {
|
||||
shouldDeployArgoResult = false
|
||||
echo "Config changes don't contain environment: ${env.cicd_environment}"
|
||||
}
|
||||
}
|
||||
return [isConfigOnlyChange, shouldDeployArgoResult]
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to execute sonar scan
|
||||
* @param repoName: repository name
|
||||
* @param skipSonarAndQualityGate: boolean parameter to skip sonar scan
|
||||
* @param goVersion: Go version string
|
||||
*/
|
||||
def sonar_scan(String repoName, boolean skipSonarAndQualityGate, String goVersion) {
|
||||
if (skipSonarAndQualityGate) {
|
||||
log.info('Sonar scan is skipped. Marking this stage as passed.')
|
||||
return
|
||||
}
|
||||
stage(stageName('Running sonar scan')) {
|
||||
try {
|
||||
withSonarQubeEnv(env.sonarEnv) {
|
||||
echo "env.sonarEnv: ${env.sonarEnv}"
|
||||
echo "env.BRANCH_NAME: ${env.BRANCH_NAME}"
|
||||
def exclusions = ""
|
||||
if (!fileExists('sonar-project.properties')) {
|
||||
exclusions = " -Dsonar.exclusions=**/*_test.go,**/mock_*.go,**/mock.go,**/*.pb.go,**/*.proto,**/model.go"
|
||||
}else{
|
||||
exclusions = " -Dproject.settings=`pwd`/sonar-project.properties"
|
||||
}
|
||||
|
||||
def scannerCommand = "sonar-scanner -Dsonar.projectKey=${repoName} -Dsonar.go.coverage.reportPaths=./cov.out -Dsonar.branch.name=${env.BRANCH_NAME} -Dsonar.ws.timeout=120 ${exclusions}"
|
||||
echo "env.SONAR_HOST_URL: ${env.SONAR_HOST_URL}"
|
||||
env.PATH = "/usr/local/sonar-scanner/sonar-scanner-5.0.1.3006-linux/bin:${env.PATH}"
|
||||
def response = sh(
|
||||
script: "curl -s -w '\n%{http_code}' -u ${env.SONAR_AUTH_TOKEN}: ${env.SONAR_HOST_URL}/api/navigation/component?component=${repoName}",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
|
||||
def responseLines = response.split('\n')
|
||||
def statusCode = responseLines[-1]
|
||||
def responseBody = responseLines[0..-2].join('\n')
|
||||
|
||||
log.info("SonarQube API Response Code: ${statusCode}")
|
||||
log.info("SonarQube API Response Body: ${responseBody}")
|
||||
|
||||
def projectExists = (statusCode == '200')
|
||||
if (!projectExists && env.CHANGE_ID) {
|
||||
log.info("Project ${repoName} does not exist. Creating it via a bootstrap scan on the target branch.")
|
||||
|
||||
def targetBranch = env.CHANGE_TARGET ?: 'develop'
|
||||
echo "targetBranch: ${targetBranch}"
|
||||
sh "sonar-scanner \
|
||||
-Dsonar.projectKey=${repoName} \
|
||||
-Dsonar.projectName=${repoName} \
|
||||
-Dsonar.branch.name=${targetBranch} \
|
||||
-Dsonar.sources=. \
|
||||
-Dsonar.scm.disabled=true \
|
||||
-Dsonar.ws.timeout=120"
|
||||
log.info("Bootstrap complete. Project created.")
|
||||
}else{
|
||||
echo "Project ${repoName} already exists. Skipping bootstrap scan."
|
||||
}
|
||||
|
||||
if (env.CHANGE_ID) {
|
||||
echo "env.CHANGE_ID: ${env.CHANGE_ID}"
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
|
||||
}
|
||||
scannerCommand = "sonar-scanner -Dsonar.projectKey=${repoName} -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Meesho/${repoName} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.go.coverage.reportPaths=./cov.out -Dsonar.ws.timeout=120${exclusions}"
|
||||
echo "scannerCommand: ${scannerCommand}"
|
||||
}
|
||||
downloadGoFromJFrog(goVersion)
|
||||
sh(script: "GOPROXY=${env.goProxyUrl},direct && go mod tidy")
|
||||
int testExitCode = sh(script: 'go test -short -coverprofile=./cov.out ./...', returnStatus: true)
|
||||
if (testExitCode != 0) {
|
||||
error('Go tests failed.')
|
||||
}
|
||||
echo "scannerCommand: ${scannerCommand}"
|
||||
sh(script: scannerCommand)
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error in running sonar scan: ${e}")
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
stage(stageName('Quality Gate')) {
|
||||
try {
|
||||
if (!env.CHANGE_ID || env.cicd_environment == 'int') {
|
||||
log.info('Skipping quality gate check on Branches/Pre-Prod. Marking this stage as passed.')
|
||||
} else {
|
||||
timeout(time: 600, unit: 'SECONDS') {
|
||||
def qg = waitForQualityGate()
|
||||
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
|
||||
if (qg.status != 'OK') {
|
||||
log.warning("Quality gate failed: ${qg.status}")
|
||||
error "Stopping pipeline due to quality gate failure."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (Exception e) {
|
||||
echo "Error in quality gate: ${e.message}"
|
||||
unstable('Quality Gate Failed !')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to download Go binary from JFrog
|
||||
* @param goVersion: Go version string
|
||||
*/
|
||||
def downloadGoFromJFrog(String goVersion) {
|
||||
try {
|
||||
echo "env.cicd_environment: ${env.cicd_environment}"
|
||||
|
||||
def jfrogUrl = (env.cicd_environment == 'prd' || env.cicd_environment == 'int') ?
|
||||
'https://jfrog-prd.meeshogcp.in' :
|
||||
'https://jfrog-dev.meeshogcp.in'
|
||||
|
||||
def repo = 'devops-tools-local'
|
||||
def goTarball = "go${goVersion}.linux-amd64.tar.gz"
|
||||
def jfrogPath = "${jfrogUrl}/artifactory/${repo}/go/${goTarball}"
|
||||
|
||||
def jfrogUser = ''
|
||||
def jfrogPass = ''
|
||||
def credentialId = (env.cicd_environment == 'prd' || env.cicd_environment == 'int') ?
|
||||
'jfrog-prd-credentials' : 'jfrog-stg-credentials'
|
||||
echo "Using credential ID: ${credentialId}"
|
||||
withCredentials([usernamePassword(credentialsId: credentialId,
|
||||
usernameVariable: 'JFROG_USER',
|
||||
passwordVariable: 'JFROG_PASS')]) {
|
||||
jfrogUser = env.JFROG_USER
|
||||
jfrogPass = env.JFROG_PASS
|
||||
|
||||
log.info("Attempting to download Go ${goVersion} from JFrog: ${jfrogPath}")
|
||||
|
||||
def downloadStatus = sh(script: """
|
||||
curl -u "${env.JFROG_USER}:${env.JFROG_PASS}" \
|
||||
-fLO "${jfrogPath}" \
|
||||
--fail --silent --show-error
|
||||
""", returnStatus: true)
|
||||
|
||||
if (downloadStatus == 0 && fileExists(goTarball)) {
|
||||
log.info("Successfully downloaded Go ${goVersion} from JFrog")
|
||||
} else {
|
||||
echo("WARN: Go ${goVersion} not found in JFrog. Falling back to go.dev...")
|
||||
sh(script: "curl -LO https://go.dev/dl/${goTarball}")
|
||||
|
||||
log.info("Uploading downloaded Go ${goVersion} to JFrog for future use")
|
||||
sh(script: """
|
||||
curl -u "${env.JFROG_USER}:${env.JFROG_PASS}" \
|
||||
-T "${goTarball}" \
|
||||
"${jfrogPath}" \
|
||||
--fail --silent --show-error || echo "Upload to JFrog failed, but continuing..."
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
sh(script: "tar -xvzf ${goTarball} -C /usr/local", returnStdout: true)
|
||||
sh(script: "rm -Rf ${goTarball}")
|
||||
env.PATH = "/usr/local/go/bin:${env.PATH}"
|
||||
|
||||
// Verify installation
|
||||
sh(script: "go version")
|
||||
|
||||
} catch (Exception e) {
|
||||
echo("ERROR: Failed to download Go from JFrog: ${e.message}")
|
||||
|
||||
// Final fallback
|
||||
sh(script: "curl -LO https://go.dev/dl/go${goVersion}.linux-amd64.tar.gz")
|
||||
sh(script: "tar -xvzf go${goVersion}.linux-amd64.tar.gz -C /usr/local", returnStdout: true)
|
||||
sh(script: "rm -Rf go${goVersion}.linux-amd64.tar.gz")
|
||||
env.PATH = "/usr/local/go/bin:${env.PATH}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.stages.checkOut
|
||||
|
||||
/*
|
||||
Function to define the flow of entire build, this function will call different stages related to maven build
|
||||
*/
|
||||
def run(Map config) {
|
||||
// get required variables from config
|
||||
def checkoutObj = new checkOut()
|
||||
def repo_name = config.repo_name
|
||||
def args = config.build_args ?: ''
|
||||
def skip_test = config.skip_test ?: false
|
||||
def skip_sonar = config.skip_sonar ?: false
|
||||
def push_to_jfrog = config.push_to_jfrog ?: false
|
||||
def push_to_s3 = config.push_to_s3 ?: false
|
||||
def branch_name = "${env.BRANCH_NAME}"
|
||||
if (branch_name == 'gcp-main' || branch_name == 'gcp-master') {
|
||||
push_to_jfrog = config.containsKey('push_to_jfrog') ? config.push_to_jfrog : false
|
||||
}
|
||||
def version = getVersion("${repo_name}")
|
||||
|
||||
if (env.hot_fix) {
|
||||
skip_test = true
|
||||
skip_sonar = true
|
||||
push_to_jfrog = false
|
||||
}
|
||||
|
||||
// call the stages
|
||||
checkS3(repo_name, branch_name, version, push_to_s3)
|
||||
build(repo_name, skip_test, args)
|
||||
sonar_scan(repo_name, skip_sonar)
|
||||
if (!env.CHANGE_ID) {
|
||||
pushArtifactToJFrog(repo_name, push_to_jfrog)
|
||||
pushArtifactToS3(repo_name, branch_name, push_to_s3)
|
||||
}
|
||||
else {
|
||||
log.info('Artifact Push is disabled for Pull Requests')
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function to check if the artifact exist in s3 or not
|
||||
input argument
|
||||
*/
|
||||
def checkS3(String repo_name, String branch_name, String version, boolean push_to_s3) {
|
||||
stage(stageName('Checking if artifact already exists')) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
if (env.hot_fix) {
|
||||
env.TAG = "v${version}-HOT"
|
||||
}
|
||||
else {
|
||||
if (("${branch_name}" == 'master' || "${branch_name}" == 'main' || push_to_s3) && !env.CHANGE_ID) {
|
||||
env.TAG = "v${version}"
|
||||
log.info('########################## Checking if Artifact Already Exists. ###########################')
|
||||
artifact_exists = sh(returnStdout: true, script: "aws s3 ls \"s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/\" 2>/dev/null || echo ''").trim()
|
||||
log.info("${artifact_exists}")
|
||||
if ( artifact_exists ) {
|
||||
env.msg = "CI for this\n version - ${version}\n branch - ${branch_name}\n TAG - ${TAG}\nis already done. Please proceed with CD."
|
||||
log.error(env.msg)
|
||||
currentBuild.result = 'FAILURE'
|
||||
throw new Exception(env.msg)
|
||||
}
|
||||
else {
|
||||
log.info("Proceeding with building artifact for TAG - ${TAG}.")
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info('Skipping - Building artifact')
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if (env.hot_fix) {
|
||||
env.TAG = "v${version}-HOT"
|
||||
}
|
||||
else {
|
||||
if (("${branch_name}" == 'master' || "${branch_name}" == 'main' || "${branch_name}" == 'gcp-main' || "${branch_name}" == 'gcp-master' || push_to_s3) && !env.CHANGE_ID) {
|
||||
env.TAG = "v${version}"
|
||||
log.info('########################## Checking if Artifact Already Exists. ###########################')
|
||||
artifact_exists = sh(returnStdout: true, script: "gsutil ls \"gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/\" 2>/dev/null || echo ''").trim()
|
||||
log.info("${artifact_exists}")
|
||||
if ( artifact_exists ) {
|
||||
env.msg = "CI for this\n version - ${version}\n branch - ${branch_name}\n TAG - ${TAG}\nis already done. Please proceed with CD."
|
||||
log.error(env.msg)
|
||||
currentBuild.result = 'FAILURE'
|
||||
throw new Exception(env.msg)
|
||||
}
|
||||
else {
|
||||
log.info("Proceeding with building artifact for TAG - ${TAG}.")
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info('Skipping - Building artifact.')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function to build the maven package
|
||||
input arguments:
|
||||
repo_name: repository name for changing dirctory
|
||||
skip_test: boolen value to skip unit tests
|
||||
skip_sonar: boolen value to skip sonar quality gate
|
||||
args: string parameter to provide additional arguments to build cmd, example: '-U'
|
||||
*/
|
||||
def build(String repo_name, boolean skip_test, String args) {
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
stage(stageName('Building gradle package')) {
|
||||
String build_cmd = 'gradle clean build'
|
||||
dir("$repo_name") {
|
||||
sh(script:"cp ~/.m2/settings.xml .;${build_cmd} ${args}")
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
stage(stageName('Building gradle package')) {
|
||||
String build_cmd = 'gradle clean build'
|
||||
dir("$repo_name") {
|
||||
sh(script:"gradle -v;cp ~/.m2/settings.xml .;${build_cmd} ${args}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception e) {
|
||||
env.msg = "Error Building the maven package. Please check console output for more details - ${e}"
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
/*
|
||||
Fuction to execute sonar scan
|
||||
Input Arguments:
|
||||
repo_name: repository name
|
||||
skip_sonar: boolena parameter to skip sonar scan
|
||||
*/
|
||||
def sonar_scan(String repo_name, boolean skip_sonar) {
|
||||
try {
|
||||
stage(stageName('Running sonar scan')) {
|
||||
if (!skip_sonar) {
|
||||
dir("$repo_name") {
|
||||
withSonarQubeEnv(env.sonarEnv) {
|
||||
if (env.CHANGE_ID) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "gradle sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Meesho/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script: "gradle sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Meesho/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "gradle sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script: "gradle sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info('Skipping - Sonar Scan')
|
||||
}
|
||||
}
|
||||
// if (!skip_sonar) {
|
||||
// stage('Quality Gate') {
|
||||
// timeout(time: 300, unit: 'SECONDS') {
|
||||
// def qg = waitForQualityGate()
|
||||
// catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
|
||||
// if (qg.status != 'OK') {
|
||||
// error "stage failed due to quality gate failure: ${qg.status}"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
catch (Exception e) {
|
||||
dir("$repo_name") {
|
||||
withSonarQubeEnv(env.sonarEnv) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: 'gradle sonar:sonar')
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script: 'gradle sonar:sonar')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Function to get the version from build.gradle
|
||||
input arguments:
|
||||
repo_name: String parameter to change the directory where build.gradle is located
|
||||
*/
|
||||
def getVersion(String repo_name) {
|
||||
try {
|
||||
dir("$repo_name") {
|
||||
return sh(returnStdout: true, script: "grep version build.gradle | head -1 | cut -d \"'\" -f2").trim()
|
||||
}
|
||||
}
|
||||
catch ( Exception e) {
|
||||
env.msg = 'Error while getting the version from build.gradle . Please check console output for more details.'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function to get the modules from build.gradle
|
||||
input arguments:
|
||||
repo_name: String parameter to change the directory where build.gradle is located
|
||||
*/
|
||||
def getModules(String repo_name) {
|
||||
try {
|
||||
dir("$repo_name") {
|
||||
modules = sh(returnStdout: true, script: 'xq -r .project.modules.module[] build.gradle 2>/dev/null || xq -r .project.modules.module build.gradle 2>/dev/null || echo empty').trim()
|
||||
if (modules == 'empty' || modules == 'null') {
|
||||
modules = 'module_less'
|
||||
}
|
||||
modules = modules.split('\n') as List
|
||||
return modules
|
||||
}
|
||||
}
|
||||
catch ( Exception e) {
|
||||
env.msg = 'Error getting the modules from build.gradle . Please check console output for more details.'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function to push artifacts to jfrog artifactory
|
||||
input arguments:
|
||||
repo_name: repository name
|
||||
push_to_jfrog: boolen argument to push_to_jfrog
|
||||
*/
|
||||
def pushArtifactToJFrog(String repo_name, boolean push_to_jfrog) {
|
||||
try {
|
||||
stage(stageName('Deploying to JFrog')) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
branch_name = 'repo'
|
||||
if (branch_name == 'master' || branch_name == 'main' || push_to_jfrog) {
|
||||
dir("${repo_name}") {
|
||||
profiles = sh(returnStdout:true, script: 'xq -r .project.profiles build.gradle ').trim()
|
||||
block_dist = sh(returnStdout:true, script: 'xq -r .project.distributionManagement build.gradle ').trim()
|
||||
// Check for profiles tag in the build.gradle
|
||||
if (profiles != 'null') {
|
||||
// Check if profiles has distiributionManagement defined
|
||||
profile_dist = sh(returnStdout:true, script: 'xq -r .project.profiles.profile[].distributionManagement build.gradle 2>/dev/null || xq -r .project.profiles.profile.distributionManagement build.gradle 2>/dev/null || echo null').trim()
|
||||
if (profile_dist != 'null' ) {
|
||||
publish_repo = (branch_name == 'master' || branch_name == 'main' || branch_name == 'gcp-main' || branch_name == 'gcp-master') ? 'useProdRepo' : 'useTestRepo'
|
||||
log.info('########################### Pushing artifact to Jfrog. ###########################')
|
||||
sh "gradle package deploy -DskipTests=true -D${publish_repo}=true"
|
||||
}
|
||||
else {
|
||||
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
|
||||
}
|
||||
}
|
||||
else if (block_dist != 'null') {
|
||||
// Check if distributionManagement is defined without profiles
|
||||
log.info('########################### Pushing artifact to Jfrog. ###########################')
|
||||
sh 'gradle package deploy -DskipTests=true'
|
||||
}
|
||||
else {
|
||||
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info('########################### Skipping - Push to Jfrog Artifactory. ###########################')
|
||||
}
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
branch_name = 'repo'
|
||||
if (branch_name == 'master' || branch_name == 'main' || push_to_jfrog) {
|
||||
dir("${repo_name}") {
|
||||
profiles = sh(returnStdout:true, script: 'xq -r .project.profiles build.gradle ').trim()
|
||||
block_dist = sh(returnStdout:true, script: 'xq -r .project.distributionManagement build.gradle ').trim()
|
||||
// Check for profiles tag in the build.gradle
|
||||
if (profiles != 'null') {
|
||||
// Check if profiles has distiributionManagement defined
|
||||
profile_dist = sh(returnStdout:true, script: 'xq -r .project.profiles.profile[].distributionManagement build.gradle 2>/dev/null || xq -r .project.profiles.profile.distributionManagement build.gradle 2>/dev/null || echo null').trim()
|
||||
if (profile_dist != 'null' ) {
|
||||
publish_repo = (branch_name == 'master' || branch_name == 'main' || branch_name == 'gcp-main' || branch_name == 'gcp-master') ? 'useProdRepo' : 'useTestRepo'
|
||||
log.info('########################### Pushing artifact to Jfrog. ###########################')
|
||||
sh "gradle package deploy -DskipTests=true -D${publish_repo}=true"
|
||||
echo 'execute gradle dependency'
|
||||
sh 'gradle dependency:list > dependency_tree.txt'
|
||||
echo ' uploading gradle dependency'
|
||||
sh 'ls -ltr'
|
||||
echo 'lets run copy command'
|
||||
try {
|
||||
sh "gsutil cp dependency_tree.txt 'gs://${env.objBucket}/common-dependencies/${repo_name}/'"
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
echo "Skipping - copying txt file to GCS - ${e}"
|
||||
}
|
||||
echo 'uploading gradle dependency'
|
||||
}
|
||||
else {
|
||||
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
|
||||
}
|
||||
}
|
||||
else if (block_dist != 'null') {
|
||||
// Check if distributionManagement is defined without profiles
|
||||
log.info('########################### Pushing artifact to Jfrog. ###########################')
|
||||
sh 'gradle package deploy -DskipTests=true'
|
||||
}
|
||||
else {
|
||||
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info('########################### Skipping - Push to Jfrog Artifactory. ###########################')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
env.msg = 'Error in pushing artifacts to jfrog . Please check console output for more details.'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Function to push artifacts to s3
|
||||
input arguments:
|
||||
repo_name: repository name
|
||||
push_to_s3: boolen argument to push to s3
|
||||
*/
|
||||
def pushArtifactToS3(String repo_name, String branch_name, boolean push_to_s3) {
|
||||
try {
|
||||
stage(stageName('Pushing artifacts to object storage')) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
if ("${branch_name}" == 'master' || "${branch_name}" == 'main' || push_to_s3) {
|
||||
def modules = getModules("${repo_name}")
|
||||
log.info('}########################### Pushing artifacts to S3. ###########################')
|
||||
j = 0
|
||||
for (module in modules) {
|
||||
j += 1
|
||||
sh """
|
||||
echo "${j}. ${module}"
|
||||
if [ -f ${repo_name}/${module}/target/*.jar ]
|
||||
then
|
||||
ls -al ${repo_name}/${module}/target/*.jar
|
||||
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
|
||||
aws s3 cp ${repo_name}/${module}/target/*.jar "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
|
||||
echo "Listing ${TAG} artifacts -"
|
||||
aws s3 ls "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
|
||||
elif [ -f ${repo_name}/target/*.jar ] && [ ${module} = 'module_less' ]
|
||||
then
|
||||
ls -al ${repo_name}/target/*.jar
|
||||
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
|
||||
aws s3 cp ${repo_name}/target/*.jar "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
|
||||
echo "Uploading Archived Code to - ${repo_name}/${branch_name}/${TAG}"
|
||||
echo "Listing ${TAG} artifacts -"
|
||||
aws s3 ls "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
|
||||
else
|
||||
echo "No jar file found."
|
||||
fi
|
||||
"""
|
||||
}
|
||||
log.info("TAG for CD - ${TAG}")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping - Artifact push. As it is not supported for ${env.BRANCH_NAME}")
|
||||
}
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if ("${branch_name}" == 'master' || "${branch_name}" == 'main' || "${branch_name}" == 'gcp-main' || branch_name == 'gcp-master' || push_to_s3) {
|
||||
def modules = getModules("${repo_name}")
|
||||
log.info('}########################### Pushing artifacts to S3. ###########################')
|
||||
j = 0
|
||||
for (module in modules) {
|
||||
j += 1
|
||||
sh """
|
||||
echo "${j}. ${module}"
|
||||
if [ -f ${repo_name}/${module}/target/*.jar ]
|
||||
then
|
||||
ls -al ${repo_name}/${module}/target/*.jar
|
||||
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
|
||||
gsutil cp ${repo_name}/${module}/target/*.jar "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
|
||||
echo "Listing ${TAG} artifacts -"
|
||||
gsutil ls "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
|
||||
elif [ -f ${repo_name}/target/*.jar ] && [ ${module} = 'module_less' ]
|
||||
then
|
||||
ls -al ${repo_name}/target/*.jar
|
||||
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
|
||||
gsutil cp ${repo_name}/target/*.jar "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
|
||||
echo "Uploading Archived Code to - ${repo_name}/${branch_name}/${TAG}"
|
||||
echo "Listing ${TAG} artifacts -"
|
||||
gsutil ls "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
|
||||
else
|
||||
echo "No jar file found."
|
||||
fi
|
||||
"""
|
||||
}
|
||||
log.info("TAG for CD - ${TAG}")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping - Artifact push. As it is not supported for ${env.BRANCH_NAME}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
env.msg = "Error in pushing artifacts to s3 bucket. Please check console output for more details - ${e}"
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fuction for java version
|
||||
*/
|
||||
def getDockerBuildVersion(String java_version) {
|
||||
switch (java_version) {
|
||||
case 'gradle': return '8-jdk-slim-secure-multiarch_v3.0'
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Fuction to build maven docker repo
|
||||
*/
|
||||
|
||||
def buildDckr(Map config) {
|
||||
def btObj = new buTeamMapping()
|
||||
def dparam_obj = new getDockerParams()
|
||||
def constructObj = new constructTemplate()
|
||||
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
def repo_name = config.repo_name
|
||||
def tag = dparam_obj.getTag(repo_name)
|
||||
def skip_test = config.skip_test ?: false
|
||||
def modules = getModules("${repo_name}")
|
||||
def excludedModules = config.excludedModules ?: []
|
||||
def deployArgo = config.deployArgo ?: false
|
||||
def repoType = config.repo_type ?: 'microservice'
|
||||
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
|
||||
env.JAVA_HOME = '/usr/lib/jvm/java-8-openjdk-amd64/'
|
||||
env.PATH = "/opt/gradle/gradle-5.6.1/bin:${env.PATH}"
|
||||
|
||||
def docker_bindings = [
|
||||
'repo_name': repo_name,
|
||||
'buildRegistry': env.buildRegistry
|
||||
]
|
||||
if (config.containsKey('copy_file')) {
|
||||
// if (env.CLOUD_PROVIDER == "AWS"){
|
||||
// def recursive = config.copy_file.recursive ? ' --recursive' : ''
|
||||
// }
|
||||
// else if (env.CLOUD_PROVIDER == "GCP"){
|
||||
// def recursive = config.copy_file.recursive ? ' -r' : ''
|
||||
// }
|
||||
def recursive = config.copy_file.recursive ? ' --recursive' : ''
|
||||
dir(repo_name) {
|
||||
dir('copied_files') {
|
||||
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
|
||||
}
|
||||
}
|
||||
docker_bindings['copy_file'] = true
|
||||
docker_bindings['copy_target'] = config.copy_file.target ?: '/opt/target'
|
||||
}
|
||||
else {
|
||||
docker_bindings['copy_file'] = false
|
||||
}
|
||||
|
||||
if (modules != 'module_less') {
|
||||
excludedModules.each { modules.removeElement(it) }
|
||||
}
|
||||
else {
|
||||
modules = ['module_less']
|
||||
}
|
||||
docker_bindings['arch'] = config.arch
|
||||
def java_version = config.dockerBuildVersion
|
||||
dockerBuildVersion = getDockerBuildVersion(java_version)
|
||||
docker_bindings['dockerBuildVersion'] = dockerBuildVersion
|
||||
run(config)
|
||||
if (docker_bindings.copy_file) {
|
||||
dir(repo_name) {
|
||||
dir('copied_files') {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
// delete any old data
|
||||
sh(script:'rm -rf *')
|
||||
sh(script:"aws s3 cp${docker_bindings.recursive} ${docker_bindings.copy_file_path} .")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
// delete any old data
|
||||
docker_bindings['recursive'] = '-r'
|
||||
sh(script:'rm -rf *')
|
||||
sh(script:"gsutil cp ${docker_bindings.recursive} ${docker_bindings.copy_file_path}* .")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage(stageName('Building docker images')) {
|
||||
// Login to docker
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
|
||||
}
|
||||
dir(repo_name) {
|
||||
for (module in modules) {
|
||||
docker_bindings['module'] = module
|
||||
constructObj.renderTemplate(docker_bindings,'java-Dockerfile','Dockerfile-' + module)
|
||||
def module_repo = (module == 'module_less') ? docker_repo : docker_repo + '/' + module
|
||||
if ( module == 'module_less') {
|
||||
sh(script: 'mkdir target;cp build/libs/*jar target')
|
||||
}
|
||||
else {
|
||||
sh(script: "mkdir -p ${module}/target;cp build/libs/*jar ${module}/target")
|
||||
}
|
||||
if (env.cicd_environment != 'ftr' && repoType == 'microservice') {
|
||||
sh(script: "ls target; docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module} . && docker push ${env.registry}/${module_repo}:${tag}")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker Build - ${env.cicd_environment} env")
|
||||
log.info("Skipping Docker Build - ${repoType} repo type")
|
||||
}
|
||||
//Remove dockerfile
|
||||
sh(script: "rm -rf Dockerfile-${module}")
|
||||
}
|
||||
}
|
||||
return [tag , deployArgo]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,568 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.utilities.addSSHKey
|
||||
import com.meesho.utilities.dockerUtilities
|
||||
import com.meesho.utilities.getYamlParameter
|
||||
|
||||
def removePackageLock() {
|
||||
sh(script: 'rm -rf package-lock.json')
|
||||
}
|
||||
|
||||
def buildNode(def build_cmd) {
|
||||
try {
|
||||
if (fileExists('package-lock.json')) {
|
||||
sh(script: 'npm ci')
|
||||
}
|
||||
else {
|
||||
sh(script: 'npm install')
|
||||
}
|
||||
sh(script: build_cmd)
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
env.msg = 'Error in building node packages . Please check console output for more details.'
|
||||
env.error_msg_to_db = 'Error Building Node Packages'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def getArtifactId(String repo_name) {
|
||||
dir("$repo_name") {
|
||||
if (fileExists('package.json')) {
|
||||
return sh(returnStdout: true, script: 'jq -r .name package.json').trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getAwsSecret(def secret_name, def destination_file, def team, def bu) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws secretsmanager get-secret-value --secret-id ${secret_name} --query SecretString --output text > ${destination_file}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
getVaultSecret("vault kv get -format=json meesho/${env.cicd_environment}/${bu}/${team}/${secret_name} | jq -r .data.data > ${destination_file}")
|
||||
}
|
||||
}
|
||||
|
||||
def getNpmRc(def secret_name, def team, def bu) {
|
||||
def npmrc_file = secret_name + '-npmrc-' + env.cicd_environment
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws secretsmanager get-secret-value --secret-id ${npmrc_file} --query SecretString --output text| jq -r .MEESHO_NPMRC_SECRET > .npmrc")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
getVaultSecret("vault kv get -format=json meesho/${env.cicd_environment}/${bu}/${team}/${npmrc_file} | jq -r .data.data.MEESHO_NPMRC_SECRET > .npmrc")
|
||||
}
|
||||
}
|
||||
|
||||
def getPemFile(def secret_name, def team, def bu) {
|
||||
def pem_secret_name = secret_name + '-secrets-' + env.cicd_environment
|
||||
if (env.BUILD_ENV == 'stage') {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_dev > 1_public_secret_dev.pem")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
getVaultSecret("vault kv get -format=json meesho/${env.cicd_environment}/${bu}/${team}/${pem_secret_name} | jq -r .data.data.public_secret_dev > 1_public_secret_dev.pem")
|
||||
}
|
||||
sh(script:"cat 1_public_secret_dev.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_dev.pem")
|
||||
}
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_prod > 1_public_secret_prod.pem")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
getVaultSecret("vault kv get -format=json meesho/${env.cicd_environment}/${bu}/${team}/${pem_secret_name} | jq -r .data.data.public_secret_prod > 1_public_secret_prod.pem")
|
||||
}
|
||||
|
||||
sh(script:"cat 1_public_secret_prod.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_prod.pem")
|
||||
}
|
||||
|
||||
def getEnvFile(def secret_name, def team, def bu, boolean useCacPath = false) {
|
||||
def env_file = secret_name + '-env-' + env.cicd_environment
|
||||
def gcp_env_file = secret_name
|
||||
def destination_file = '.env'
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws secretsmanager get-secret-value --secret-id ${env_file} | jq --raw-output '.SecretString' | jq '.' | jq -r 'to_entries|map(\"\\(.key)=\\(.value|tostring)\")|.[]' > .env")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
def vault_path = useCacPath
|
||||
? "meesho/${env.cicd_environment}-cac/${bu}/${team}/${gcp_env_file}-client"
|
||||
: "meesho/${env.cicd_environment}/${bu}/${team}/${gcp_env_file}"
|
||||
getVaultSecret("vault kv get -format=json ${vault_path} | jq -r '.data.data | to_entries|map(\"\\(.key)=\\(.value|tostring)\")|.[]' > .env")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read appConfigEnabled from deployment yaml(s) in repo (deployments/<name>.yaml).
|
||||
* Uses config.deployment_order for deployment names, or repo_name if not set.
|
||||
* Aligns with deploy/Helm which reads appConfigEnabled from the same files.
|
||||
*/
|
||||
def isAppConfigEnabledFromDeployments(String repo_name, Map config) {
|
||||
def deploymentNames = (config.deployment_order instanceof List && !config.deployment_order.isEmpty())
|
||||
? config.deployment_order
|
||||
: [repo_name]
|
||||
def yamlObj = new getYamlParameter()
|
||||
for (def deployment in deploymentNames) {
|
||||
try {
|
||||
def depYaml = yamlObj.getParam(repo_name, "deployments/${deployment}.yaml")
|
||||
def enabled = depYaml?.appConfigEnabled
|
||||
if (enabled == true || enabled?.toString()?.equalsIgnoreCase('true')) {
|
||||
return true
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("No appConfigEnabled in ${repo_name}/deployments/${deployment}.yaml or file missing: ${e.message}")
|
||||
continue
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
def getManifestJson(def secret_name, def team, def bu) {
|
||||
def manifest_file = secret_name + '-manifest-' + env.cicd_environment
|
||||
def destination_file = 'public/manifest.json'
|
||||
getAwsSecret(manifest_file, destination_file, team, bu)
|
||||
}
|
||||
|
||||
def generateExcludePattern(String excludeS3Files) {
|
||||
def files = excludeS3Files.split(/\s*,\s*/) // Split the string by comma and trim whitespace
|
||||
return '|' + files.join('|') // Join file names with '|' as an "or" operator in regex
|
||||
}
|
||||
|
||||
def shouldSkipPm2Metrics(Map config) {
|
||||
return config.skip_pm2_metrics?.toString()?.toBoolean() ?: false
|
||||
}
|
||||
|
||||
/*
|
||||
Fuction to build maven docker repo
|
||||
*/
|
||||
|
||||
def getCommitSHA(String repo_name) {
|
||||
dir(repo_name) {
|
||||
return sh(returnStdout: true, script: 'git log -1 --format=%H').trim()
|
||||
}
|
||||
}
|
||||
|
||||
def buildDckr(Map config) {
|
||||
// // Block all Node.js builds - throwing exception
|
||||
// throw new Exception("Node.js builds are currently blocked, As a precautionary measure. Due to some packages that got hacked.")
|
||||
def btObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dparam_obj = new getDockerParams()
|
||||
def addSSHKey = new addSSHKey()
|
||||
def dockerUtilObj = new dockerUtilities()
|
||||
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
def bu = btObj.get_bu_initials(config.bu)
|
||||
def repo_name = config.repo_name
|
||||
// CAC: read appConfigEnabled from deployment folder (deployments/<name>.yaml), same source as deploy/Helm
|
||||
def useCacPath = isAppConfigEnabledFromDeployments(repo_name, config)
|
||||
def build_cmd = config.build_cmd ?: 'npm run build'
|
||||
// Resolve secret_name from deployment YAML app_name.
|
||||
// For multi-deployment repos, env/secret files are kept in sync so the first valid app_name is used.
|
||||
def secret_name = repo_name
|
||||
def keep_package_lock = config.keep_package_lock != null ? config.keep_package_lock : true
|
||||
def skip_npmrc = config.skip_npmrc != null ? config.skip_npmrc : true
|
||||
if (config.secret_name) {
|
||||
secret_name = config.secret_name
|
||||
} else {
|
||||
try {
|
||||
def yamlObj = new getYamlParameter()
|
||||
def deploymentsPath = "${repo_name}/deployments"
|
||||
def yamlFilesOutput = sh(
|
||||
script: "ls ${deploymentsPath}/*.yaml 2>/dev/null | xargs -r -n1 basename",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
if (yamlFilesOutput) {
|
||||
def yamlFiles = yamlFilesOutput.split('\n').collect { it.trim() }.findAll { it }
|
||||
for (yamlFile in yamlFiles) {
|
||||
def appConfig = yamlObj.getParam(deploymentsPath, yamlFile)
|
||||
def appName = appConfig?.app_name?.toString()?.trim()
|
||||
if (appName) {
|
||||
echo "Resolved secret_name to ${appName} from ${deploymentsPath}/${yamlFile}"
|
||||
secret_name = appName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (secret_name == repo_name) {
|
||||
echo "No app_name found in deployment yamls; using repo_name: ${repo_name}"
|
||||
}
|
||||
} catch (Exception e) {
|
||||
echo "Error reading deployment yaml: ${e.getMessage()}; using repo_name: ${repo_name}"
|
||||
}
|
||||
}
|
||||
def require_mainfest = config.require_mainfest ?: false
|
||||
def pbac_enabled = config.pbac_enabled ?: false
|
||||
def pbac_scope_name = config.pbac_scope_name ?: ''
|
||||
def npm_install_arg = config.npm_install_arg ?: ''
|
||||
if (!npm_install_arg) {
|
||||
if (fileExists("${repo_name}/pnpm-lock.yaml") || build_cmd.contains('pnpm')) {
|
||||
npm_install_arg = 'npm install -g pnpm@10.33.0 && pnpm install --frozen-lockfile'
|
||||
}
|
||||
else if (!keep_package_lock || !fileExists("${repo_name}/package-lock.json")) {
|
||||
npm_install_arg = 'npm install'
|
||||
}
|
||||
// else: package-lock.json exists + keep_package_lock=true → Dockerfile uses `npm ci`
|
||||
}
|
||||
def require_pemfiles = config.require_pemfiles ?: false
|
||||
def deployArgo = config.deployArgo ?: false
|
||||
def artifactId = getArtifactId("${repo_name}")
|
||||
// def region = dparam_obj.getRegion(env.cicd_environment)
|
||||
// def registry = dparam_obj.getRegistry(env.cicd_environment)
|
||||
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
|
||||
def push_to_s3 = config.push_to_s3 ?: false
|
||||
def s3_path = config.s3_path ?: "meesho-${env.BUILD_ENV}-artifacts/${repo_name}/${env.BRANCH_NAME}"
|
||||
if (env.INFRA_ENV == 'toolchain' && env.TOOLCHAIN_ENV) {
|
||||
docker_repo = "${env.cicd_environment}/${env.TOOLCHAIN_ENV}/${team}/${repo_name.toLowerCase()}"
|
||||
log.info("Toolchain: Overriding docker_repo to ${docker_repo}")
|
||||
echo "docker_repo: ${docker_repo}"
|
||||
|
||||
if (config.s3_path && config.push_to_s3) {
|
||||
echo" {env.cicd_environment} should be stg due ot ovveride"
|
||||
s3_path = s3_path.replaceFirst("/${env.cicd_environment}/", "/${env.TOOLCHAIN_ENV}/")
|
||||
log.info("TOOLCHAIN OVERRIDE:")
|
||||
log.info(" Original S3 Path: ${config.s3_path}")
|
||||
log.info(" New Toolchain S3 Path: ${s3_path}")
|
||||
log.info(" Toolchain Env ID: ${env.TOOLCHAIN_ENV}")
|
||||
|
||||
} else if (!config.push_to_s3) {
|
||||
log.info("Toolchain: push_to_s3 is false, skipping s3_path override as it wont be pushed")
|
||||
} else if (!config.s3_path && config.push_to_s3) {
|
||||
log.info("Toolchain: s3_path is not set but push_to_s3 is true, skipping s3_path override as it wont be pushed")
|
||||
error("CRITICAL: 's3_path' is missing in config.yaml for the ${env.cicd_environment} environment. Toolchain builds require an s3_path.")
|
||||
}
|
||||
}
|
||||
if (env.TOOLCHAIN_ENV) {
|
||||
log.info("TOOLCHAIN_ENV: ${env.TOOLCHAIN_ENV}")
|
||||
}else{
|
||||
log.info("TOOLCHAIN_ENV: not set")
|
||||
}
|
||||
def local_path = config.local_path ?: 'build/'
|
||||
def acl = config.acl ? ' --acl ' + config.acl : ''
|
||||
def custom_pm2_metrics = config.custom_pm2_metrics ?: false
|
||||
def skip_pm2_metrics = shouldSkipPm2Metrics(config)
|
||||
def include_s3_files = ''
|
||||
def exclude_s3_files = ''
|
||||
if (!s3_path.endsWith('/')) {
|
||||
s3_path += '/'
|
||||
}
|
||||
if (!local_path.endsWith('/')) {
|
||||
local_path += '/'
|
||||
}
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
if (config.include_s3_files) {
|
||||
include_s3_files = ' --exclude "*"'
|
||||
def include_file_map = config.include_s3_files.split(',')
|
||||
for (pattern in include_file_map) {
|
||||
include_s3_files += ' --include "'+pattern+'"'
|
||||
}
|
||||
}
|
||||
exclude_s3_files = config.exclude_s3_files ? ' --exclude "'+config.exclude_s3_files+'"' : ''
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if (config.include_s3_files) {
|
||||
def includeFileMap = config.include_s3_files.split(',')
|
||||
def file_types = ''
|
||||
def i = 0
|
||||
includeFileMap.each { pattern ->
|
||||
if ( i == 0 ) {
|
||||
file_types = "${pattern.replaceAll('\\*.', '')}"
|
||||
}
|
||||
else {
|
||||
file_types += "|${pattern.replaceAll('\\*.', '')}"
|
||||
}
|
||||
i++
|
||||
}
|
||||
if ( file_types == '*' ) {
|
||||
include_s3_files = '^(?!.*\\.*$)'
|
||||
}
|
||||
else {
|
||||
include_s3_files = "^(?!.*\\.(${file_types})\$)"
|
||||
}
|
||||
echo "include_s3_files is ${include_s3_files}"
|
||||
}
|
||||
else {
|
||||
include_s3_files = '^(?!.*\\.*$)'
|
||||
}
|
||||
|
||||
exclude_s3_files = config.exclude_s3_files != null && config.exclude_s3_files.trim()? generateExcludePattern(config.exclude_s3_files.trim()) : ''
|
||||
|
||||
}
|
||||
def phantomjs = config.phantomjs ?: false
|
||||
def version = config.dockerBuildVersion.split('-')[-1]
|
||||
def tag = dparam_obj.getTag(repo_name)
|
||||
// TODO: create value binding for dockerfile render
|
||||
|
||||
def skip_sonar = config.skip_sonar ?: false
|
||||
if (env.hot_fix || env.INFRA_ENV == 'toolchain') {
|
||||
skip_sonar = true
|
||||
}
|
||||
def testCMD = config.testCMD ?: 'test-report'
|
||||
def scmType = 'branch'
|
||||
def commit_sha = getCommitSHA(config.repo_name)
|
||||
def docker_bindings = [
|
||||
'buildRegistry': env.buildRegistry,
|
||||
'version': version,
|
||||
'build_cmd': build_cmd,
|
||||
'push_to_s3': push_to_s3,
|
||||
's3_path': s3_path,
|
||||
'local_path': local_path,
|
||||
'include_s3_files': include_s3_files,
|
||||
'exclude_s3_files': exclude_s3_files,
|
||||
'acl': acl,
|
||||
'phantomjs': phantomjs,
|
||||
'skip_sonar': skip_sonar,
|
||||
'testCMD': testCMD,
|
||||
'CLOUD_PROVIDER': env.CLOUD_PROVIDER,
|
||||
'npm_install_arg': npm_install_arg
|
||||
]
|
||||
docker_bindings['arch'] = config.arch
|
||||
docker_bindings['pbac_enabled'] = pbac_enabled
|
||||
docker_bindings['pbac_scope_name'] = pbac_scope_name ?: ''
|
||||
// Map BUILD_ENV to pbac format (stg/int/prd)
|
||||
def pbac_env = env.cicd_environment
|
||||
docker_bindings['pbac_env'] = pbac_env
|
||||
docker_bindings['useCacPath'] = useCacPath
|
||||
|
||||
// Validate pbac configuration
|
||||
if (pbac_enabled && !pbac_scope_name) {
|
||||
error('pbac_scope_name is required when pbac_enabled is true in config.yaml')
|
||||
}
|
||||
|
||||
stage(stageName('Creating build files')) {
|
||||
dir(repo_name) {
|
||||
if (!keep_package_lock) {
|
||||
removePackageLock()
|
||||
}
|
||||
if (!skip_npmrc) {
|
||||
getNpmRc(secret_name, team, bu)
|
||||
}
|
||||
|
||||
getEnvFile(secret_name, team, bu, useCacPath)
|
||||
|
||||
if (require_pemfiles) {
|
||||
getPemFile(secret_name, team, bu)
|
||||
}
|
||||
if (require_mainfest) {
|
||||
getManifestJson(secret_name, team, bu)
|
||||
}
|
||||
def npm_registry = ''
|
||||
if (fileExists('.npmrc')) {
|
||||
npm_registry = sh(
|
||||
returnStdout: true,
|
||||
script: "grep '^@meesho:registry=' .npmrc | head -1 | cut -d'=' -f2 | tr -d '\\r\\n'"
|
||||
).trim()
|
||||
echo "Detected npm registry: ${npm_registry ?: 'default (none found)'}"
|
||||
} else {
|
||||
echo ".npmrc not found, skipping registry extraction"
|
||||
}
|
||||
docker_bindings['npm_registry'] = npm_registry
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_sonar){
|
||||
stage(stageName('Checking quality gate')){
|
||||
log.info("Skipping the quality gate check as sonar scan is skipped or this is a hotfix ")
|
||||
}
|
||||
}
|
||||
stage(stageName('Building docker images')) {
|
||||
// Login to docker
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in Docker login'
|
||||
env.error_msg_to_db = 'Error in Docker login'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${docker_repo} || aws ecr create-repository --region ${env.region} --repository-name ${docker_repo}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
echo 'Skipping - Registry Creation in GCP.'
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "Error in creating ECR repository ${docker_repo}"
|
||||
env.error_msg_to_db = "Error in creating ECR repository ${docker_repo}"
|
||||
currentBuild.result = 'FAILURE'
|
||||
}
|
||||
try {
|
||||
dir(repo_name) {
|
||||
addSSHKey.create()
|
||||
withCredentials([usernamePassword(credentialsId: "svc-devops-meesho-token", usernameVariable: 'GIT_USER', passwordVariable: 'GIT_TOKEN')]) {
|
||||
sh """
|
||||
echo "GITHUB_TOKEN=${GIT_TOKEN}" >> .env
|
||||
echo "GIT_COMMIT_SHA='${commit_sha}'" >> .env
|
||||
"""
|
||||
}
|
||||
withCredentials([string(credentialsId: env.sonarToken, variable: 'TOKEN')]) {
|
||||
sh """
|
||||
echo "SONAR_HOST_URL='${env.sonarURL}'" >> .env
|
||||
echo "SONAR_TOKEN='${TOKEN}'" >> .env
|
||||
echo "SONAR_WS_TIMEOUT=120" >> .env
|
||||
"""
|
||||
if (env.CHANGE_ID) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
|
||||
}
|
||||
sh """
|
||||
echo "SONAR_CHANGE_ID='${env.CHANGE_ID}'" >> .env
|
||||
echo "SONAR_CHANGE_BRANCH='${env.CHANGE_BRANCH}'" >> .env
|
||||
echo "SONAR_CHANGE_TARGET='${env.CHANGE_TARGET}'" >> .env
|
||||
"""
|
||||
scmType = 'pr'
|
||||
}
|
||||
else {
|
||||
sh """
|
||||
echo "SONAR_BRANCH_NAME='${env.BRANCH_NAME}'" >> .env
|
||||
"""
|
||||
}
|
||||
echo 'Make sure to update script section in package.json for Sonar Analysis to be successfull.'
|
||||
docker_bindings['scmType'] = scmType
|
||||
}
|
||||
if (!fileExists('Dockerfile')) {
|
||||
constructObj.renderTemplate(docker_bindings, 'node-Dockerfile', 'Dockerfile-' + artifactId)
|
||||
sh "cat Dockerfile-${artifactId}"
|
||||
if (push_to_s3) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh """
|
||||
echo 'FROM amazon/aws-cli:2.2.0 as push_env' >> Dockerfile-${artifactId}
|
||||
echo 'COPY --from=build-env /usr/src/app /app' >> Dockerfile-${artifactId}
|
||||
echo 'RUN ls -al && aws s3 cp /app/${local_path} s3://${s3_path}${include_s3_files}${exclude_s3_files} --recursive --cache-control max-age=31536000,public${acl}' >> Dockerfile-${artifactId}
|
||||
"""
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP' ) {
|
||||
sh """
|
||||
echo 'FROM asia-southeast1-docker.pkg.dev/meesho-devops-admin-0622/admin/devops/google-cloud-sdk:458.0.0-alpine as push_env' >> Dockerfile-${artifactId}
|
||||
echo 'COPY --from=build-env /usr/src/app /app' >> Dockerfile-${artifactId}
|
||||
# echo 'RUN ls -al /app && find /app/${local_path} -type f \\( -name "*.js" -o -name "*.map" \\) && find /app/${local_path} -type f \\( -name "*.js" -o -name "*.map" \\) | wc -l && gsutil -m cp -r /app/${local_path}* gs://${s3_path}' >> Dockerfile-${artifactId}
|
||||
echo "RUN ls -al /app && gsutil -m rsync -r -x \'${include_s3_files} ${exclude_s3_files}\' /app/${local_path} gs://${s3_path}" >> Dockerfile-${artifactId}
|
||||
echo "RUN if [ -f /app/${local_path}index.html ]; then gsutil cp /app/${local_path}index.html gs://${s3_path}; fi" >> Dockerfile-${artifactId}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
if (phantomjs) {
|
||||
sh """
|
||||
echo 'FROM build-env' >> Dockerfile-${artifactId}
|
||||
echo 'RUN apt-get update && apt-get install -y libfontconfig' >> Dockerfile-${artifactId}
|
||||
echo 'WORKDIR /usr/src/app' >> Dockerfile-${artifactId}
|
||||
echo 'RUN npm install pm2 -g' >> Dockerfile-${artifactId}
|
||||
echo 'RUN pm2 install pm2-metrics' >> Dockerfile-${artifactId}
|
||||
if [ "${custom_pm2_metrics}" = "true" ]; then
|
||||
echo 'RUN pm2 install pm2-prom-module' >> Dockerfile-${artifactId}
|
||||
echo 'RUN pm2 set pm2-prom-module:port 9200' >> Dockerfile-${artifactId}
|
||||
echo 'RUN pm2 restart pm2-prom-module' >> Dockerfile-${artifactId}
|
||||
fi
|
||||
echo 'RUN rm -rf /root/.ssh/id_rsa && apt-get remove -y git openssh-client bzip2' >> Dockerfile-${artifactId}
|
||||
"""
|
||||
}
|
||||
else {
|
||||
sh """
|
||||
echo 'FROM ${env.buildRegistry}/build/node:${version}-alpine-secure-multiarch_v1.0' >> Dockerfile-${artifactId}
|
||||
echo 'RUN npm install pm2 -g' >> Dockerfile-${artifactId}
|
||||
if [ "${skip_pm2_metrics}" != "true" ]; then
|
||||
echo 'RUN pm2 install pm2-metrics' >> Dockerfile-${artifactId}
|
||||
fi
|
||||
if [ "${custom_pm2_metrics}" = "true" ]; then
|
||||
echo 'RUN pm2 install pm2-prom-module' >> Dockerfile-${artifactId}
|
||||
echo 'RUN pm2 set pm2-prom-module:port 9200' >> Dockerfile-${artifactId}
|
||||
echo 'RUN pm2 restart pm2-prom-module' >> Dockerfile-${artifactId}
|
||||
fi
|
||||
echo 'WORKDIR /app' >> Dockerfile-${artifactId}
|
||||
echo 'COPY --from=build-env /usr/src/app /app' >> Dockerfile-${artifactId}
|
||||
"""
|
||||
}
|
||||
if (docker_bindings['useCacPath']) {
|
||||
sh "echo 'RUN truncate -s 0 .env' >> Dockerfile-${artifactId}"
|
||||
}
|
||||
sh "cat Dockerfile-${artifactId}"
|
||||
def imageList = "${env.buildRegistry}/build/node:${version}-alpine-secure-multiarch_v1.0 " +
|
||||
"asia-southeast1-docker.pkg.dev/meesho-devops-admin-0622/admin/devops/google-cloud-sdk:458.0.0-alpine " +
|
||||
"${env.buildRegistry}/build/node:${version}-slim-secure-multiarch_v2.0"
|
||||
|
||||
sh """
|
||||
max_attempts=5
|
||||
images=\"$imageList\"
|
||||
|
||||
for image in \$images; do
|
||||
attempt=1
|
||||
until docker pull \"\$image\"; do
|
||||
if [ \$attempt -eq \$max_attempts ]; then
|
||||
echo \"Failed to pull \$image after \$attempt attempts.\"
|
||||
exit 1
|
||||
fi
|
||||
echo \"Pull failed for \$image, retrying in 2 seconds... (Attempt \$attempt/\$max_attempts)\"
|
||||
attempt=\$((attempt + 1))
|
||||
sleep 2
|
||||
done
|
||||
done
|
||||
"""
|
||||
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
|
||||
def docker_cmd = "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} -f Dockerfile-${artifactId} . "
|
||||
sh(script: docker_cmd)
|
||||
dockerUtilObj.retryDockerPush("docker push ${env.registry}/${docker_repo}:${tag}")
|
||||
}
|
||||
else {
|
||||
def docker_cmd = "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} -f Dockerfile-${artifactId} ."
|
||||
sh(script: docker_cmd)
|
||||
}
|
||||
//Remove dockerfile
|
||||
sh(script: "rm -rf Dockerfile-${artifactId}")
|
||||
}
|
||||
else {
|
||||
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
|
||||
sh(script: "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} . ")
|
||||
dockerUtilObj.retryDockerPush("docker push ${env.registry}/${docker_repo}:${tag}")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker Push - ${env.cicd_environment} env")
|
||||
sh(script: "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in building DockerFile Or Pushing To ECR'
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error(env.msg + '\n' + e.toString())
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
return [tag , deployArgo]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def getVaultSecret(String vault_cmd) {
|
||||
log.info("Fetching secrets from Vault with vault-${env.cicd_environment}-token with CMD - ${vault_cmd}")
|
||||
if (env.INFRA_ENV == 'toolchain' && env.TOOLCHAIN_ENV) {
|
||||
boolean skipToolchainOverride = vault_cmd.contains("npmrc") || vault_cmd.contains("-secrets-")
|
||||
if (!skipToolchainOverride) {
|
||||
vault_cmd = vault_cmd.replace("meesho/${env.cicd_environment}-cac/", "meesho/toolchain/${env.TOOLCHAIN_ENV}/${env.cicd_environment}-cac/")
|
||||
vault_cmd = vault_cmd.replace("meesho/${env.cicd_environment}/", "meesho/toolchain/${env.TOOLCHAIN_ENV}/${env.cicd_environment}/")
|
||||
log.info("TOOLCHAIN OVERRIDE (Application Config):")
|
||||
log.info(" New Toolchain Vault CMD: ${vault_cmd}")
|
||||
} else {
|
||||
log.info("TOOLCHAIN: Reading from standard (non-toolchain) Vault path for npmrc / pem secret.")
|
||||
}
|
||||
}
|
||||
|
||||
withCredentials([string(credentialsId: "${env.vaultToken}", variable: 'TOKEN')]) {
|
||||
env.VAULT_ADDR = "${env.vaultURL}"
|
||||
env.VAULT_TOKEN = "${TOKEN}"
|
||||
sh(script:"${vault_cmd}")
|
||||
env.VAULT_TOKEN = 'empty'
|
||||
env.VAULT_ADDR = env.VAULT_TOKEN
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.meesho.stages
|
||||
|
||||
def run(String build_tool){
|
||||
try {
|
||||
switch (build_tool) {
|
||||
case 'maven':
|
||||
return new buildMaven()
|
||||
break;
|
||||
case 'docker':
|
||||
return new buildDocker()
|
||||
break;
|
||||
case ~/^maven-.*/:
|
||||
return new buildMaven()
|
||||
break;
|
||||
case ~/^python-.*/:
|
||||
return new buildPython()
|
||||
break;
|
||||
case ~/^node-.*/:
|
||||
return new buildNode()
|
||||
break;
|
||||
case ~/^rust.*/:
|
||||
return new buildRust()
|
||||
break;
|
||||
case ~/^go.*/:
|
||||
return new buildGo()
|
||||
break;
|
||||
case 'gradle':
|
||||
return new buildGradle()
|
||||
break;
|
||||
case 'php':
|
||||
return new buildPhp()
|
||||
default:
|
||||
return defaultBuild()
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in selecting the build tool (check the spell) Error: ' + e.toString()
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
|
||||
def buildDckr(Map config){
|
||||
def btObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dparam_obj = new getDockerParams()
|
||||
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
def repo_name = config.repo_name
|
||||
def deployArgo = config.deployArgo ?: false
|
||||
// def region = dparam_obj.getRegion(env.cicd_environment)
|
||||
// def registry = dparam_obj.getRegistry(env.cicd_environment)
|
||||
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
|
||||
def tag = dparam_obj.getTag(repo_name)
|
||||
def docker_bindings = [
|
||||
"repo_name": repo_name,
|
||||
'buildRegistry': env.buildRegistry
|
||||
|
||||
]
|
||||
if (config.containsKey("copy_file")){
|
||||
if (env.CLOUD_PROVIDER == 'AWS'){
|
||||
def recursive = config.copy_file.recursive ? " --recursive" : ""
|
||||
dir(repo_name){
|
||||
dir('copied_files'){
|
||||
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
|
||||
}
|
||||
}
|
||||
} else if (env.CLOUD_PROVIDER == 'GCP'){
|
||||
def recursive = config.copy_file.recursive ? " -r" : ""
|
||||
dir(repo_name){
|
||||
dir('copied_files'){
|
||||
sh(script:"gsutil cp${recursive} ${config.copy_file.path} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
docker_bindings["copy_file"] = true
|
||||
docker_bindings["copy_target"] = config.copy_file.target ?: "/opt/target"
|
||||
}
|
||||
else{
|
||||
docker_bindings["copy_file"] = false
|
||||
}
|
||||
stage(stageName('Building docker images')){
|
||||
// Login to docker
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
env.msg = "Error in Docker login"
|
||||
env.error_msg_to_db = "Error in Docker login"
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
try{
|
||||
if (env.CLOUD_PROVIDER == "AWS"){
|
||||
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${docker_repo} || aws ecr create-repository --region ${env.region} --repository-name ${docker_repo}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP'){
|
||||
echo "Skipping - Registry Creation in GCP."
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
env.msg = "Error in creating ECR repository ${docker_repo}"
|
||||
env.error_msg_to_db = "Error in creating ECR repository ${docker_repo}"
|
||||
currentBuild.result = "FAILURE"
|
||||
}
|
||||
try {
|
||||
dir(repo_name){
|
||||
if(!fileExists("Dockerfile")){
|
||||
constructObj.renderTemplate(docker_bindings,'php-Dockerfile','Dockerfile-php')
|
||||
if (env.cicd_environment != 'ftr') {
|
||||
sh(script: "docker build --tag ${env.registry}/${docker_repo}:${tag} -f Dockerfile-php . && docker push ${env.registry}/${docker_repo}:${tag}")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker builds for PHP in ${env.cicd_environment} env")
|
||||
}
|
||||
|
||||
//Remove dockerfile
|
||||
sh(script: "rm -rf Dockerfile-php")
|
||||
}
|
||||
else {
|
||||
sh(script: "docker build --tag ${env.registry}/${docker_repo}:${tag} . && docker push ${env.registry}/${docker_repo}:${tag}")
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "Error in building DockerFile Or Pushing To artifact registry"
|
||||
env.error_msg_to_db = "Error in building DockerFile Or Pushing To image registry"
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return [tag , deployArgo]
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.utilities.addSSHKey
|
||||
import com.meesho.utilities.dockerUtilities
|
||||
/*
|
||||
Function to get the version from pom.xml
|
||||
input arguments:
|
||||
repo_name: String parameter to change the directory where pom.xml is located
|
||||
*/
|
||||
// def getArtifactId(String repo_name){
|
||||
// dir("$repo_name"){
|
||||
// if (fileExists("package.json")) {
|
||||
// return sh(returnStdout: true, script: 'jq -r .name package.json').trim()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// def getAwsSecret(def secret_name, def destination_file){
|
||||
// sh (script:"aws secretsmanager get-secret-value --secret-id ${secret_name} --query SecretString --output text > ${destination_file}")
|
||||
// }
|
||||
|
||||
// def getCommitid(String repo_name){
|
||||
// dir("$repo_name"){
|
||||
// return sh(returnStdout: true, script: 'git log -1 --format=%h').trim()
|
||||
// }
|
||||
// }
|
||||
|
||||
// def getNpmRc(def secret_name){
|
||||
// def npmrc_file = secret_name + "-npmrc"
|
||||
// sh (script:"aws secretsmanager get-secret-value --secret-id ${npmrc_file} --query SecretString --output text| jq -r .MEESHO_NPMRC_SECRET > .npmrc")
|
||||
// }
|
||||
|
||||
// def getPemFile(def secret_name){
|
||||
// def pem_secret_name = secret_name + "-secrets"
|
||||
// if(env.BUILD_ENV == 'stage'){
|
||||
// sh (script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_dev > 1_public_secret_dev.pem")
|
||||
// sh (script:"cat 1_public_secret_dev.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_dev.pem")
|
||||
// }
|
||||
// sh (script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_prod > 1_public_secret_prod.pem")
|
||||
// sh (script:"cat 1_public_secret_prod.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_prod.pem")
|
||||
// }
|
||||
|
||||
// def getEnvFile(def secret_name){
|
||||
// def env_file = secret_name + "-env"
|
||||
// def destination_file = ".env"
|
||||
// sh(script:"aws secretsmanager get-secret-value --secret-id ${env_file} | jq --raw-output '.SecretString' | jq '.' | jq -r 'to_entries|map(\"\\(.key)=\\(.value|tostring)\")|.[]' > .env")
|
||||
// }
|
||||
|
||||
// def getManifestJson(def secret_name){
|
||||
// def manifest_file = secret_name+"-manifest"
|
||||
// def destination_file = "public/manifest.json"
|
||||
// getAwsSecret(manifest_file,destination_file)
|
||||
// }
|
||||
/*
|
||||
Fuction to build maven docker repo
|
||||
*/
|
||||
|
||||
def buildDckr(Map config) {
|
||||
def btObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dparam_obj = new getDockerParams()
|
||||
def addSSHKey = new addSSHKey()
|
||||
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
def repo_name = config.repo_name
|
||||
def deployArgo = config.deployArgo ?: false
|
||||
def modules_requirements_file = config.modules_requirements_file ?: 'requirements.txt'
|
||||
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
|
||||
def tag = dparam_obj.getTag(repo_name)
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
def dockerUtilObj = new dockerUtilities()
|
||||
if (dockerUtilObj.imageExists(env.registry, docker_repo, tag)) {
|
||||
log.info("Toolchain: Image found in registry for ${docker_repo}:${tag}. Skipping build step.")
|
||||
return [tag, deployArgo]
|
||||
} else {
|
||||
log.info("Toolchain: Image missing for ${docker_repo}:${tag}. Proceeding with build.")
|
||||
}
|
||||
}
|
||||
// TODO: create value binding for dockerfile render
|
||||
def docker_bindings = [
|
||||
'buildRegistry': env.buildRegistry,
|
||||
'modules_requirements_file': modules_requirements_file,
|
||||
'arch': config.arch,
|
||||
'buildRegistry': env.buildRegistry
|
||||
]
|
||||
docker_bindings['arch'] = config.arch
|
||||
// stage("Create build files"){
|
||||
// dir(repo_name){
|
||||
// getNpmRc(secret_name)
|
||||
// getEnvFile(secret_name)
|
||||
// if (require_pemfiles){getPemFile(secret_name)}
|
||||
// if (require_mainfest){getManifestJson(secret_name)}
|
||||
// }
|
||||
// }
|
||||
stage(stageName('Building docker images')) {
|
||||
// Login to docker
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in Docker login'
|
||||
env.error_msg_to_db = 'Error in Docker login'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
if (config.containsKey('copy_file')) {
|
||||
def recursive = config.copy_file.recursive ? ' --recursive' : ''
|
||||
docker_bindings['copy_file_path'] = config.copy_file.path
|
||||
dir(repo_name) {
|
||||
dir('copied_files') {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
// delete any old data
|
||||
sh(script:'rm -rf *')
|
||||
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
// delete any old data
|
||||
docker_bindings['recursive'] = '-r'
|
||||
sh(script:'rm -rf *')
|
||||
sh(script:"gsutil cp ${docker_bindings.recursive} ${docker_bindings.copy_file_path} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
docker_bindings['copy_file'] = true
|
||||
docker_bindings['copy_target'] = config.copy_file.target ?: '/app/'
|
||||
}
|
||||
else {
|
||||
docker_bindings['copy_file'] = false
|
||||
}
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${docker_repo} || aws ecr create-repository --region ${env.region} --repository-name ${docker_repo}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
echo 'Skipping - Registry Creation in GCP.'
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "Error in creating ECR repository ${docker_repo}"
|
||||
env.error_msg_to_db = "Error in creating ECR repository ${docker_repo}"
|
||||
currentBuild.result = env.FAILURE
|
||||
}
|
||||
try {
|
||||
dir(repo_name) {
|
||||
addSSHKey.create()
|
||||
if (!fileExists('Dockerfile')) {
|
||||
// print(config)
|
||||
constructObj.renderTemplate(docker_bindings,config.dockerBuildVersion+'-Dockerfile','Dockerfile-'+repo_name)
|
||||
sh "cat Dockerfile-${repo_name}"
|
||||
// withCredentials([string(credentialsId: 'meesho-github-ssh-prv-key', variable: 'SSH_PRIVATE_KEY_S')]) {
|
||||
// withCredentials(bindings: [sshUserPrivateKey(credentialsId: 'meesho-ssh-github-key', \
|
||||
// keyFileVariable: 'SSH_PRIVATE_KEY', \
|
||||
// passphraseVariable: '', \
|
||||
// usernameVariable: '')]) {
|
||||
//withCredentials([string(credentialsId: 'git_private_key', variable: 'gitkey')]) {
|
||||
// sh """
|
||||
// set +x
|
||||
// docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile-${repo_name}" . && docker push ${env.registry}/${docker_repo}:${tag}
|
||||
// set -x
|
||||
// """
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh """
|
||||
set +x
|
||||
docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile-${repo_name}" .
|
||||
docker push ${env.registry}/${docker_repo}:${tag}
|
||||
set -x
|
||||
"""
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
|
||||
sh """
|
||||
set +x
|
||||
docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile-${repo_name}" .
|
||||
docker push ${env.registry}/${docker_repo}:${tag}
|
||||
set -x
|
||||
"""
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker builds for Python in ${env.cicd_environment} env")
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
//Remove dockerfile
|
||||
sh(script: "rm -rf Dockerfile-${repo_name}")
|
||||
}
|
||||
else {
|
||||
sh "cat Dockerfile"
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh """
|
||||
set +x
|
||||
docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile" .
|
||||
docker push ${env.registry}/${docker_repo}:${tag}
|
||||
set -x
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "Error in building DockerFile Or Pushing To ECR. For Full Error Details - ${e}"
|
||||
env.error_msg_to_db = 'Error in building DockerFile Or Pushing To ECR'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
return [tag , deployArgo]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.utilities.addSSHKey
|
||||
|
||||
|
||||
|
||||
def buildDckr(Map config) {
|
||||
env.RUSTPRIVATE = 'github.com/Meesho'
|
||||
def btObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dparam_obj = new getDockerParams()
|
||||
def addSSHKey = new addSSHKey()
|
||||
def deployArgo = config.deployArgo ?: true
|
||||
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
def modules = config.modules ?: ['module_less']
|
||||
def repo_name = config.repo_name
|
||||
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
|
||||
def tag = dparam_obj.getTag(repo_name)
|
||||
def buildx = config.containsKey('buildx') ? config.buildx : true
|
||||
def docker_bindings = [:]
|
||||
def skip_sonar = config.skip_sonar ?: false
|
||||
def version = config.dockerBuildVersion.split('-')[-1]
|
||||
def repoType = config.repo_type ?: 'microservice'
|
||||
docker_bindings['version'] = version
|
||||
docker_bindings['base_dir'] = config.base_dir ?: false
|
||||
docker_bindings['buildRegistry'] = env.buildRegistry
|
||||
docker_bindings['build_packages'] = getSystemPackages(config, 'build_packages')
|
||||
docker_bindings['runtime_packages'] = getSystemPackages(config, 'runtime_packages')
|
||||
stage('Build docker images') {
|
||||
|
||||
|
||||
// Login to docker
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
|
||||
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in Docker login'
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error(env.msg + '. Error: ' + e.toString())
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
if (config.containsKey('copy_file')) {
|
||||
def recursive = config.copy_file.recursive ? ' --recursive' : ''
|
||||
dir(repo_name) {
|
||||
dir('copied_files') {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
|
||||
} else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script:"gsutil cp${recursive} ${config.copy_file.path} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
docker_bindings['copy_file'] = true
|
||||
docker_bindings['copy_target'] = config.copy_file.target ?: '/app/'
|
||||
docker_bindings['base_dir'] = config.base_dir ?: false
|
||||
}
|
||||
else {
|
||||
docker_bindings['copy_file'] = false
|
||||
}
|
||||
|
||||
try {
|
||||
dir(repo_name) {
|
||||
sonar_scan(repo_name, skip_sonar, version )
|
||||
|
||||
if (repoType != 'microservice') {
|
||||
log.info("Skipping Docker build for ${repoType} repo type")
|
||||
return [tag, deployArgo]
|
||||
}
|
||||
|
||||
addSSHKey.create()
|
||||
if (!fileExists('Dockerfile')) {
|
||||
for (module in modules) {
|
||||
def module_name = (module instanceof LinkedHashMap) ? module.keySet()[0] : module
|
||||
docker_bindings['module_property'] = (module instanceof LinkedHashMap) ? module[module_name] : [ : ]
|
||||
docker_bindings['module'] = module_name
|
||||
docker_bindings['binary_name'] = (module == 'module_less') ? repo_name : module_name
|
||||
constructObj.renderTemplate(docker_bindings, 'rust-Dockerfile', 'Dockerfile-' + module_name)
|
||||
sh "cat Dockerfile-${module_name}"
|
||||
module_repo = (module == 'module_less') ? docker_repo : docker_repo + '/' + module_name
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${module_repo} || aws ecr create-repository --region ${env.region} --repository-name ${module_repo}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
echo 'Skipping - Registry Creation in GCP.'
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "Error in creating ECR repository ${module_repo}"
|
||||
env.error_msg_to_db = "Error in creating ECR repository ${module_repo}"
|
||||
currentBuild.result = 'FAILURE'
|
||||
}
|
||||
if (buildx) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "set +x && docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} --push .")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if (env.cicd_environment != 'ftr') {
|
||||
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} . && docker push ${env.registry}/${module_repo}:${tag}")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker Push - ${env.cicd_environment} env")
|
||||
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} . && docker push ${env.registry}/${module_repo}:${tag}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if (env.cicd_environment != 'ftr') {
|
||||
sh(script: """
|
||||
set +x
|
||||
# Setup buildx for ARM64 builds
|
||||
docker buildx rm mybuilder || true
|
||||
docker buildx create --name mybuilder --driver docker-container --bootstrap
|
||||
docker buildx use mybuilder
|
||||
|
||||
# Build for ARM64
|
||||
docker buildx build --platform linux/arm64 --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} --push .
|
||||
""")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker Push - ${env.cicd_environment} env")
|
||||
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
//Remove dockerfile
|
||||
sh(script: "rm -rf Dockerfile-${module_name}")
|
||||
}
|
||||
}
|
||||
else {
|
||||
sh "cat Dockerfile"
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
|
||||
if (env.cicd_environment != 'ftr') {
|
||||
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
|
||||
}
|
||||
else {
|
||||
log.info("Skipping Docker Push - ${env.cicd_environment} env")
|
||||
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} .")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in building DockerFile Or Pushing To ECR'
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error(env.msg + '. Error: ' + e.toString())
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
return [tag, deployArgo]
|
||||
}
|
||||
}
|
||||
|
||||
// Services may need native libraries that are not part of a shared base image
|
||||
// (for example, database client headers used by a crate's build script). The
|
||||
// keys are language-neutral for future reuse; currently only the Rust builder
|
||||
// consumes them. Restrict values to Debian package names so config data cannot
|
||||
// alter the rendered Dockerfile instruction.
|
||||
def getSystemPackages(Map config, String key) {
|
||||
def configuredPackages = config[key]
|
||||
if (configuredPackages == null) {
|
||||
return []
|
||||
}
|
||||
if (!(configuredPackages instanceof List)) {
|
||||
throw new IllegalArgumentException("${key} must be a YAML list of system package names")
|
||||
}
|
||||
|
||||
def packages = configuredPackages.collect { packageName -> packageName?.toString()?.trim() }
|
||||
if (packages.any { packageName -> !packageName || !(packageName ==~ /^[a-z0-9][a-z0-9+.-]*$/) }) {
|
||||
throw new IllegalArgumentException("${key} contains an invalid system package name")
|
||||
}
|
||||
return packages.unique()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Fuction to execute sonar scan
|
||||
Input Arguments:
|
||||
repo_name: repository name
|
||||
skip_sonar: boolena parameter to skip sonar scan
|
||||
*/
|
||||
|
||||
def sonar_scan(String repo_name, boolean skip_sonar , String version ) {
|
||||
try {
|
||||
stage('Run sonar scan') {
|
||||
if (!skip_sonar) {
|
||||
|
||||
withSonarQubeEnv('sonarqube-test') {
|
||||
if (env.CHANGE_ID) {
|
||||
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
|
||||
}
|
||||
sh(script: "mvn sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Meesho/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
|
||||
}
|
||||
|
||||
sh(script: "curl -LO https://go.dev/dl/go${go_version}.linux-amd64.tar.gz")
|
||||
sh(script: "tar -xvzf go${go_version}.linux-amd64.tar.gz -C /usr/local",returnStdout: true)
|
||||
sh(script:"rm -Rf go${go_version}.linux-amd64.tar.gz")
|
||||
// Set Go environment variables
|
||||
env.PATH = "/usr/local/go/bin:${env.PATH}"
|
||||
|
||||
// Run Go mod tidy and tests
|
||||
sh (script: "go mod tidy")
|
||||
int testExitCode = sh(script: "go test -short -coverprofile=./cov.out ./...", returnStatus: true)
|
||||
if (testExitCode != 0) {
|
||||
sh(script: "echo Go tests failed, but the pipeline will continue.")
|
||||
}
|
||||
|
||||
// Download and extract Sonar Scanner
|
||||
sh(script: "curl -LO https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip")
|
||||
sh(script: "unzip -o sonar-scanner-cli-5.0.1.3006-linux.zip -d /usr/local/sonar-scanner")
|
||||
sh(script: "rm -Rf sonar-scanner-cli-5.0.1.3006-linux.zip")
|
||||
env.PATH = "/usr/local/sonar-scanner/sonar-scanner-5.0.1.3006-linux/bin:${env.PATH}"
|
||||
|
||||
// Run Sonar Scanner
|
||||
sh(script:"sonar-scanner -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Meesho/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.go.coverage.reportPaths=./cov.out ")
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: "mvn sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}")
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
|
||||
sh(script: "curl -LO https://go.dev/dl/go${go_version}.linux-amd64.tar.gz")
|
||||
sh(script: "tar -xvzf go${go_version}.linux-amd64.tar.gz -C /usr/local",returnStdout: true)
|
||||
sh(script:"rm -Rf go${go_version}.linux-amd64.tar.gz")
|
||||
// Set Go environment variables
|
||||
env.PATH = "/usr/local/go/bin:${env.PATH}"
|
||||
|
||||
// Run Go mod tidy and tests
|
||||
sh (script: "go mod tidy")
|
||||
int testExitCode = sh(script: "go test -short -coverprofile=./cov.out ./...", returnStatus: true)
|
||||
if (testExitCode != 0) {
|
||||
sh(script: "echo Go tests failed, but the pipeline will continue.")
|
||||
}
|
||||
|
||||
// Download and extract Sonar Scanner
|
||||
sh(script: "curl -LO https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip")
|
||||
sh(script: "unzip -o sonar-scanner-cli-5.0.1.3006-linux.zip -d /usr/local/sonar-scanner")
|
||||
sh(script: "rm -Rf sonar-scanner-cli-5.0.1.3006-linux.zip")
|
||||
env.PATH = "/usr/local/sonar-scanner/sonar-scanner-5.0.1.3006-linux/bin:${env.PATH}"
|
||||
|
||||
// Run Sonar Scanner
|
||||
sh(script:"sonar-scanner -Dsonar.go.coverage.reportPaths=./cov.out -Dproject.settings=`pwd`/sonar-project.properties -Dsonar.branch.name=${env.BRANCH_NAME}")
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
log.info('Skipping - Sonar Scan')
|
||||
}
|
||||
}
|
||||
stage("Quality Gate"){
|
||||
|
||||
if (skip_sonar){
|
||||
log.info("Sonar scan is skipped. Marking this stage as passed.")
|
||||
}
|
||||
else if (!env.CHANGE_ID){
|
||||
log.info("Skipping quality gate check on Branches. Marking this stage as passed.")
|
||||
}
|
||||
else{
|
||||
timeout(time: 600, unit: 'SECONDS') {
|
||||
def qg = waitForQualityGate()
|
||||
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE'){
|
||||
if (qg.status != 'OK') {
|
||||
log.warn("Quality gate failed: ${qg.status}, but continuing pipeline execution.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
dir("$repo_name") {
|
||||
withSonarQubeEnv('sonarqube-test') {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
sh(script: 'mvn sonar:sonar')
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
sh(script: "Quality Gate Failed !")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.meesho.stages
|
||||
|
||||
def run(Map param) {
|
||||
try {
|
||||
stage(stageName('Checkout from git')) {
|
||||
dir("${param.repo_name}") {
|
||||
checkout scm
|
||||
if (fileExists('.gitmodules')) {
|
||||
log.info('Repository has submodules - running git submodule init and update --recursive')
|
||||
def credId = env.GITHUB_CRED?.trim()
|
||||
if (!credId || credId == 'null') credId = 'svc-devops-meesho'
|
||||
withCredentials([gitUsernamePassword(credentialsId: credId, gitToolName: 'git-tool')]) {
|
||||
sh 'git submodule init && git submodule update --recursive'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e) {
|
||||
env.msg = 'Error cloning the job. Error: ' + e.toString()
|
||||
env.error_msg_to_db = 'Error cloning the job'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def chekoutSubmodule(String repo_name) {
|
||||
try {
|
||||
def credId = env.GITHUB_CRED?.trim()
|
||||
if (!credId || credId == 'null') credId = 'svc-devops-meesho'
|
||||
dir(repo_name) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: credId, gitToolName: 'git-tool')]) {
|
||||
sh(script:'git submodule init && git submodule update && git submodule update --recursive --remote')
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
env.msg = 'Error submodule checkout'
|
||||
env.error_msg_to_db = env.msg
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,906 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
|
||||
|
||||
import com.meesho.utilities.getYamlParameter
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.gitActions
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.constructParam
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.utilities.nodePoolSelection
|
||||
|
||||
def run(String repo_name, def deployment_order, def tag, def build_team, def dockerBuildVersion, String notify_channel) {
|
||||
def userInput = ''
|
||||
// def helm_repo_name = 'devops-helm-charts'
|
||||
// def argo_repo_name = 'devops-argo-config'
|
||||
|
||||
def gitObj = new gitActions()
|
||||
def constructParam = new constructParam()
|
||||
def yamlObj = new getYamlParameter()
|
||||
def branch_name = env.BRANCH_NAME
|
||||
def branch_param_map = ['(master|main|gcp-main|gcp-master|farmiso-main)': ['branch':'main', 'envrn':'prd'],
|
||||
'(develop|gcp-dev)':['branch':'develop', 'envrn':'stg']]
|
||||
|
||||
if (env.CHANGE_ID) {
|
||||
branch_param_map = [
|
||||
'(develop|gcp-dev)':['branch':'feature', 'envrn':'ftr'],
|
||||
'(master|main|gcp-main|gcp-master|farmiso-main)':['branch':'pre-prod', 'envrn':'int']]
|
||||
branch_name = env.CHANGE_TARGET
|
||||
}
|
||||
def branch_param = branch_param_map.collectEntries { key, value -> branch_name.matches(key) ? value : [ : ] }
|
||||
if (branch_param == [:]) {
|
||||
branch_param = ['branch':'feature', 'envrn':'ftr']
|
||||
}
|
||||
def helm_branch_name = branch_param.branch
|
||||
def argo_branch_name = branch_param.branch
|
||||
def envrn = branch_param.envrn
|
||||
if (env.CHANGE_ID && env.CHANGE_BRANCH != "develop" && env.CHANGE_TARGET == "main" ) {
|
||||
def allowedNonDevelopPrDeploymentToInt = constructParam.allowedNonDevelopPrDeploymentToIntRepos(repo_name)
|
||||
if (!allowedNonDevelopPrDeploymentToInt) {
|
||||
log.error("******** ONLY DEVELOP BRANCH PR ALLOWED FOR PRE-PROD ENV DEPLOYMENT ********")
|
||||
return
|
||||
}
|
||||
}
|
||||
log.info('Please provide apps to deploy')
|
||||
timeout(unit: 'SECONDS', time: 300) {
|
||||
userInput = wait_for_user_input(deployment_order)
|
||||
}
|
||||
|
||||
// change deployment order according to user input
|
||||
|
||||
if (userInput == '') {
|
||||
log.info('No Deployments selected. Running remaining steps.')
|
||||
return
|
||||
}
|
||||
else if (!userInput.contains('All')) {
|
||||
deployment_order = userInput.split(',') as List
|
||||
}
|
||||
|
||||
commit_branch_name = env.CHANGE_ID ? env.CHANGE_BRANCH : env.BRANCH_NAME
|
||||
def commit_id = gitObj.fetchLatestCommitId(repo_name, commit_branch_name)
|
||||
env.COMMIT_ID = commit_id
|
||||
|
||||
env.SERVICES = deployment_order
|
||||
//Show selected applications to deploy
|
||||
log.info('Following services will be deployed:\n' + deployment_order.join('\n'))
|
||||
// Clone the repo just once for all the deployments
|
||||
gitObj.clone("${WORKSPACE}", "${env.helm_repo_name}", "${helm_branch_name}")
|
||||
|
||||
// Clone the repo just once for all the deployments
|
||||
gitObj.clone("${WORKSPACE}", "${env.argo_repo_name}", "${argo_branch_name}")
|
||||
|
||||
for (deployment in deployment_order) {
|
||||
try {
|
||||
|
||||
def isMultizoneEnabled = constructParam.isMultizoneEnabled(deployment)
|
||||
log.info(" Multi-zone enabled for ${deployment} - ${isMultizoneEnabled}")
|
||||
if (isMultizoneEnabled) {
|
||||
def multizone = "Multi-zone enabled for this deployable ${deployment}. Please use Ringmaster for deployment."
|
||||
currentBuild.result = env.FAILURE
|
||||
throw new Exception(multizone)
|
||||
}
|
||||
def value_binding = yamlObj.getParam("${repo_name}/deployments", "${deployment}.yaml")
|
||||
constructParam.perDeploymentVars(value_binding)
|
||||
// if(envrn == 'prd') {
|
||||
// stage("${deployment}: Downscale Pods in Preprod Env") {
|
||||
// preprod_downscale(repo_name, deployment,notify_channel)
|
||||
// }
|
||||
// }
|
||||
stage("${deployment}: Update Argo App") {
|
||||
update_argo_repo(repo_name, deployment, argo_branch_name, envrn)
|
||||
}
|
||||
stage('Update Argo App of apps') {
|
||||
refresh_app_of_apps(envrn)
|
||||
}
|
||||
stage("${deployment}: Update Helm Repo") {
|
||||
update_helm_repo(repo_name, deployment, tag, build_team, helm_branch_name, envrn, dockerBuildVersion, notify_channel)
|
||||
}
|
||||
stage("${deployment}: Refresh & Sync App in argoCD") {
|
||||
refresh_and_sync(repo_name, deployment, envrn)
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e)
|
||||
currentBuild.result = env.FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// def preprod_downscale(String repo_name, String deployment, String notify_channel){
|
||||
// def yamlobj = new getYamlParameter()
|
||||
// def deploy_values = yamlobj.getParam("${repo_name}/deployments","${deployment}.yaml")
|
||||
// def app_name = deploy_values.app_name
|
||||
// def bu = deploy_values.bu
|
||||
// def slack_channel = notify_channel
|
||||
// def as_enabled = deploy_values.environment.'int'.as_enabled
|
||||
// log.info("########################### Invoking Jenkins Job to Downscale Pods in Preprod Environment. ###########################")
|
||||
// build wait: false, job: 'downscale-preprod-eks', parameters:[string(name:'app_name', value:"${app_name}"),
|
||||
// string(name:'bu',value:"${bu}"),
|
||||
// string(name:'as_enabled',value:"${as_enabled}"),
|
||||
// string(name:'slack_channel',value:"${slack_channel}")]
|
||||
// }
|
||||
|
||||
def wait_for_user_input(def deployments) {
|
||||
def userInput = ''
|
||||
String choices = 'All,' + deployments.join(',')
|
||||
int visibleItemCount = 1 + deployments.size()
|
||||
def multiSelect = new ExtendedChoiceParameterDefinition('deployments', //name
|
||||
'PT_CHECKBOX', // parameter type
|
||||
choices, //values
|
||||
'', //projectName
|
||||
'', //propertyFile
|
||||
'', //groovyScript
|
||||
'', //groovyScriptFile
|
||||
'', //bindings
|
||||
'', //groovyClasspath
|
||||
'', //propertyKey
|
||||
'', //defaultValue
|
||||
'', //defaultPropertyFile
|
||||
'', //defaultGroovyScript
|
||||
'', //defaultGroovyScriptFile
|
||||
'', //defaultBindings
|
||||
'', //defaultGroovyClasspath
|
||||
'', //defaultPropertyKey
|
||||
'', //descriptionPropertyValue
|
||||
'', //descriptionPropertyFile
|
||||
'', //descriptionGroovyScript
|
||||
'', //descriptionGroovyScriptFile
|
||||
'', //descriptionBindings
|
||||
'', //descriptionGroovyClasspath
|
||||
'', //descriptionPropertyKey
|
||||
'', //javascriptFile
|
||||
'', //javascript
|
||||
false, //saveJSONParameterToFile
|
||||
false, //quoteValue
|
||||
visibleItemCount, //visibleItemCount
|
||||
'Choose Deployments', //description
|
||||
',') //multiSelectDelimiter
|
||||
|
||||
stage('wait for user input') {
|
||||
try {
|
||||
echo "Skipping User Input - ${env.skip_user_input}"
|
||||
if (env.skip_user_input.toBoolean()) {
|
||||
userInput = 'All'
|
||||
}
|
||||
else {
|
||||
userInput = input message: 'Choose applications to deploy', ok: 'Deploy', parameters: [multiSelect]
|
||||
}
|
||||
return userInput
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in taking userInput' + e.toString()
|
||||
env.error_msg_to_db = 'Error Taking User Input for Deployment of Applications'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def update_helm_repo(String repo_name, String deployment, String tag, String build_team, String helm_branch_name, String envrn, def dockerBuildVersion, String notify_channel) {
|
||||
def yamlobj = new getYamlParameter()
|
||||
def btObj = new buTeamMapping()
|
||||
def gitObj = new gitActions()
|
||||
def templateObj = new constructTemplate()
|
||||
def nodePoolSelection = new nodePoolSelection()
|
||||
// def helm_repo_name = 'devops-helm-charts'
|
||||
|
||||
def value_yaml_file = get_value_yaml_file(dockerBuildVersion)
|
||||
def value_binding1 = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
|
||||
if (value_binding1.containsKey('cron')) {
|
||||
if (value_binding1['cron']) {
|
||||
value_yaml_file = 'cron-values.yaml'
|
||||
}
|
||||
}
|
||||
|
||||
def env_norm = ['prd':'prod', 'int':'pre-prod', 'stg':'stg', 'ftr':'feature']
|
||||
def pr_num = ''
|
||||
def commit_status = 0
|
||||
|
||||
try {
|
||||
// Get values from deployments/deployment.yaml
|
||||
isfeatureDeployment = (envrn == 'ftr') ? true : false
|
||||
value_binding1 = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
|
||||
def memory_request = value_binding1.environment[env.cicd_environment].memory_request
|
||||
def cpu_request = value_binding1.environment[env.cicd_environment].cpu_request
|
||||
def priority_v2 = value_binding1.priority_v2
|
||||
def commit_id = env.COMMIT_ID
|
||||
if ( env.CLOUD_PROVIDER == 'GCP' && !value_binding1.containsKey('cron') ) {
|
||||
nodeSelectorValue = nodePoolSelection.run(memory_request, cpu_request.toString(),priority_v2)
|
||||
echo "Node Selector Value is ${nodeSelectorValue}"
|
||||
value_binding1['nodeSelectorValue'] = nodeSelectorValue
|
||||
}
|
||||
def xms = ''
|
||||
def xmx = ''
|
||||
if (!value_binding1.containsKey('cron')) {
|
||||
if (dockerBuildVersion.contains('maven') || dockerBuildVersion.contains('gradle') || dockerBuildVersion.contains('go')) {
|
||||
value_binding1['activeProcessorCount'] = calculate_active_processors(cpu_request.toString())
|
||||
}
|
||||
if (dockerBuildVersion.contains('maven') || dockerBuildVersion.contains('gradle')) {
|
||||
def memory_limit = value_binding1.environment[env.cicd_environment].memory_limit
|
||||
def deployment_args = value_binding1.environment[env.cicd_environment].deployment_args
|
||||
echo "memory_limit is ${memory_limit}"
|
||||
def memory_string = memory_limit
|
||||
echo "performing operations on this memory string - ${memory_string}"
|
||||
|
||||
def memory_value = ''
|
||||
|
||||
if ( memory_string.contains('M') ) {
|
||||
memory_value = memory_string.replaceAll('Mi', '')
|
||||
memory_value = memory_value.replaceAll('M', '')
|
||||
try {
|
||||
memory_value = memory_value.toInteger()
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
memory_value = memory_value.toDouble()
|
||||
memory_value = memory_value.toInteger()
|
||||
}
|
||||
}
|
||||
else if ( memory_string.contains('G') ) {
|
||||
memory_value = memory_string.replaceAll('Gi', '')
|
||||
memory_value = memory_value.replaceAll('G', '')
|
||||
try {
|
||||
memory_value = memory_value.toInteger() * 1024
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
memory_value = memory_value.toDouble() * 1024
|
||||
memory_value = memory_value.toInteger()
|
||||
}
|
||||
}
|
||||
|
||||
memory_value = memory_value * 0.5
|
||||
memory_value = memory_value.toInteger()
|
||||
xms = "${memory_value}M"
|
||||
xmx = "${memory_value}M"
|
||||
|
||||
echo "xms and xmx from memory value - ${memory_value} are - ${xms} ${xmx}"
|
||||
for (arg in deployment_args) {
|
||||
if (arg.contains('Xms')) {
|
||||
xms = arg.replaceAll('.*Xms', '')
|
||||
echo "xms from deployment_args - ${xms}"
|
||||
}
|
||||
if (arg.contains('Xmx')) {
|
||||
xmx = arg.replaceAll('.*Xmx', '')
|
||||
echo "xmx from deployment_args - ${xmx}"
|
||||
}
|
||||
}
|
||||
echo "final xms and xmx - ${xms} ${xmx}"
|
||||
}
|
||||
}
|
||||
|
||||
value_binding1['dockerBuildVersion'] = dockerBuildVersion == 'python-3.10.12' ? 'python-3.7' : dockerBuildVersion
|
||||
deployEnv = !value_binding1['environment'].containsKey(envrn) && isfeatureDeployment ? 'stg' : envrn
|
||||
Map value_binding = value_binding1['environment'].collectEntries { key, value -> deployEnv.matches(key) ? value : [ : ] }
|
||||
value_binding1.remove('environment')
|
||||
value_binding1.putAll(value_binding)
|
||||
|
||||
value_binding1['repo_name'] = repo_name
|
||||
value_binding1['environment'] = envrn
|
||||
value_binding1['environment_norm'] = env_norm[envrn]
|
||||
value_binding1['tag'] = tag
|
||||
value_binding1['repo_name'] = repo_name
|
||||
value_binding1['build_team'] = build_team
|
||||
value_binding1['commit_id'] = commit_id
|
||||
|
||||
def buini = btObj.get_bu_initials(value_binding1.bu)
|
||||
def bu = btObj.get_bu_initials(value_binding1.bu)
|
||||
def teamini = btObj.get_team_initials(value_binding1.team)
|
||||
def team = btObj.get_team_initials(value_binding1.team)
|
||||
def app_name = value_binding1.app_name
|
||||
def app_branch = app_name + '-' + helm_branch_name
|
||||
|
||||
def app_helm_repo = "${env.helm_repo_name}/${env.helmChartsPath}/${buini}/${teamini}/${app_name}"
|
||||
def ingress_val = value_binding1.ingress_val ?: (env.CHANGE_ID) ? "pr-${CHANGE_ID}" : "${BRANCH_NAME}"
|
||||
|
||||
sh "chmod -R 777 ${app_helm_repo}"
|
||||
|
||||
sh "yq . ${app_helm_repo}/values_properties.yaml -y > a.yaml;mv a.yaml ${app_helm_repo}/values_properties.yaml"
|
||||
sh "cat ${app_helm_repo}/values_properties.yaml"
|
||||
if (isfeatureDeployment) {
|
||||
env.ingress_val = ingress_val
|
||||
value_binding1['env_ns'] = ingress_val
|
||||
value_binding1['vault_env'] = value_binding1['create_vault_path'] ? ingress_val : 'stg'
|
||||
sh(returnStdout: true, script: """
|
||||
mkdir -p ${app_helm_repo}/${ingress_val}
|
||||
sed "s/INGRESS_PR_NUMBER/${ingress_val}/g" ${app_helm_repo}/values_properties.yaml > ${app_helm_repo}/${ingress_val}/values_properties.yaml
|
||||
""")
|
||||
value_binding2 = yamlobj.getParam("${app_helm_repo}/${ingress_val}", 'values_properties.yaml')
|
||||
app_branch = ingress_val + '-' + app_branch
|
||||
}
|
||||
else {
|
||||
value_binding1['vault_env'] = envrn
|
||||
value_binding1['env_ns'] = envrn
|
||||
value_binding2 = yamlobj.getParam("${app_helm_repo}", 'values_properties.yaml')
|
||||
echo '722 Printing Value Binding 2'
|
||||
print value_binding2
|
||||
}
|
||||
|
||||
value_binding1.putAll(value_binding2)
|
||||
value_binding1['bu_norm'] = value_binding1['bu']
|
||||
value_binding1['team_norm'] = value_binding1['team']
|
||||
value_binding1['bu'] = buini
|
||||
value_binding1['team'] = teamini
|
||||
|
||||
|
||||
def serviceTypes = ["httpstateless", "consumer", "producer", "scheduler", "worker", "grpc", "web", "websocket", "cache", "database"]
|
||||
//validate service type params
|
||||
if (value_binding1['service_type']){
|
||||
// Validating the parameter type
|
||||
if(!(value_binding1['service_type'] instanceof List) || value_binding1['service_type'].isEmpty()){
|
||||
env.msg = 'You have not specified service_type correctly. Exiting the pipeline.'
|
||||
log.error(env.msg)
|
||||
sh 'exit 1'
|
||||
}
|
||||
// Check if value_binding1['service_type'] contains any service type not in servicesType
|
||||
def invalidServiceTypes = value_binding1['service_type'].findAll { !serviceTypes.contains(it) }
|
||||
if (!invalidServiceTypes.isEmpty()) {
|
||||
log.error("Invalid service type(s): ${invalidServiceTypes.join(',')}. Allowed service_types are: ${serviceTypes.join(',')}")
|
||||
sh 'exit 1'
|
||||
}
|
||||
value_binding1['service_type_norm'] = value_binding1['service_type'].join(',')
|
||||
}
|
||||
else{
|
||||
value_binding1['service_type_norm']=''
|
||||
}
|
||||
|
||||
// Enable backward compatibility for missing keys
|
||||
enable_backward_compatibility(value_binding1)
|
||||
value_binding1['prismsdk_environment'] = 'PRODUCTION' // THIS KEY WILL CHANGE ONCE 3RD CONFIRM TO STANDERIZE
|
||||
if (envrn == 'stg'){
|
||||
value_binding1['otel_enabled'] = true
|
||||
value_binding1['prismsdk_environment'] = 'SANDBOX' // THIS KEY WILL CHANGE ONCE 3RD CONFIRM TO STANDERIZE
|
||||
}
|
||||
// Override hot fix and notify_channel
|
||||
value_binding1['canary']['skipAnalysis'] = (env.hot_fix) ? true : value_binding1['canary']['skipAnalysis']
|
||||
value_binding1['canary']['slackChannel'] = notify_channel
|
||||
value_binding1['xms'] = xms
|
||||
value_binding1['xmx'] = xmx
|
||||
value_binding1['CLOUD_PROVIDER'] = env.CLOUD_PROVIDER
|
||||
def appConfig = value_binding1['appConfigEnabled']
|
||||
if (appConfig) {
|
||||
def configModule = (value_binding1["module"] == 'module_less') ? repo_name : value_binding1["module"]
|
||||
// read the static config from configs directory
|
||||
def value_binding3 = yamlobj.getParamAsString("${repo_name}/configs/${configModule}", "application-${envrn}.yml")
|
||||
// to update in values.yaml
|
||||
value_binding1['staticAppConfigData'] = value_binding3
|
||||
//read the dynamic config from config directory
|
||||
def value_binding4 = yamlobj.getParamAsString("${repo_name}/configs/${configModule}", "application-dyn-${envrn}.yml")
|
||||
// to update in values.yaml
|
||||
value_binding1['dynamicAppConfigData'] = value_binding4
|
||||
echo 'printing the values_binding3 and values_binding4'
|
||||
print value_binding3
|
||||
print value_binding4
|
||||
value_binding1['vault_env'] = value_binding1['vault_env'] + '-cac'
|
||||
|
||||
}
|
||||
|
||||
|
||||
gitObj.preDeleteBranch(env.helm_repo_name, helm_branch_name, app_branch)
|
||||
gitObj.branchCheckOut(env.helm_repo_name, app_branch)
|
||||
|
||||
echo "Helm Step - Value Binding 1 - ${value_binding1}"
|
||||
if (isfeatureDeployment) {
|
||||
echo 'It is feature deployment'
|
||||
templateObj.renderTemplate(value_binding1, value_yaml_file, "${app_helm_repo}/${ingress_val}/values.yaml")
|
||||
echo 'Before YAML Linting'
|
||||
sh "cat ${app_helm_repo}/${ingress_val}/values.yaml"
|
||||
sh "yq . ${app_helm_repo}/${ingress_val}/values.yaml -y > a.yaml;mv a.yaml ${app_helm_repo}/${ingress_val}/values.yaml"
|
||||
echo 'After YAML Linting'
|
||||
sh "cat ${app_helm_repo}/${ingress_val}/values.yaml"
|
||||
gitObj.add(env.helm_repo_name, "${env.helmChartsPath}/${buini}/${teamini}/${app_name}/${ingress_val}/values.yaml")
|
||||
}
|
||||
else {
|
||||
echo 'Not a feature deployment'
|
||||
templateObj.renderTemplate(value_binding1, value_yaml_file, "${app_helm_repo}/values.yaml")
|
||||
echo 'Before YAML Linting'
|
||||
sh "cat ${app_helm_repo}/values.yaml"
|
||||
|
||||
// Perform YAML linting
|
||||
sh "yq . ${app_helm_repo}/values.yaml -y > a.yaml; mv a.yaml ${app_helm_repo}/values.yaml"
|
||||
echo 'After YAML Linting'
|
||||
sh "cat ${app_helm_repo}/values.yaml"
|
||||
|
||||
// creating a map from final values.yaml to check canary enforcement conditions
|
||||
def valuesMap = yamlobj.getParam("${app_helm_repo}", "values.yaml")
|
||||
|
||||
// Canary enforcement for sp0 services
|
||||
// Also will have to check for cron, worker and scheduler services
|
||||
def enforceCanary = false
|
||||
if (!app_helm_repo.contains("cron") && !app_helm_repo.contains("worker") && !app_helm_repo.contains("scheduler") && !app_helm_repo.contains("consumer") && (valuesMap["labels"]["priority_v2"] == "sp0" || valuesMap["labels"]["priority_v2"] == "up0") && !value_binding1["addHeadless"] && !value_binding1['dockerBuildVersion'].contains("node") && envrn == "prd") {
|
||||
enforceCanary = true
|
||||
}
|
||||
|
||||
def proceed = false
|
||||
def deploymentFailureErrorMessage
|
||||
if (enforceCanary) {
|
||||
if (valuesMap["canary"]["enabled"] == true) {
|
||||
if (valuesMap["canary"]["skipAnalysis"] == false) {
|
||||
if (valuesMap["canary"]["enableManualPromotion"] == true) {
|
||||
proceed = true
|
||||
} else {
|
||||
error("Error: Update the enableManualPromotion parameter")
|
||||
}
|
||||
} else {
|
||||
error("Error: Update the skipAnalysis parameter")
|
||||
|
||||
}
|
||||
} else {
|
||||
error("Error: Enable canary and retry")
|
||||
}
|
||||
} else {
|
||||
proceed = true
|
||||
}
|
||||
|
||||
// Check if priority labels and environment conditions require critical dependency check
|
||||
def criticalPriorities = ["sp0", "up0", "cp0", "sp1", "up1", "cp1"]
|
||||
def priority = valuesMap["labels"]["priority_v2"]
|
||||
if (criticalPriorities.contains(priority) && (envrn == "prd")) {
|
||||
isDependabotCritcal = dependabotCriticalCheck(repo_name)
|
||||
if (isDependabotCritcal) {
|
||||
error("Error: Critical vulnerabilities found in repo: " + repo_name + " \nPlease resolve the alerts marked with CRITICAL here and retry: https://github.com/Meesho/" + repo_name + "/security/dependabot and Retry.")
|
||||
}
|
||||
}
|
||||
|
||||
def param = new constructParam()
|
||||
log.info("checking if appConfig is enabled")
|
||||
def isAppConfigDisabled = param.appConfigDisabledForbidden(appConfig, repo_name, envrn, dockerBuildVersion)
|
||||
if (isAppConfigDisabled){
|
||||
error("Error: appConfig is disabled , onboard your application with config-as-code changes")
|
||||
}
|
||||
|
||||
sh "cat ${app_helm_repo}/values.yaml"
|
||||
gitObj.add(env.helm_repo_name, "${env.helmChartsPath}/${buini}/${teamini}/${app_name}/values.yaml")
|
||||
|
||||
}
|
||||
|
||||
|
||||
commit_status = gitObj.codeCommit(env.helm_repo_name, app_branch, 'Generating values yaml file')
|
||||
if (commit_status == 0) {
|
||||
gitObj.codePush(env.helm_repo_name, app_branch)
|
||||
pr_num = gitObj.createPR(app_name, env.helm_repo_name, helm_branch_name, app_branch, 'Merge helm values file')
|
||||
gitObj.mergePR(env.helm_repo_name, pr_num, app_branch)
|
||||
gitObj.deleteBranch(env.helm_repo_name, helm_branch_name, app_branch)
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
env.msg = 'Error Updating Helm Repo ' + e.toString()
|
||||
env.error_msg_to_db = 'File Not Found'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error Updating Helm Repo ' + e.toString()
|
||||
env.error_msg_to_db += 'Error Updating in Helm repo. Git error message - ' + env.error_part_msg_to_db
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def refresh_and_sync(String repo_name, String deployment, String envrn) {
|
||||
def yamlobj = new getYamlParameter()
|
||||
def deploy_values = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
|
||||
def app_name = deploy_values.app_name
|
||||
// def argoUrl = (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'main' || env.CHANGE_TARGET == 'master' || env.CHANGE_TARGET == 'main') ? 'prod-ops-argocd.meesho.com' : 'stg-dev-argocd.meeshotest.in'
|
||||
def argoEnv = (envrn == 'ftr') ? env.ingress_val : envrn
|
||||
|
||||
log.info('########################### Pulling latest changes in ArgoCD. ###########################')
|
||||
withCredentials([usernamePassword(credentialsId: env.argoCreds, passwordVariable: 'ARGO_PASSWORD', usernameVariable: 'ARGO_USERNAME')]) {
|
||||
try {
|
||||
sh """
|
||||
set +x
|
||||
argocd login ${env.argoURL}:443 --username ${ARGO_USERNAME} --password ${ARGO_PASSWORD} --grpc-web
|
||||
argocd app get --hard-refresh ${argoEnv}-${app_name} --grpc-web
|
||||
"""
|
||||
}
|
||||
catch (Exception e) { //added try catch block here
|
||||
env.msg = "Error in hard refresh of app ${app_name} full error: ${e}"
|
||||
env.error_msg_to_db += "Error in hard refresh of app ${app_name};"
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
log.info('########################### Syncing latest changes in ArgoCD. ###########################')
|
||||
return_value = sh(returnStatus: true, script: "argocd app sync ${argoEnv}-${app_name} --grpc-web --http-retry-max 3 --retry-backoff-duration 1m") as Integer
|
||||
if (return_value == 0) {
|
||||
log.info('App synced succesfully.')
|
||||
} else {
|
||||
env.msg = 'App sync failed. Please check in ArgoCD UI.'
|
||||
env.error_msg_to_db += "Error Argo App sync failed ${app_name};"
|
||||
log.error(env.msg)
|
||||
error "${env.msg}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def refresh_app_of_apps(String envrn) {
|
||||
try {
|
||||
appofapps = env.argoIncubator
|
||||
log.info('########################### Pulling latest changes in ArgoCD for App of Apps. ###########################')
|
||||
withCredentials([usernamePassword(credentialsId: env.argoCreds, passwordVariable: 'ARGO_PASSWORD', usernameVariable: 'ARGO_USERNAME')]) {
|
||||
sh """
|
||||
set +x
|
||||
argocd login ${env.argoURL}:443 --username ${ARGO_USERNAME} --password ${ARGO_PASSWORD} --grpc-web
|
||||
argocd app sync ${appofapps} --grpc-web --http-retry-max 3 --retry-backoff-duration 1m || true
|
||||
"""
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error in App Sync' + e.toString()
|
||||
env.error_msg_to_db += 'Error syncing app of app;'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def update_argo_repo(String repo_name, String deployment, String argoBranch, String envrn) {
|
||||
def yamlobj = new getYamlParameter()
|
||||
def btObj = new buTeamMapping()
|
||||
def gitObj = new gitActions()
|
||||
def templateObj = new constructTemplate()
|
||||
// def argo_repo_name = 'devops-argo-config'
|
||||
def pr_num = ''
|
||||
def commit_status = 0
|
||||
def commit_id = env.COMMIT_ID
|
||||
|
||||
value_binding1 = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
|
||||
value_binding1['CLOUD_PROVIDER'] = env.CLOUD_PROVIDER
|
||||
isfeatureDeployment = (envrn == 'ftr') ? true : false
|
||||
deployEnv = !value_binding1['environment'].containsKey(envrn) && isfeatureDeployment ? 'stg' : envrn
|
||||
Map value_binding = value_binding1['environment'].collectEntries { key, value -> deployEnv.matches(key) ? value : [ : ] }
|
||||
value_binding1.remove('environment')
|
||||
value_binding1.putAll(value_binding)
|
||||
value_binding1['environment'] = envrn
|
||||
|
||||
def buini = btObj.get_bu_initials(value_binding1.bu)
|
||||
def bu = value_binding1.bu
|
||||
|
||||
def teamini = btObj.get_team_initials(value_binding1.team)
|
||||
def team = value_binding1.team
|
||||
def app_name = value_binding1.app_name
|
||||
def filename = "${teamini}-${app_name}.yaml"
|
||||
def helm_values_path = "${env.helmChartsPath}/${buini}/${teamini}/${app_name}"
|
||||
def app_branch = app_name + '-' + argoBranch
|
||||
def ingress_val = value_binding1.ingress_val ?: (env.CHANGE_ID) ? "pr-${CHANGE_ID}" : "${BRANCH_NAME}"
|
||||
value_binding1['helm_version'] = value_binding1.helm_version ?: env.defaultHelmChartVersion
|
||||
|
||||
if (isfeatureDeployment) {
|
||||
value_binding1['env_ns'] = ingress_val
|
||||
value_binding1['helm_values_path'] = "${env.helmChartsPath}/${buini}/${teamini}/${app_name}/${ingress_val}"
|
||||
filename = ingress_val + '-' + "${app_name}.yaml"
|
||||
app_branch = ingress_val + '-' + app_branch
|
||||
}
|
||||
else {
|
||||
value_binding1['env_ns'] = envrn
|
||||
value_binding1['helm_values_path'] = "${env.helmChartsPath}/${buini}/${teamini}/${app_name}"
|
||||
filename = "${teamini}-${app_name}.yaml"
|
||||
}
|
||||
|
||||
value_binding1['server'] = env.clusterName
|
||||
value_binding1['clusterName'] = env.clusterName
|
||||
|
||||
value_binding1['branch_name'] = argoBranch
|
||||
value_binding1['buini'] = buini
|
||||
value_binding1['teamini'] = teamini
|
||||
|
||||
value_binding1['priority_v2'] = value_binding1.priority_v2 ?: 'cp3'
|
||||
value_binding1['primary_owner'] = value_binding1.primary_owner != null ? value_binding1.primary_owner.split('@')[0] : value_binding1.team
|
||||
value_binding1['secondary_owner'] = value_binding1.secondary_owner != null ? value_binding1.secondary_owner.split('@')[0] : value_binding1.team
|
||||
value_binding1['argoAppNS'] = env.argoAppNS
|
||||
value_binding1['commit_id'] = commit_id
|
||||
log.info(commit_id)
|
||||
gitObj.preDeleteBranch(env.argo_repo_name, argoBranch, app_branch)
|
||||
gitObj.branchCheckOut(env.argo_repo_name, app_branch)
|
||||
echo "Argo Step - Value Binding 1 - ${value_binding1}"
|
||||
|
||||
dir(env.argo_repo_name) {
|
||||
def dirExists = sh(script: "cat ${env.argoAppsPath}/${filename}", returnStatus: true)
|
||||
if ( dirExists != 0 ) {
|
||||
sh "mkdir -p ${env.argoAppsPath}"
|
||||
sh "touch ${env.argoAppsPath}/${filename}"
|
||||
}
|
||||
sh "chmod -R 777 ${env.argoAppsPath}/${filename}"
|
||||
templateObj.renderTemplate(value_binding1, 'argoApp.yaml', "${env.argoAppsPath}/${filename}")
|
||||
sh "yq . ${env.argoAppsPath}/${filename} -y > a.yaml;mv a.yaml ${env.argoAppsPath}/${filename}"
|
||||
sh "cat ${env.argoAppsPath}/${filename}"
|
||||
}
|
||||
|
||||
gitObj.add(env.argo_repo_name, "${env.argoAppsPath}/${filename}")
|
||||
commit_status = gitObj.codeCommit(env.argo_repo_name, app_branch, "onboarding ${deployment} app to ARGO")
|
||||
if (commit_status == 0) {
|
||||
gitObj.codePush(env.argo_repo_name, app_branch)
|
||||
pr_num = gitObj.createPR(app_name, env.argo_repo_name, argoBranch, app_branch, 'Merge argo application configuration')
|
||||
gitObj.mergePR(env.argo_repo_name, pr_num, app_branch)
|
||||
gitObj.deleteBranch(env.argo_repo_name, argoBranch, app_branch)
|
||||
}
|
||||
}
|
||||
|
||||
def calculate_active_processors(String cpu_request) {
|
||||
// If lowercase m is present
|
||||
if (cpu_request.contains('m')) {
|
||||
// Remove m
|
||||
cpu_request = cpu_request.replaceAll('m', '')
|
||||
|
||||
// If this fails means invalid input is given with m, so we can let the pipeline fail here
|
||||
// Convert to double, divide by thousand to get another double, round it off and then convert to integer.
|
||||
return Math.ceil(cpu_request.toDouble() / 1000).toInteger()
|
||||
}
|
||||
|
||||
return Math.ceil(cpu_request.toDouble()).toInteger()
|
||||
}
|
||||
|
||||
def enable_backward_compatibility(def bindings) {
|
||||
// def primaryEmailInitial = bindings.primary_owner.tokenize( '@' )[0]: null
|
||||
// def secondaryEmailInitial = bindings.secondary_owner.tokenize( '@' )[0]: null
|
||||
def dparam_obj = new getDockerParams()
|
||||
bindings['registry'] = env.registry
|
||||
def canary_default = [
|
||||
'progressDeadlineSeconds': 300,
|
||||
'analysisInterval': '120s',
|
||||
'analysisThreshold': 5,
|
||||
'analysisMaxWeight': 5,
|
||||
'analysisStepWeight': 5,
|
||||
'analysisMetrics':[
|
||||
'thresholdRangeMin': 0.99,
|
||||
'interval': '1m'],
|
||||
'skipAnalysis': false
|
||||
]
|
||||
def statefulset_default = [
|
||||
'updateStrategy': 'RollingUpdate',
|
||||
'volumeType': 'dynamic',
|
||||
'dynamicVolume':[
|
||||
'accessMode': 'ReadWriteMany',
|
||||
'mountPath': '/opt/data',
|
||||
'size': '5Gi',
|
||||
'storageClass': ''],
|
||||
'staticVolume':[
|
||||
'accessMode': 'ReadWriteMany',
|
||||
'size': '5Gi',
|
||||
'mountPath': '/opt/data',
|
||||
'storageClass': '',
|
||||
'volumeHandle': '',
|
||||
'csiDriver': '']
|
||||
]
|
||||
bindings['hostAliases'] = bindings.hostAliases ?: false
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
bindings['nodeSelector'] = bindings.nodeSelector ?: (env.cicd_environment == 'stg' || env.cicd_environment == 'ftr') ? bindings.bu : ( env.cicd_environment == 'int' ? bindings.bu + '-int' : bindings.team )
|
||||
bindings['nodeSelectorValue'] = 'dedicated'
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
if (env.cicd_environment == 'int') {
|
||||
bindings['nodeSelector'] = bindings.nodeSelector ?: 'cloud.google.com/compute-class'
|
||||
} else {
|
||||
bindings['nodeSelector'] = bindings.nodeSelector ?: 'dedicated'
|
||||
}
|
||||
bindings['nodeSelectorValue'] = bindings.nodeSelectorValue ?: 'megatetra'
|
||||
}
|
||||
bindings['triggers'] = bindings.triggers ?: false
|
||||
bindings['host'] = bindings.host ?: false
|
||||
bindings['hosts'] = bindings.hosts ?: false
|
||||
bindings['grpc_host'] = bindings.grpc_host ?: false
|
||||
bindings['grpc_hosts'] = bindings.grpc_hosts ?: false
|
||||
bindings['serviceAccount'] = bindings.serviceAccount ?: false
|
||||
bindings['ingress_annotations'] = bindings.ingress_annotations ?: ''
|
||||
bindings['canary'] = bindings.canary ?: canary_default
|
||||
bindings['minCanaryReplicas'] = bindings.canary?.minCanaryReplicas ?: bindings.minCanaryReplicas ?: bindings.as_min
|
||||
bindings['maxCanaryReplicas'] = bindings.canary?.maxCanaryReplicas ?: bindings.maxCanaryReplicas ?: bindings.as_max
|
||||
bindings['enableManualPromotion'] = bindings.canary?.enableManualPromotion ?: bindings.enableManualPromotion ?: false
|
||||
bindings['cpu_limit'] = bindings.cpu_limit ?: bindings.cpu_request
|
||||
bindings['slowStartWindow'] = bindings.slowStartWindow ?: false
|
||||
bindings['slowStartAggression'] = bindings.slowStartAggression ?: '1'
|
||||
bindings['slowStartMinPercent'] = bindings.slowStartMinPercent ?: '10'
|
||||
bindings['lifecycle'] = bindings.lifecycle ?: false
|
||||
bindings['maxSurge'] = bindings.maxSurge ?: '50'
|
||||
bindings['as_down_pod_count'] = bindings.as_down_pod_count ?: '2'
|
||||
bindings['as_up_pod_count'] = bindings.as_up_pod_count ?: '2'
|
||||
bindings['as_up_pod_percentage'] = bindings.as_up_pod_percentage ?: '10'
|
||||
bindings['createContourGateway'] = bindings.createContourGateway ?: false
|
||||
bindings['service_annotations'] = bindings.service_annotations ?: false
|
||||
bindings['pod_annotations'] = bindings.pod_annotations ?: false
|
||||
bindings['kind'] = bindings.kind ?: 'deployment'
|
||||
bindings['statefulset'] = bindings.statefulset ?: statefulset_default
|
||||
bindings['contourResponseTimeout'] = bindings.contourResponseTimeout ?: false
|
||||
bindings['pdbMinAvailable'] = bindings.pdbMinAvailable ?: ''
|
||||
bindings['pdbMaxUnavailable'] = bindings.pdbMaxUnavailable ?: '10%'
|
||||
|
||||
// Just to keep compatibility for services which still use grpc_port
|
||||
// If someone has supplied primary_port, then it is used
|
||||
// Else we check for grpc_port, and that is used
|
||||
// If none of the above is supplied, then app_port is used just like normal flow
|
||||
bindings['primary_port'] = bindings.primary_port ?: bindings.grpc_port ?: bindings.app_port
|
||||
bindings['grpc_port'] = bindings.grpc_port ?: false
|
||||
// bindings['xmx'] = bindings.xmx ?: '50.0'
|
||||
// bindings['xms'] = bindings.xms ?: '50.0'
|
||||
bindings['enableWebsocket'] = bindings.enableWebsocket ?: false
|
||||
bindings['external_secrets_annotations'] = bindings.external_secrets_annotations ?: ''
|
||||
bindings['liveness_failure_threshold'] = bindings.liveness_failure_threshold ?: '5'
|
||||
bindings['liveness_period_seconds'] = bindings.liveness_period_seconds ?: bindings.team_norm == 'ml-platform' ? '5' : '10'
|
||||
bindings['liveness_success_threshold'] = bindings.liveness_success_threshold ?: '1'
|
||||
bindings['liveness_timeout_seconds'] = bindings.liveness_timeout_seconds ?: '2'
|
||||
bindings['readiness_failure_threshold'] = bindings.readiness_failure_threshold ?: '5'
|
||||
bindings['readiness_period_seconds'] = bindings.liveness_period_seconds ?: bindings.team_norm == 'ml-platform' ? '5' : '10'
|
||||
bindings['readiness_success_threshold'] = bindings.liveness_success_threshold ?: '1'
|
||||
bindings['readiness_timeout_seconds'] = bindings.liveness_timeout_seconds ?: '2'
|
||||
bindings['addon_ports'] = bindings.addon_ports ?: false
|
||||
|
||||
validateRequiredMetadata(bindings)
|
||||
|
||||
bindings['priority_v2'] = bindings.priority_v2 ?: 'cp3'
|
||||
bindings['primary_owner'] = bindings.primary_owner != null ? bindings.primary_owner.split('@')[0] : bindings.team_norm
|
||||
bindings['secondary_owner'] = bindings.secondary_owner != null ? bindings.secondary_owner.split('@')[0] : bindings.team_norm
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
if (bindings.otel_enabled == null) {
|
||||
bindings['otel_enabled'] = (bindings.priority_v2 == 'cp1' || bindings.priority_v2 == 'up1') ? true : false
|
||||
}
|
||||
else {
|
||||
bindings['otel_enabled'] = bindings.otel_enabled
|
||||
}
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
echo "Checking for otel value - ${bindings.otel_enabled}"
|
||||
if (bindings.otel_enabled == null) {
|
||||
bindings['otel_enabled'] = true
|
||||
}
|
||||
else {
|
||||
bindings['otel_enabled'] = bindings.otel_enabled
|
||||
}
|
||||
|
||||
// Setting metrics mode -> avaliable options: telegraf | otel | dual
|
||||
echo "Setting metrics mode - ${bindings.metrics_mode}"
|
||||
// Setting default values
|
||||
bindings['telegraf_metrics'] = false
|
||||
bindings['otel_metrics'] = false
|
||||
bindings['metrics_mode'] = bindings.metrics_mode?.toLowerCase()
|
||||
def samplerArg = bindings.otel_traces_sampler_arg
|
||||
def isValidSamplerArg = false
|
||||
if (samplerArg != null && (samplerArg instanceof Float || samplerArg instanceof Double)) {
|
||||
if (samplerArg >= 0.0 && samplerArg <= 1.0) {
|
||||
isValidSamplerArg = true
|
||||
}
|
||||
}
|
||||
bindings['otel_traces_sampler_arg'] = isValidSamplerArg ? samplerArg : '0.1'
|
||||
log.info("1 - otel_traces_sampler_arg - ${bindings.otel_traces_sampler_arg}")
|
||||
log.info("2 - ${bindings['otel_traces_sampler_arg']}")
|
||||
// Enabling metrics based on mode
|
||||
if (bindings.metrics_mode == 'telegraf') {
|
||||
bindings['telegraf_metrics'] = true
|
||||
}
|
||||
else if (bindings.metrics_mode == 'otel') {
|
||||
bindings['otel_metrics'] = true
|
||||
}
|
||||
else if (bindings.metrics_mode == 'dual') {
|
||||
bindings['telegraf_metrics'] = true
|
||||
bindings['otel_metrics'] = true
|
||||
}
|
||||
else {
|
||||
bindings['metrics_mode'] = 'telegraf'
|
||||
bindings['telegraf_metrics'] = true
|
||||
}
|
||||
}
|
||||
bindings['command'] = bindings.command
|
||||
if (bindings.command == null) {
|
||||
bindings['command'] = get_default_command(bindings['dockerBuildVersion'])
|
||||
}
|
||||
bindings['as_down_stable_window'] = bindings.as_down_stable_window ?: '1800'
|
||||
bindings['podDistributionSkew'] = bindings.podDistributionSkew ?: false
|
||||
bindings["appConfigEnabled"] = bindings.appConfigEnabled ?: false
|
||||
bindings["addHeadless"] = bindings.addHeadless?: false
|
||||
}
|
||||
|
||||
def get_value_yaml_file(def dockerBuildVersion) {
|
||||
switch (dockerBuildVersion) {
|
||||
case ~/^maven-.*/: return 'values.yaml'
|
||||
case ~/^node-.*/: return 'node-values.yaml'
|
||||
case ~/^python-.*/: return 'python-values.yaml'
|
||||
case ~/^go.*/: return 'go-values.yaml'
|
||||
case 'php': return 'php-values.yaml'
|
||||
case 'gradle': return 'values.yaml'
|
||||
}
|
||||
}
|
||||
|
||||
def get_default_command(def dockerBuildVersion) {
|
||||
switch (dockerBuildVersion) {
|
||||
case ~/^maven-.*/: return 'java'
|
||||
case ~/^node-.*/: return 'pm2-runtime'
|
||||
case ~/^go.*/: return '/app/server'
|
||||
case 'php': return 'apache2-foreground'
|
||||
case 'gradle': return 'java'
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
|
||||
def validateRequiredMetadata(def bindings) {
|
||||
def requiredParams = ['primary_owner', 'secondary_owner', 'priority_v2', 'service_type']
|
||||
def serviceOwners = ['primary_owner', 'secondary_owner']
|
||||
// Validate if required parameters are present
|
||||
for (param in requiredParams) {
|
||||
if (bindings[param] == null || bindings[param] == '') {
|
||||
env.msg = 'You have not supplied ' + param + '. Exiting the pipeline.'
|
||||
log.error(env.msg)
|
||||
sh 'exit 1'
|
||||
}
|
||||
}
|
||||
|
||||
// Validate if the owners are valid or not
|
||||
if (env.cicd_environment == 'dev' || env.cicd_environment == 'ftr' || env.cicd_environment == 'stg') {
|
||||
return
|
||||
}
|
||||
|
||||
for (param in serviceOwners) {
|
||||
final String owner = bindings[param]
|
||||
final String url = "https://pulse.meeshogcp.in/api/anonymous-User/userexist?email=${owner}"
|
||||
final def(String response, String code) = sh(returnStdout: true, script: """
|
||||
set +x
|
||||
curl -s -X GET -w '\n%{response_code}' $url
|
||||
set -x
|
||||
""").trim().tokenize('\n')
|
||||
|
||||
if (code != "200") {
|
||||
// Let's not break the pipeline in case the API fails
|
||||
log.info("Received ${code} code from Pulse while checking for user. Skipping the checks further and letting the pipeline proceed.")
|
||||
} else {
|
||||
// Check if the user exists
|
||||
def jqCommand = "echo '${response}' | jq -r '.exists'"
|
||||
def userExists = sh(returnStdout: true, script: """
|
||||
set +x
|
||||
${jqCommand}
|
||||
set -x
|
||||
""").trim()
|
||||
if (userExists != "true") {
|
||||
env.msg = "Invalid value provided in ${param}. Check if the user ${owner} exists"
|
||||
log.error(env.msg)
|
||||
sh 'exit 1'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def dependabotCriticalCheck(def repoName) {
|
||||
def repo = repoName
|
||||
|
||||
def alerts
|
||||
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_CRED}", usernameVariable:'user', passwordVariable: 'token')]) {
|
||||
validateDependabot = httpRequest httpMode: 'GET',
|
||||
customHeaders: [
|
||||
[name: 'Accept', value: 'application/vnd.github+json'],
|
||||
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
|
||||
],
|
||||
url: "https://api.github.com/repos/meesho/${repo}/dependabot/alerts?state=open&per_page=100",
|
||||
validResponseCodes: '200',
|
||||
timeout: 10
|
||||
alerts = readJSON(text: validateDependabot.content)
|
||||
|
||||
}
|
||||
|
||||
// if (!alerts) {
|
||||
// println "Failed to fetch alerts for ${repo}."
|
||||
// return false
|
||||
// }
|
||||
|
||||
// Parse the JSON response
|
||||
if (!alerts) {
|
||||
println "No alerts found for ${repo}."
|
||||
return false
|
||||
}
|
||||
|
||||
def criticalCount = 0
|
||||
alerts.each { alert ->
|
||||
def severity = alert?.security_vulnerability?.severity
|
||||
|
||||
if (severity == "critical") {
|
||||
criticalCount++
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (criticalCount > 0) {
|
||||
println "Critical vulnerabilities found in ${repo}: ${criticalCount}"
|
||||
return true // Critical vulnerabilities found
|
||||
} else {
|
||||
println "No critical vulnerabilities in ${repo}."
|
||||
return false // No critical vulnerabilities found
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.meesho.stages
|
||||
|
||||
def run(Map param){
|
||||
//get the jar for deployment, get it from the params module
|
||||
//run the ansible playbook
|
||||
//create the inventory file with given ip in parameters
|
||||
def server_ip = param.run_automation.server_ip
|
||||
def app_name = param.run_automation.app_name
|
||||
def healthcheck_api = param.run_automation.healthcheck_api
|
||||
def app_port = param.run_automation.app_port
|
||||
def repo_name = param.repo_name
|
||||
|
||||
deploy(server_ip,repo_name,app_name,healthcheck_api,app_port)
|
||||
}
|
||||
|
||||
def deploy(String server_ip, String repo_name, String app_name, String healthcheck_api, String app_port){
|
||||
try{
|
||||
stage('Deploying JAR'){
|
||||
sh "echo '$server_ip' > host_file.txt"
|
||||
echo "inventory created"
|
||||
def playbook_content = libraryResource 'com/meesho/deployJar.yaml'
|
||||
writeFile file:"deployJar.yaml", text: playbook_content
|
||||
sh(returnStatus: true, script: "ansible-playbook -i host_file.txt -u 'ubuntu' -e 'env=stage' -e 'app_name=${app_name}' -e 'repo_name=${repo_name}' -e 'healthcheck_api=${healthcheck_api}' -e 'app_port=${app_port}' deployJar.yaml -v")
|
||||
}
|
||||
}
|
||||
catch( Exception e) {
|
||||
env.msg = "Error while deploying JAR. Please check console output for more details."
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.getYamlParameter
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatterBuilder
|
||||
|
||||
def run(String repo_name, def deployment_order, def tag, def build_team, def dockerBuildVersion, String notify_channel){
|
||||
def yamlobj = new getYamlParameter()
|
||||
def applicationNames = []
|
||||
def jobStatusMap=["SUCCESS": "BUILD_STATUS_COMPLETED","FAILURE": "BUILD_STATUS_FAILED","UNSTABLE":"BUILD_STATUS_FAILED"]
|
||||
def build_user = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
|
||||
|
||||
for (deployment in deployment_order){
|
||||
def value_binding = yamlobj.getParam("${repo_name}/deployments","${deployment}.yaml")
|
||||
applicationNames.add(value_binding['app_name'])
|
||||
}
|
||||
def end_time = getDateTime()
|
||||
def working_env = (env.CLOUD_PROVIDER == "GCP")? "gcp_${env.cicd_environment}" : env.cicd_environment
|
||||
|
||||
def jsonMap = [:]
|
||||
jsonMap["hot_fix"] = env.hot_fix ? true : false
|
||||
jsonMap["job_name"] = env.JOB_NAME ? env.JOB_NAME.split('/')[0] : "unknown"
|
||||
jsonMap["build_no"] = env.BUILD_NUMBER
|
||||
jsonMap["image"] = tag
|
||||
jsonMap["applications"] = applicationNames
|
||||
jsonMap["job_status"] = jobStatusMap[currentBuild?.currentResult]
|
||||
jsonMap["err_msg"] = env.error_msg_to_db
|
||||
jsonMap["end_time"] = end_time
|
||||
jsonMap["email"] = currentBuild?.rawBuild?.getCause(Cause.UserIdCause)?.getUserId()
|
||||
jsonMap["start_time"] = env.STARTTIME
|
||||
jsonMap["build_team"] = build_team
|
||||
jsonMap["docker_build_version"] = dockerBuildVersion
|
||||
jsonMap["notify_channel"] = notify_channel
|
||||
jsonMap["branch_name"] = env.CHANGE_ID ? env.CHANGE_BRANCH : env.BRANCH_NAME
|
||||
jsonMap["commit_id"] = env.commit_id
|
||||
jsonMap["deploy_argo"] = env.deployArgo != null ? env.deployArgo.toBoolean() : false
|
||||
jsonMap["pr_number"] = env.CHANGE_ID ? env.CHANGE_ID.toInteger() : 0
|
||||
|
||||
final String baseUrl
|
||||
|
||||
switch (env.cicd_environment) {
|
||||
case 'prd':
|
||||
case 'int':
|
||||
baseUrl = 'https://ringmaster-api.meeshogcp.in/api/v1/key/cicd/cd/update'
|
||||
break
|
||||
default:
|
||||
baseUrl = 'https://ringmaster-api.admin.meeshogcp.in/api/v1/key/cicd/cd/update'
|
||||
}
|
||||
final String url = "${baseUrl}?workingEnv=${working_env}"
|
||||
final String header = "Content-Type: application/json"
|
||||
final String jsonData = writeJSON returnText: true, json: jsonMap
|
||||
|
||||
|
||||
if (build_user == "ringmaster-bot"){
|
||||
callApi(url, header, jsonData)
|
||||
} else{
|
||||
def newCICD_Payload = [:]
|
||||
newCICD_Payload["repo_name"] = repo_name
|
||||
newCICD_Payload["source_branch"] = env.CHANGE_ID ? env.CHANGE_BRANCH : env.BRANCH_NAME
|
||||
newCICD_Payload["pull_request_number"] = env.CHANGE_ID ? env.CHANGE_ID.toInteger() : 0
|
||||
newCICD_Payload["env"] = env.cicd_environment
|
||||
newCICD_Payload["job_name"] = env.JOB_NAME ? env.JOB_NAME.split('/')[0] : "UNKNOWN"
|
||||
newCICD_Payload["sub_job_name"] = env.JOB_NAME ? env.JOB_NAME.split('/')[1] : "UNKNOWN"
|
||||
newCICD_Payload["build_number"] = env.BUILD_NUMBER.toInteger()
|
||||
newCICD_Payload["image_tag"] = tag
|
||||
newCICD_Payload["build_detailed_error"] = env.error_msg_to_db
|
||||
switch (env.cicd_environment) {
|
||||
case 'prd':
|
||||
case 'int':
|
||||
cicdBaseUrl = 'http://turbo-turtle.meeshogcp.in'
|
||||
break
|
||||
default:
|
||||
cicdBaseUrl = 'http://turbo-turtle.admin.meeshogcp.in'
|
||||
}
|
||||
final String newCICD_JSON = writeJSON returnText: true, json: newCICD_Payload
|
||||
//log.info("New CICD JSON - ${newCICD_JSON}")
|
||||
final String newCICD_URL = cicdBaseUrl + "/api/v1/ci/jenkins/callback"
|
||||
final String newCICD_Header = "Content-Type: application/json"
|
||||
// Use a temporary file to store the JSON payload
|
||||
// This avoids shell quoting issues completely
|
||||
final String jsonFilePath = "cicd_payload_${env.BUILD_NUMBER}_${System.currentTimeMillis()}.json"
|
||||
|
||||
try {
|
||||
// 1. Write the JSON payload to a temporary file
|
||||
// The writeJSON step ensures the content is valid JSON, escaping internal characters
|
||||
writeFile(file: jsonFilePath, text: writeJSON(returnText: true, json: newCICD_Payload))
|
||||
final String newCICD_JSON_log = readFile(file: jsonFilePath)
|
||||
log.info("New CICD JSON (from file) - ${newCICD_JSON_log.take(500)}...") // Log a snippet
|
||||
final def(String response, String code) = sh(
|
||||
returnStdout: true,
|
||||
script: """
|
||||
curl -s -X POST \\
|
||||
-H '$newCICD_Header' \\
|
||||
-w '\\n%{response_code}' \\
|
||||
$newCICD_URL \\
|
||||
-d @$jsonFilePath
|
||||
"""
|
||||
).trim().tokenize("\n")
|
||||
|
||||
if (code != "200") {
|
||||
log.error("CICD Application API call failed with error code - ${code}, response - ${response}")
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("CICD Application API call failed - " + "Error: " + e.toString())
|
||||
throw e
|
||||
} finally {
|
||||
sh(script: "rm -f ${jsonFilePath}", returnStatus: true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def callApi(String url, String header, String jsonData){
|
||||
try{
|
||||
withCredentials([usernamePassword(credentialsId: "ringmaster-token", usernameVariable:'user', passwordVariable: 'token')]){
|
||||
final def(String response, String code) = sh(returnStdout: true, script: "curl -s -X POST -H '$header' -H 'Authorization: $token' -w '\\n%{response_code}' $url -d '$jsonData'").trim().tokenize("\n")
|
||||
log.info("HTTP response status code : ${code}")
|
||||
if(code != "200"){
|
||||
log.error("API call failed with error code - ${code}, response - ${response}")
|
||||
currentBuild.result = 'FAILURE'
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception e) {
|
||||
log.error("API call failed")
|
||||
currentBuild.result = 'FAILURE'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
@NonCPS
|
||||
def getDateTime() {
|
||||
// Get the current date and time in IST
|
||||
def currentDateTime = ZonedDateTime.now()
|
||||
// Create a formatter for the desired pattern
|
||||
def formatter = new DateTimeFormatterBuilder()
|
||||
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
|
||||
.appendOffset("+HH:mm", "+00:00")
|
||||
.toFormatter()
|
||||
// Format the current date and time using the formatter
|
||||
def formattedDateTime = currentDateTime.format(formatter)
|
||||
return formattedDateTime;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.gitActions
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.stages.multiBranchPipeline
|
||||
|
||||
def run(Map params) {
|
||||
def btObj = new buTeamMapping()
|
||||
def gitObj = new gitActions()
|
||||
|
||||
def environments = ['stg':'develop', 'int':'pre-prod', 'prd':'main', 'ftr':'feature']
|
||||
final Map<?, ?> modifiedParams = new HashMap<>(params)
|
||||
|
||||
// def helm_repo_name = 'devops-helm-charts'
|
||||
// def argoRepo = "devops-argo-config"
|
||||
|
||||
def deployment_order = modifiedParams.app_names.replaceAll('\\s', '').split(', ') as List
|
||||
|
||||
modifiedParams['deployment_order'] = deployment_order
|
||||
|
||||
stage('Create Jenkinsfile') {
|
||||
jenkinsfileCreate(modifiedParams)
|
||||
}
|
||||
|
||||
modifiedParams['bu'] = btObj.get_bu_initials(modifiedParams['bu'])
|
||||
modifiedParams['team'] = btObj.get_team_initials(modifiedParams['team'])
|
||||
log.info(modifiedParams)
|
||||
|
||||
stage('Update Helm charts') {
|
||||
gitObj.clone("${WORKSPACE}", "${env.helm_repo_name}", null)
|
||||
environments.each {
|
||||
modifiedParams['environment'] = it.key
|
||||
def helm_branch_name = it.value
|
||||
for (deployment in deployment_order) {
|
||||
modifiedParams['app_name'] = deployment
|
||||
modifiedParams['host'] = helm_branch_name == 'feature' ? "INGRESS_PR_NUMBER-${deployment}.dev.internal.meeshotest.in" : "${deployment}.${it.key}.internal.meeshotest.in"
|
||||
modifiedParams['host'] = (helm_branch_name == 'pre-prod') ? "${deployment}.${modifiedParams.bu}.internal.meesho.co" : modifiedParams.host
|
||||
//If branch is main, then assuming the env as prod
|
||||
//Making nodeSelector changes to hypercore or hypermem & based on arch, so that it moves to common node pool
|
||||
if (helm_branch_name == 'main') {
|
||||
def cpu = modifiedParams['cpu_request']
|
||||
def memory = modifiedParams['memory_request']
|
||||
def nodeSelector = 'hypercore'
|
||||
|
||||
if (cpu.contains('m')) {
|
||||
def numericValue = cpu.replaceAll('\\D+', '').toDouble()
|
||||
def gb = numericValue / 1000
|
||||
cpu = gb.toString()
|
||||
}
|
||||
def mem_dgt = memory.replaceAll('\\D+', '').toDouble()
|
||||
memory = memory.contains('Mi') ? mem_dgt / 1024 : mem_dgt
|
||||
def ratio = cpu.toDouble() / memory.toDouble()
|
||||
def arch = modifiedParams['arch']
|
||||
def graviton_required = false
|
||||
if (arch == 'arm64') {
|
||||
graviton_required = true
|
||||
}
|
||||
if (ratio <= 1 / 3) {
|
||||
if (graviton_required) {
|
||||
nodeSelector = 'hypermem-arm64'
|
||||
} else {
|
||||
nodeSelector = 'hypermem'
|
||||
}
|
||||
} else {
|
||||
if (graviton_required) {
|
||||
nodeSelector = 'hypercore-arm64'
|
||||
} else {
|
||||
nodeSelector = 'hypercore'
|
||||
}
|
||||
}
|
||||
modifiedParams['nodeSelector'] = nodeSelector
|
||||
}
|
||||
updateHelmRepo(modifiedParams, env.helm_repo_name, helm_branch_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stage("Update Argo Application"){
|
||||
// gitObj.clone("${WORKSPACE}", "${argoRepo}", null)
|
||||
// environments.each{
|
||||
// modifiedParams["environment"] = it.key
|
||||
// def argo_branch_name = it.value
|
||||
// for (deployment in deployment_order){
|
||||
// modifiedParams["app_name"] = deployment
|
||||
// updateArgoRepo(modifiedParams,argoRepo,argo_branch_name)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
stage('Create ECR repo') {
|
||||
def buildDockerObj = new getDockerParams()
|
||||
def modules = buildDockerObj.getModules(modifiedParams['repo_name'])
|
||||
if (modules == null) {
|
||||
modules = ['module_less']
|
||||
}
|
||||
for (module in modules) {
|
||||
def ecr_repo_name = (module == 'module_less') ? "${modifiedParams.team}/${modifiedParams.repo_name.toLowerCase()}" : "${modifiedParams.team}/${modifiedParams.repo_name.toLowerCase()}/${module}"
|
||||
try {
|
||||
sh "aws ecr create-repository --repository-name ${ecr_repo_name}"
|
||||
}
|
||||
catch (Exceptione) {
|
||||
log.info('repository already present')
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Create Multibranch pipeline') {
|
||||
def multiBranchPipelineObj = new multiBranchPipeline()
|
||||
multiBranchPipelineObj.applicationOnboard(params['bu'], params['repo_name'])
|
||||
}
|
||||
}
|
||||
|
||||
def jenkinsfileCreate(Map config) {
|
||||
def constructObj = new constructTemplate()
|
||||
def gitObj = new gitActions()
|
||||
def repo_name = config.repo_name
|
||||
def deployment_order = config.deployment_order
|
||||
def repo_branch_name = 'eks_onboarding'
|
||||
config['branch_params'] = ''
|
||||
config['excludedMoudles'] = config.excludedMoudles.replaceAll('\\s', '').split(', ') as List
|
||||
gitObj.clone("${WORKSPACE}", "${config.repo_name}", null)
|
||||
gitObj.branchCheckOut(config.repo_name, repo_branch_name)
|
||||
deployment_yaml_file = get_deployment_yaml_file(config['dockerBuildVersion'])
|
||||
dir(repo_name) {
|
||||
sh(script:'mkdir -p deployments/')
|
||||
sh 'chmod -R 777 .'
|
||||
constructObj.renderTemplate(config, 'Jenkinsfile', 'Jenkinsfile')
|
||||
gitObj.add('.', 'Jenkinsfile')
|
||||
|
||||
constructObj.renderTemplate(config, 'config.yaml', 'config.yaml')
|
||||
gitObj.add('.', 'config.yaml')
|
||||
|
||||
dir('deployments') {
|
||||
for (deployment in deployment_order) {
|
||||
config['app_name'] = deployment
|
||||
constructObj.renderTemplate(config, deployment_yaml_file, deployment + '.yaml')
|
||||
gitObj.add('.', deployment + '.yaml')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gitObj.codeCommit(repo_name, repo_branch_name, 'Generating build and deployments files')
|
||||
gitObj.codePush(repo_name, repo_branch_name)
|
||||
}
|
||||
|
||||
def updateHelmRepo(Map config, String helm_repo_name, String helm_branch_name) {
|
||||
def constructObj = new constructTemplate()
|
||||
def gitObj = new gitActions()
|
||||
def filepath = "${env.helmChartsPath}/${config.bu}/${config.team}/${config.app_name}"
|
||||
def file_name = 'values_properties.yaml'
|
||||
def app_branch = config.app_name + '-' + helm_branch_name + '-helm'
|
||||
def pr_num = ''
|
||||
def commit_status = 0
|
||||
|
||||
gitObj.branchCheckOut(env.helm_repo_name, helm_branch_name)
|
||||
gitObj.branchCheckOut("${env.helm_repo_name}", "${app_branch}")
|
||||
// create filepath
|
||||
dir(env.helm_repo_name) {
|
||||
sh(script:"mkdir -p ${filepath}" ,returnStdout:true)
|
||||
sh 'chmod -R 777 .'
|
||||
constructObj.renderTemplate(config, file_name, filepath + '/' + file_name)
|
||||
}
|
||||
|
||||
// git commit and push
|
||||
gitObj.add(env.helm_repo_name, filepath + '/' + file_name)
|
||||
commit_status = gitObj.codeCommit(env.helm_repo_name, app_branch, 'Generating properties values yaml file')
|
||||
if (commit_status == 0) {
|
||||
gitObj.codePush(env.helm_repo_name, app_branch)
|
||||
pr_num = gitObj.createPR(config.app_name, env.helm_repo_name, helm_branch_name, app_branch, 'Merge helm values properties')
|
||||
gitObj.mergePR(env.helm_repo_name, pr_num, app_branch)
|
||||
gitObj.deleteBranch(env.helm_repo_name, helm_branch_name, app_branch)
|
||||
}
|
||||
}
|
||||
|
||||
def get_deployment_yaml_file(def dockerBuildVersion) {
|
||||
switch(dockerBuildVersion) {
|
||||
case ~/^maven-.*/: return 'deployment.yaml'
|
||||
case ~/^node-.*/: return 'node-deployment.yaml'
|
||||
case ~/^python-.*/: return 'python-deployment.yaml'
|
||||
case ~/^go.*/: return 'go-deployment.yaml'
|
||||
case 'gradle': return 'gradle-deployment.yaml'
|
||||
case 'php': return 'php-deployment.yaml'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.meesho.stages
|
||||
|
||||
def run(String repo_name){
|
||||
stage(stageName("Check for Hot Fix")){
|
||||
dir(repo_name){
|
||||
if (env.CHANGE_ID) {
|
||||
def source_branch_name = env.CHANGE_BRANCH
|
||||
log.info("Source-Branch : ${source_branch_name}")
|
||||
source_branch_name = source_branch_name.toLowerCase()
|
||||
if (source_branch_name.contains("hotfix_")){
|
||||
env.hot_fix = true
|
||||
log.info("***************** Enabling Hot-fix workflow *****************")
|
||||
}
|
||||
else if (source_branch_name.matches('^revert-\\d+-.+$')){
|
||||
env.hot_fix = true
|
||||
log.info("***************** Enabling Hot-fix workflow for revert branch *****************")
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info("**** Branch: ${env.BRANCH_NAME}, So Skipping Hot-fix check ****")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import jxl.*
|
||||
import hudson.util.PersistedList
|
||||
import jenkins.model.Jenkins
|
||||
import jenkins.branch.*
|
||||
import jenkins.plugins.git.*
|
||||
import org.jenkinsci.plugins.workflow.multibranch.*
|
||||
|
||||
import com.cloudbees.hudson.plugins.folder.*
|
||||
import org.jenkinsci.plugins.github_branch_source.*
|
||||
import org.jenkinsci.plugins.workflow.libs.*
|
||||
import hudson.scm.SCM
|
||||
import hudson.plugins.git.*
|
||||
import net.gleske.scmfilter.impl.trait.*
|
||||
|
||||
def applicationOnboard(String foldername, String repo_name) {
|
||||
// Bring some values in from ansible using the jenkins_script modules wierd "args" approach (these are not gstrings)
|
||||
String folderName = "${foldername}"
|
||||
String repoName = "${repo_name}"
|
||||
String scriptPath = "Jenkinsfile"
|
||||
String gitRepo = "https://github.com/Meesho/${repo_name}.git"
|
||||
String mBPName = "${repo_name}-cicd"
|
||||
String credentialsId = env.GITHUB_CRED
|
||||
|
||||
Jenkins jenkins = Jenkins.instance // saves some typing
|
||||
|
||||
// Get the folder where this job should be
|
||||
// def folder = jenkins.getItem(folderName)
|
||||
// //Create the folder if it doesn't exist
|
||||
// if (folder == null) {
|
||||
// folder = jenkins.createProject(Folder.class, folderName)
|
||||
// }
|
||||
|
||||
// Multibranch creation/update
|
||||
WorkflowMultiBranchProject mbp
|
||||
def view = jenkins.getView(foldername)
|
||||
Item item = jenkins.getItem(mBPName)
|
||||
if ( item != null ) {
|
||||
// Update case
|
||||
mbp = (WorkflowMultiBranchProject) item
|
||||
} else {
|
||||
// Create case
|
||||
mbp = jenkins.createProject(WorkflowMultiBranchProject.class, mBPName)
|
||||
}
|
||||
|
||||
// Configure the script this MBP uses
|
||||
mbp.getProjectFactory().setScriptPath(scriptPath)
|
||||
|
||||
def implicit = false
|
||||
def defaultVersion = "master"
|
||||
def traits = []
|
||||
|
||||
GitHubSCMSource gitHubSCMSource = new GitHubSCMSource("Meesho", repoName, gitRepo, implicit)
|
||||
gitHubSCMSource.credentialsId = credentialsId
|
||||
|
||||
BranchDiscoveryTrait branchDiscoveryTrait = new BranchDiscoveryTrait(3)
|
||||
OriginPullRequestDiscoveryTrait pullRequestTrait = new OriginPullRequestDiscoveryTrait(1)
|
||||
WildcardSCMHeadFilterTrait wildcardSCMHeadFilterTrait = new WildcardSCMHeadFilterTrait('gcp-main*','','','*')
|
||||
traits.add(branchDiscoveryTrait)
|
||||
traits.add(pullRequestTrait)
|
||||
traits.add(wildcardSCMHeadFilterTrait)
|
||||
gitHubSCMSource.setTraits(traits)
|
||||
BranchSource branchSource = new BranchSource(gitHubSCMSource)
|
||||
NoTriggerBranchProperty noTriggerBranchProperty = new NoTriggerBranchProperty()
|
||||
BranchProperty[] ntbp = [noTriggerBranchProperty]
|
||||
branchSource.setStrategy(new DefaultBranchPropertyStrategy(ntbp))
|
||||
|
||||
PersistedList sources = mbp.getSourcesList()
|
||||
sources.clear()
|
||||
sources.add(branchSource)
|
||||
view.add(mbp)
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import hudson.Util
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.stages.deployRingmaster
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
|
||||
def run(Map config) {
|
||||
def maintainer = config.maintainer
|
||||
def skip_notify = config.skip_notify ?: false
|
||||
def notify_channel = config.notify_channel && config.notify_channel != '' ? config.notify_channel : 'ci-cd-status'
|
||||
def build_user = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
|
||||
def COLOR_MAP = ['SUCCESS':'good', 'FAILURE':'danger']
|
||||
def build_duration = Util.getTimeSpanString(System.currentTimeMillis() - currentBuild.startTimeInMillis)
|
||||
stage(stageName('Sending notification')) {
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
log.info("Toolchain environment detected. Sending signal...")
|
||||
def dkrobj = new getDockerParams()
|
||||
def commit_id=dkrobj.getCommitid(config.repo_name)
|
||||
log.info("Toolchain environment detected. Sending signal...")
|
||||
def btObj = new buTeamMapping()
|
||||
def team_initial = btObj.get_team_initials(config.team)
|
||||
def isNodeBuild = (config.dockerBuildVersion?.toString()?.toLowerCase()?.startsWith('node-'))
|
||||
def image_path="${env.cicd_environment}/${team_initial}/${config.repo_name}".toLowerCase()
|
||||
if (env.TOOLCHAIN_ENV && isNodeBuild) {
|
||||
image_path = "${env.cicd_environment}/${env.TOOLCHAIN_ENV}/${team_initial}/${config.repo_name}".toLowerCase()
|
||||
log.info("Toolchain: Node build detected, using TOOLCHAIN_ENV-aware image_path: ${image_path}")
|
||||
}
|
||||
else {
|
||||
image_path = "${env.cicd_environment}/${team_initial}/${config.repo_name}".toLowerCase()
|
||||
log.info("Toolchain: using default image_path (no TOOLCHAIN_ENV segment): ${image_path}")
|
||||
}
|
||||
def modules_to_notify = config.modules ?: ""
|
||||
def imageList = []
|
||||
if (modules_to_notify != "") {
|
||||
imageList = modules_to_notify.collect { module ->
|
||||
def moduleName = (module instanceof Map) ? module.keySet()[0] : module.toString()
|
||||
"${env.registry}/${image_path}/${moduleName}:${env.TAG}"
|
||||
}
|
||||
} else {
|
||||
imageList = ["${env.registry}/${image_path}:${env.TAG}"]
|
||||
}
|
||||
def payload = [
|
||||
"repo_name": config.repo_name,
|
||||
"build_number": env.BUILD_NUMBER,
|
||||
"build_status": currentBuild.currentResult,
|
||||
"image_path": image_path,
|
||||
"image_tag": env.TAG,
|
||||
"commit_id": commit_id,
|
||||
"imageList": imageList.join(',')
|
||||
]
|
||||
|
||||
def jsonPayload = writeJSON(returnText: true, json: payload)
|
||||
|
||||
try {
|
||||
sh """
|
||||
curl -k --insecure -X POST -H "Content-Type: application/json" \
|
||||
-d '${jsonPayload}' \
|
||||
http://172.23.72.116:5002/api/v1/deploy/build-callback
|
||||
"""
|
||||
log.info("Toolchain signal sent successfully.")
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send Toolchain signal: ${e.toString()}")
|
||||
}
|
||||
return
|
||||
}
|
||||
if (build_user == "ringmaster-bot" || build_user == "turbo-turtle") {
|
||||
def ringmaster_obj = new deployRingmaster()
|
||||
def btObj = new buTeamMapping()
|
||||
def team = btObj.get_team_initials(config.team)
|
||||
ringmaster_obj.run(config.repo_name, config.deployment_order, env.TAG, team, config.dockerBuildVersion, notify_channel)
|
||||
if(env.cicd_environment == "prd"){
|
||||
slackSend color:COLOR_MAP[currentBuild.currentResult], channel:notify_channel, message: "[*${currentBuild.currentResult}*]\n Repo Name - ${config.repo_name}\n maintainer - @${maintainer}\n Time Taken - ${build_duration}\n Build logs - <${BUILD_URL}/console|Open URL>\n TAG for CD - ```${env.TAG}``` Job Message - ```${env.msg}```\n Deploy Applications - <https://ringmaster.meeshogcp.in/applications/cicd/repo/${config.repo_name}/builds|deploy URL> "
|
||||
}
|
||||
skip_notify = true
|
||||
}
|
||||
if (skip_notify.toBoolean()) {
|
||||
echo "${config.skip_notify} ${skip_notify}"
|
||||
log.info('Skipping - Slack Notification.')
|
||||
}
|
||||
else {
|
||||
slackSend color:COLOR_MAP[currentBuild.currentResult], channel:notify_channel, message: "[*${currentBuild.currentResult}*]\n Job Name - <${JOB_URL}|${JOB_NAME}>\n Build Number - <${BUILD_URL}|#${BUILD_NUMBER}>\n Started by - @${maintainer}\n Time Taken - ${build_duration}\n Console Output - <${BUILD_URL}/console|Open URL>\n TAG for CD - ```${env.TAG}``` Job Message - ```${env.msg}```"
|
||||
}
|
||||
|
||||
if (env.BRANCH_NAME ==~ /(gcp-main|main|gcp-master|master|farmiso-main)/) {
|
||||
postTrackingApi(config)
|
||||
if (env.SERVICES != null && (build_user != "ringmaster-bot" || build_user != "turbo-turtle")) {
|
||||
log.info('Updating Ringmaster deployment history db')
|
||||
postTrackingRingmasterApi(config)
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info('Skipping - Updating in Deployment Tracker.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def postTrackingRingmasterApi(Map config){
|
||||
log.info('Updating Deployment Details in Ringmaster DB')
|
||||
final String baseUrl
|
||||
switch (env.cicd_environment) {
|
||||
case 'prd':
|
||||
case 'int':
|
||||
baseUrl = 'https://ringmaster-api.admin.meeshogcp.in/api/v1/key/update/deployment-history'
|
||||
break
|
||||
default:
|
||||
baseUrl = 'https://ringmaster-api.admin.meeshogcp.in/api/v1/key/update/deployment-history'
|
||||
}
|
||||
def working_env = "gcp_${env.cicd_environment}"
|
||||
final String url = "${baseUrl}?workingEnv=${working_env}"
|
||||
final String jsonData = getRingmasterJsonData(config)
|
||||
callRingmasterApi(url, jsonData)
|
||||
}
|
||||
|
||||
def callRingmasterApi(String url, String jsonData) {
|
||||
try {
|
||||
withCredentials([usernamePassword(credentialsId: "ringmaster-token", usernameVariable: 'user', passwordVariable: 'token')]) {
|
||||
def response = sh(
|
||||
script: """
|
||||
curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: $token" \
|
||||
-d '${jsonData}' \
|
||||
${url}
|
||||
""",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
|
||||
log.info("API call response: ${response}")
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("API call failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
def getRingmasterJsonData(Map config) {
|
||||
def dkrobj = new getDockerParams()
|
||||
def jsonMap = [:]
|
||||
|
||||
jsonMap['repository'] = config.repo_name
|
||||
jsonMap['team'] = config.team
|
||||
jsonMap['link'] = env.BUILD_URL
|
||||
jsonMap['cd_job'] = env.JOB_NAME
|
||||
jsonMap['cd_id'] = env.BUILD_NUMBER
|
||||
jsonMap['initiator'] = currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId()
|
||||
jsonMap['tag'] = env.TAG
|
||||
jsonMap['commit_id'] = dkrobj.getCommitid(config.repo_name)
|
||||
jsonMap['services'] = env.SERVICES ? env.SERVICES.tokenize(',[] ') : []
|
||||
jsonMap['status'] = currentBuild.currentResult == 'FAILURE' ? 'FAIL' : currentBuild.currentResult
|
||||
jsonMap['error_msg'] = env.error_msg_to_db
|
||||
jsonMap['start_time'] = env.deploymentStartTime
|
||||
jsonMap['end_time'] = env.deploymentEndTime
|
||||
jsonMap['working_env'] = "gcp_${env.cicd_environment}"
|
||||
|
||||
def jsonString = writeJSON(returnText: true, json: jsonMap)
|
||||
return jsonString
|
||||
}
|
||||
|
||||
def postTrackingApi(Map config) {
|
||||
final String host = ''
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
host = 'http://deployment-tracker.meeshoint.in'
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
host = 'http://deployment-tracker.prd.meesho.int'
|
||||
}
|
||||
final String path = '/api/1.0/deployment-tracker/jenkins/create'
|
||||
final String url = "${host}${path}"
|
||||
final String header = 'Content-Type: application/json'
|
||||
final String jsonData = getJsonData(config)
|
||||
|
||||
try {
|
||||
echo "Deployment Tracker URL - ${url}"
|
||||
final def(String response, String code) = sh(returnStdout: true, script: "curl -s -X POST -H '$header' -w '\\n%{response_code}' $url -d '$jsonData'").trim().tokenize('\n')
|
||||
log.info("HTTP response status code : ${code}")
|
||||
if (code != '200') {
|
||||
log.error("API call failed with error code - ${code}")
|
||||
}
|
||||
}
|
||||
catch ( Exception e) {
|
||||
log.error('API call failed')
|
||||
}
|
||||
}
|
||||
|
||||
def getJsonData(Map config) {
|
||||
def dkrobj = new getDockerParams()
|
||||
def build_status_map = ["FAILURE":"FAIL", "SUCCESS":"SUCCESS", "UNSTABLE":"SUCCESS"]
|
||||
def jsonMap = [:]
|
||||
jsonMap['repository'] = config.repo_name
|
||||
jsonMap['team'] = config.team
|
||||
jsonMap['link'] = env.BUILD_URL
|
||||
jsonMap['cd_job'] = env.JOB_NAME
|
||||
jsonMap['cd_id'] = env.BUILD_NUMBER
|
||||
jsonMap['initiator'] = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
|
||||
jsonMap['tag'] = env.TAG
|
||||
jsonMap['commit_id'] = dkrobj.getCommitid(config.repo_name)
|
||||
jsonMap['services'] = env.SERVICES ? env.SERVICES.tokenize(',[] ') : null
|
||||
jsonMap['status'] = currentBuild.currentResult == env.FAILURE ? 'FAIL' : currentBuild.currentResult
|
||||
jsonMap['error_msg'] = env.error_msg_to_db
|
||||
|
||||
def jsonString = writeJSON returnText: true, json: jsonMap
|
||||
return jsonString
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.meesho.stages
|
||||
|
||||
def run(Map config) {
|
||||
try {
|
||||
def repo_name = config.repo_name
|
||||
stage('Security scan') {
|
||||
if (config.skip_security_scan) {
|
||||
log.info('Skipping - Security Scan')
|
||||
}
|
||||
else {
|
||||
final String url = '172.31.5.29:63232/scans'
|
||||
final def(String response, String code) = sh(returnStdout: true, script: "curl -s -X POST -H 'Content-Type: application/json' -w '\\n%{response_code}' $url -d '{\"reponame\":\"$repo_name\",\"branch\":\"$BRANCH_NAME\"}'").trim().tokenize('\n')
|
||||
log.info("HTTP response status code : ${code}")
|
||||
log.info("Response: ${response}")
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception e) {
|
||||
env.msg = 'failed in security scan . Please check console output for more details.'
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.meesho.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
|
||||
def run(String bu, String team,String module){
|
||||
stage("Validate BU and Team"){
|
||||
def vObj = new buTeamMapping()
|
||||
if (vObj.validate(bu,team)){
|
||||
log.info("Correct team and BU values")
|
||||
}
|
||||
else{
|
||||
error "Incorrect BU and team values provided"
|
||||
}
|
||||
if(module == ""){
|
||||
error "Module can't be empty. if there is no module, Please provide the parameter value as module_less"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def create() {
|
||||
withCredentials([file(credentialsId: 'ssh-private-key', variable: 'FILE')]) {
|
||||
sh """
|
||||
cat ${FILE} > ./id_github_jenkins
|
||||
chmod 600 ./id_github_jenkins
|
||||
|
||||
# Ensure .ssh directory has correct permissions
|
||||
chmod 700 /root/.ssh
|
||||
|
||||
# Fix SSH config file permissions if it exists
|
||||
if [ -f /root/.ssh/config ]; then
|
||||
chmod 600 /root/.ssh/config
|
||||
chown root:root /root/.ssh/config
|
||||
fi
|
||||
|
||||
# Fix existing SSH private key permissions if it exists
|
||||
if [ -f /root/.ssh/id_rsa ]; then
|
||||
chmod 600 /root/.ssh/id_rsa
|
||||
chown root:root /root/.ssh/id_rsa
|
||||
fi
|
||||
|
||||
# Fix any other SSH key files that might exist
|
||||
find /root/.ssh -type f -name "id_*" -exec chmod 600 {} \\; 2>/dev/null || true
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Purpose: Utility function to return BU and their respective teams
|
||||
Author: Avinash kumar Lodhi
|
||||
*/
|
||||
package com.meesho.utilities
|
||||
|
||||
def validate(String bu, String team) {
|
||||
def bu_team_map = ['supply':['supplier-ads', 'supplier-ads-frontend', 'experience', 'fulfilment', 'fulfilment-frontend','financial-services', 'cataloging', 'cataloging-frontend', 'payout', 'payout-frontend', 'supplier-acquisition-activation', 'supplier-service', 'returns', 'supply-shared', 'display-ads', 'offers','transact', 'supplier-live-commerce'],
|
||||
'demand':['comms-platform', 'live-commerce', 'shopping-platform', 'product-feed', 'search', 'product-meta', 'user-growth', 'web', 'transact', 'communications', 'discovery-platform', 'offers', 'android-platform', 'ios', 'demand-shared', 'discovery-ranking'],
|
||||
'farmiso':['farmiso'],
|
||||
'admin':['devops'],
|
||||
'central':['shared', 'devops', 'psec', 'dbe'],
|
||||
'dataengg':['data-platform', 'dataengg-shared', 'data-intelligence', 'data-platform-consumption', 'data-platform-ingestion', 'data-platform-nrt', 'data-platform-prism-frmw', 'data-platform-experimentation'],
|
||||
'datascience':['data-science', 'ml-platform', 'for-you', 'recommendation', 'catalog-listing-page', 'search', 'advertisement', 'explore', 'pricing', 'product-match', 'catalog-taxonomy', 'brand-infringment', 'fds', 'return-reimbursements', 'fullfilment', 'ugc-moderation-analysis', 'home-page', 'core', 'usergrowth', 'demand-forecast', 'catalog-qc'],
|
||||
'mcache':['mcache', 'mcache-shared', 'supplier-service'],
|
||||
'infra':['devops', 'dbe']
|
||||
]
|
||||
if (bu == null || team == null) {
|
||||
return null
|
||||
}
|
||||
return bu_team_map[bu].contains(team)
|
||||
}
|
||||
|
||||
def get_initials(String targetMap, String targetString) {
|
||||
def bu_initials = ['supply':'supl',
|
||||
'demand':'dmnd',
|
||||
'farmiso':'farm',
|
||||
'admin':'admn',
|
||||
'central':'cntr',
|
||||
'dataengg':'deng',
|
||||
'datascience':'dsci',
|
||||
'mcache':'mche',
|
||||
'infra':'infr'
|
||||
]
|
||||
def team_initials = ['supplier-ads':'ads',
|
||||
'comms-platform': 'cplat',
|
||||
'supplier-ads-frontend':'fads',
|
||||
'experience':'xp',
|
||||
'fulfilment':'fnf',
|
||||
'fulfilment-frontend':'ffnf',
|
||||
'financial-services':'fsvc',
|
||||
'cataloging':'ctlng',
|
||||
'cataloging-frontend':'fctlg',
|
||||
'payout':'pay',
|
||||
'payout-frontend':'fpay',
|
||||
'supplier-acquisition-activation':'saa',
|
||||
'supplier-service':'ssvc',
|
||||
'seller-services': 'sis',
|
||||
'live-commerce':'lcom',
|
||||
'shopping-platform':'splat',
|
||||
'product-feed':'pfeed',
|
||||
'search':'srch',
|
||||
'product-meta':'pmeta',
|
||||
'user-growth':'grwth',
|
||||
'web':'web',
|
||||
'transact':'trnst',
|
||||
'communications':'comms',
|
||||
'discovery-platform':'dplat',
|
||||
'farmiso':'farm',
|
||||
'devops':'devop',
|
||||
'offers':'offer',
|
||||
'returns':'retrn',
|
||||
'android-platform':'andrd',
|
||||
'ios':'ios',
|
||||
'shared':'xcntr',
|
||||
'supply-shared':'xsupl',
|
||||
'demand-shared':'xdmnd',
|
||||
'data-platform':'dp',
|
||||
'data-science':'ds',
|
||||
'ml-platform':'ml',
|
||||
'dataengg-shared':'xdeng',
|
||||
'datascience-shared':'xdsci',
|
||||
'data-intelligence':'di',
|
||||
'recommendation':'rcmnd',
|
||||
'catalog-listing-page':'ctllp',
|
||||
'advertisement':'adv',
|
||||
'explore':'explr',
|
||||
'pricing':'price',
|
||||
'product-match':'patch',
|
||||
'catalog-taxonomy':'ctltx',
|
||||
'brand-infringment':'brndi',
|
||||
'fds':'fds',
|
||||
'return-reimbursements':'retrr',
|
||||
'fullfilment':'flfmt',
|
||||
'ugc-moderation-analysis':'umdra',
|
||||
'home-page':'hpage',
|
||||
'usergrowth':'ugrwt',
|
||||
'demand-forecast':'dmndf',
|
||||
'catalog-qc':'ctlqc',
|
||||
'data-platform-consumption':'dpcon',
|
||||
'data-platform-ingestion':'dping',
|
||||
'data-platform-nrt':'dpnrt',
|
||||
'data-platform-prism-frmw':'dpprf',
|
||||
'data-platform-experimentation':'dpexp',
|
||||
'display-ads':'dplay',
|
||||
'discovery-ranking':'drank',
|
||||
'mcache':'mche',
|
||||
'mcache-shared':'xmche',
|
||||
'supplier-live-commerce':'slcom',
|
||||
'trust-and-safety': 'tns',
|
||||
'valmo': 'vlm',
|
||||
'psec':'psec',
|
||||
'dbe':'dbe',
|
||||
'dev-productivity':'devprd']
|
||||
|
||||
if (targetString == null) {
|
||||
return null
|
||||
}
|
||||
switch (targetMap) {
|
||||
case 'bu_initials':
|
||||
return bu_initials[targetString]
|
||||
case 'team_initials':
|
||||
return team_initials[targetString]
|
||||
default:
|
||||
return 'Undefined option'
|
||||
}
|
||||
}
|
||||
|
||||
def get_team_initials(String team) {
|
||||
return get_initials('team_initials', team)
|
||||
}
|
||||
|
||||
def get_bu_initials(String bu) {
|
||||
return get_initials('bu_initials', bu)
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
|
||||
package com.meesho.utilities
|
||||
|
||||
def getWhitelistedRepos(fileName){
|
||||
dir('whitelist'){
|
||||
git(
|
||||
url: "https://github.com/Meesho/whitelists.git",
|
||||
branch: "main",
|
||||
credentialsId: 'cicd-github-app',
|
||||
)}
|
||||
def yaml = readYaml file: "whitelist/${fileName}.yaml"
|
||||
return yaml.get("repos", []) as Set
|
||||
}
|
||||
|
||||
def getWhitelistedDeployable(fileName, keyName){
|
||||
dir('whitelist'){
|
||||
git(
|
||||
url: "https://github.com/Meesho/whitelists.git",
|
||||
branch: "main",
|
||||
credentialsId: 'cicd-github-app',
|
||||
)}
|
||||
def yaml = readYaml file: "whitelist/${fileName}.yaml"
|
||||
return yaml.get(keyName, []) as Set
|
||||
}
|
||||
|
||||
/*
|
||||
* return `true` if we should not proceed
|
||||
*/
|
||||
def isMultizoneEnabled( String deployable){
|
||||
def WHITELIST = getWhitelistedDeployable("multizone-enabled-repos" , "multizone_enabled_deployables")
|
||||
if (WHITELIST.contains(deployable)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
* return `true` if we should not proceed
|
||||
*/
|
||||
def skipSonarCheckForbidden(Map config, Map environment_map) {
|
||||
def branch = env.BRANCH_NAME
|
||||
def environment = environment_map.getOrDefault(branch, "int")
|
||||
|
||||
def WHITELIST = getWhitelistedRepos("skip-sonar-whitelist")
|
||||
|
||||
// returns 'true' if we aren't skipping sonar
|
||||
// or if we're allowed to skip sonar
|
||||
def build_version = config['dockerBuildVersion']
|
||||
def repo_name = config['repo_name']
|
||||
|
||||
// if not a maven build OR if it a hotfix we exit early and don’t care what skip_sonar is
|
||||
if (WHITELIST.contains(repo_name)|| !(build_version.contains("maven")) || environment != "prd" || branch.contains("hotfix")){
|
||||
return false;
|
||||
}
|
||||
|
||||
return config['skip_sonar'];
|
||||
}
|
||||
|
||||
def skipSonarCheckForGo(Map config) {
|
||||
def branch = env.BRANCH_NAME
|
||||
def WHITELIST = getWhitelistedRepos("skip-sonar-whitelist")
|
||||
def build_version = config['dockerBuildVersion']
|
||||
def repo_name = config['repo_name']
|
||||
echo "env.INFRA_ENV: ${env.INFRA_ENV}"
|
||||
if (WHITELIST.contains(repo_name)|| branch.contains("hotfix")|| env.INFRA_ENV == "toolchain"){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* return `true` if we should not proceed
|
||||
*/
|
||||
def appConfigDisabledForbidden(boolean appConfigEnabled, String repo_name, String environment, String build_version){
|
||||
def branch = env.CHANGE_TARGET
|
||||
def WHITELIST = getWhitelistedRepos("app-config-disabled")
|
||||
if (WHITELIST.contains(repo_name) || environment!="stg"){
|
||||
return false
|
||||
}
|
||||
if (!(build_version.contains("maven") || build_version.contains("gradle"))){
|
||||
return false
|
||||
}
|
||||
return !appConfigEnabled
|
||||
}
|
||||
|
||||
/*
|
||||
* return `true` if we should not proceed
|
||||
*/
|
||||
def allowedNonDevelopPrDeploymentToIntRepos( String repo_name){
|
||||
def WHITELIST = getWhitelistedRepos("allowedNonDevelopPrDeploymentToInt")
|
||||
if (WHITELIST.contains(repo_name)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
* return `true` if we should not proceed
|
||||
*/
|
||||
def ValidateCacConfigForRepo(boolean ValidateConfig, String repo_name ){
|
||||
def branch = env.CHANGE_TARGET
|
||||
def WHITELIST = getWhitelistedRepos("ValidateCacConfig")
|
||||
if (WHITELIST.contains(repo_name)) {
|
||||
return true
|
||||
}
|
||||
return ValidateConfig
|
||||
}
|
||||
|
||||
def getToolchainEnv() {
|
||||
def paramsAction = currentBuild.rawBuild.getAction(hudson.model.ParametersAction.class)
|
||||
if (paramsAction) {
|
||||
echo "paramsAction: ${paramsAction}"
|
||||
def p = paramsAction.getParameter("TOOLCHAIN_ENV")
|
||||
echo "p: ${p}"
|
||||
if (p) {
|
||||
return p.getValue()?.toString()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
def run(Map config) {
|
||||
def branch_name = env.BRANCH_NAME
|
||||
if (env.INFRA_ENV == 'toolchain' && (config.build_tool?.startsWith('node-') || config.dockerBuildVersion?.startsWith('node-'))) {
|
||||
branch_name = 'develop' // develop maps to stg in the environment_map
|
||||
def tcEnv = getToolchainEnv()
|
||||
env.TOOLCHAIN_ENV = tcEnv
|
||||
log.info("Successfully extracted TOOLCHAIN_ENV from trigger cause: ${env.TOOLCHAIN_ENV}")
|
||||
}
|
||||
def environment_map = ['master':'prd', 'main':'prd', 'develop':'stg', 'gcp-main':'prd', 'farmiso-main':'prd', 'gcp-master':'prd', 'gcp-dev':'stg']
|
||||
env.skip_user_input = config.skip_user_input ?: false
|
||||
|
||||
// don't allow skip_sonar
|
||||
if (skipSonarCheckForbidden(config, environment_map)){
|
||||
throw new Exception("Not allowed to skip sonar (skip_sonar in config.yaml)")
|
||||
}
|
||||
|
||||
if (env.CHANGE_ID) {
|
||||
branch_name = env.CHANGE_TARGET
|
||||
environment_map = ['master':'int', 'main':'int', 'gcp-main':'int', 'farmiso-main':'int', 'gcp-master':'int', 'develop':'ftr', 'gcp-dev':'ftr']
|
||||
}
|
||||
environment_map[branch_name] = environment_map[branch_name] ?: 'ftr'
|
||||
|
||||
if (config.containsKey('branch_params')) {
|
||||
Map branch_config = config['branch_params'].collectEntries { key, value -> branch_name.matches(key) ? value : [ : ] }
|
||||
config.remove('branch_params')
|
||||
config.putAll(branch_config)
|
||||
}
|
||||
if (config.containsKey('environment')) {
|
||||
Map envrionment_config = config['environment'].collectEntries { key, value -> environment_map[branch_name].matches(key) ? value : [ : ] }
|
||||
config.remove('environment')
|
||||
config.putAll(envrionment_config)
|
||||
}
|
||||
|
||||
env.GITHUB_CRED = 'svc-devops-meesho'
|
||||
env.cicd_environment = environment_map[branch_name]
|
||||
env.helm_repo_name = 'devops-helm-charts'
|
||||
env.argo_repo_name = 'devops-argo-config'
|
||||
|
||||
echo "Branch Name - ${branch_name} and Environment - ${env.cicd_environment}"
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
def prodAccountID = '847438129436'
|
||||
def prodRegion = 'ap-southeast-1'
|
||||
def prodObjBucket = 'meesho-prod-artifacts'
|
||||
def devAccountID = '766380763301'
|
||||
def devObjBucket = 'meesho-stg-artifacts'
|
||||
def devRegion = 'ap-south-1'
|
||||
def accountDetails = [
|
||||
'prd': [
|
||||
'accountID': prodAccountID,
|
||||
'region': prodRegion,
|
||||
'objBucket': prodObjBucket
|
||||
],
|
||||
'int': [
|
||||
'accountID': prodAccountID,
|
||||
'region': prodRegion,
|
||||
'objBucket': prodObjBucket
|
||||
],
|
||||
'stg': [
|
||||
'accountID': devAccountID,
|
||||
'region': devRegion,
|
||||
'objBucket': devObjBucket
|
||||
],
|
||||
'ftr': [
|
||||
'accountID': devAccountID,
|
||||
'region': devRegion,
|
||||
'objBucket': devObjBucket
|
||||
]
|
||||
]
|
||||
env.accountID = accountDetails[env.cicd_environment]['accountID']
|
||||
env.region = accountDetails[env.cicd_environment]['region']
|
||||
env.registry = "${env.accountID}.dkr.ecr.${env.region}.amazonaws.com"
|
||||
env.buildRegistry = env.registry
|
||||
env.helmChartsPath = 'charts'
|
||||
env.defaultHelmChartVersion = '1.0.10'
|
||||
env.objBucket = accountDetails[env.cicd_environment]['objBucket']
|
||||
env.skip_notify = false
|
||||
echo "${env.accountID}.dkr.ecr.${env.region}.amazonaws.com"
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
def prodVaultURL = 'https://vault-prd.meeshogcp.in'
|
||||
def prodVaultToken = 'vault-prd-token'
|
||||
def prodSonarURL = 'https://sonarqube-prd.meeshogcp.in'
|
||||
def prodSonarToken = 'sonar-token-prod'
|
||||
def prodSonarEnv = 'sonarqube-test'
|
||||
def prodGoProxyUrl = 'https://athens-prd.meeshogcp.in'
|
||||
def prdDockerHost = 'dind-prd-svc'
|
||||
def preProdDockerHost = 'dind-int-svc'
|
||||
def prodGCPProject = "meesho-${config.bu}-prd-0622"
|
||||
def preprodGCPProject = "meesho-shared-int-0525"
|
||||
def devVaultURL = 'https://vault-dev.meeshogcp.in'
|
||||
def devVaultToken = 'vault-dev-token'
|
||||
def devSonarURL = "https://sonarqube-${config.bu}-dev.meeshogcp.in"
|
||||
def devSonarToken = "sonar-token-${config.bu}-dev"
|
||||
def devSonarEnv = "sonar-${config.bu}-dev"
|
||||
def devGoProxyUrl = 'https://athens-dev.meeshogcp.in'
|
||||
def devGCPProject = "meesho-${config.bu}-dev-0622"
|
||||
def devDockerHost = 'dind-dev-new-svc.jenkins-new.svc.cluster.local'
|
||||
def toolchainDockerHost = 'toolchain-dind-dev-svc.jenkins-toolchain.svc.cluster.local'
|
||||
def accountDetails = [
|
||||
'prd': [
|
||||
'vaultURL': prodVaultURL,
|
||||
'vaultToken': prodVaultToken,
|
||||
'sonarURL': prodSonarURL,
|
||||
'sonarToken': prodSonarToken,
|
||||
'GCPProject': prodGCPProject,
|
||||
'sonarEnv': prodSonarEnv,
|
||||
'GCPLBProject': prodGCPProject,
|
||||
'goProxyUrl': prodGoProxyUrl,
|
||||
'dockerHost': prdDockerHost
|
||||
],
|
||||
'int': [
|
||||
'vaultURL': prodVaultURL,
|
||||
'vaultToken': prodVaultToken,
|
||||
'sonarURL': prodSonarURL,
|
||||
'sonarToken': prodSonarToken,
|
||||
'GCPProject': preprodGCPProject,
|
||||
'sonarEnv': prodSonarEnv,
|
||||
'GCPLBProject': prodGCPProject,
|
||||
'goProxyUrl': prodGoProxyUrl,
|
||||
'dockerHost': preProdDockerHost
|
||||
],
|
||||
'stg': [
|
||||
'vaultURL': devVaultURL,
|
||||
'vaultToken': devVaultToken,
|
||||
'sonarURL': devSonarURL,
|
||||
'sonarToken': devSonarToken,
|
||||
'GCPProject': devGCPProject,
|
||||
'sonarEnv': devSonarEnv,
|
||||
'GCPLBProject': devGCPProject,
|
||||
'goProxyUrl': devGoProxyUrl,
|
||||
'dockerHost': devDockerHost
|
||||
],
|
||||
'ftr': [
|
||||
'vaultURL': devVaultURL,
|
||||
'vaultToken': devVaultToken,
|
||||
'sonarURL': devSonarURL,
|
||||
'sonarToken': devSonarToken,
|
||||
'GCPProject': devGCPProject,
|
||||
'sonarEnv': devSonarEnv,
|
||||
'GCPLBProject': devGCPProject,
|
||||
'goProxyUrl': devGoProxyUrl,
|
||||
'dockerHost': devDockerHost ]
|
||||
]
|
||||
env.GCPProject = accountDetails[env.cicd_environment]['GCPProject']
|
||||
env.GCPLBProject = accountDetails[env.cicd_environment]['GCPLBProject']
|
||||
env.registry = 'asia-southeast1-docker.pkg.dev/meesho-devops-admin-0622'
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
env.registry = 'asia-southeast1-docker.pkg.dev/meesho-central-dev-0622/toolchain'
|
||||
}
|
||||
env.buildRegistry = 'asia-southeast1-docker.pkg.dev/meesho-devops-admin-0622/admin'
|
||||
env.helmChartsPath = env.cicd_environment == 'prd' ? 'values_v3' : 'values_v2'
|
||||
env.defaultHelmChartVersion = '2.0.0'
|
||||
env.objBucket = "gcs-infr-dvps-meesho-artifacts-${env.cicd_environment}"
|
||||
env.vaultURL = accountDetails[env.cicd_environment]['vaultURL']
|
||||
env.vaultToken = accountDetails[env.cicd_environment]['vaultToken']
|
||||
env.sonarURL = accountDetails[env.cicd_environment]['sonarURL']
|
||||
env.sonarToken = accountDetails[env.cicd_environment]['sonarToken']
|
||||
env.sonarEnv = accountDetails[env.cicd_environment]['sonarEnv']
|
||||
env.goProxyUrl = accountDetails[env.cicd_environment]['goProxyUrl']
|
||||
env.skip_notify = true
|
||||
env.DOCKER_HOST = accountDetails[env.cicd_environment]['dockerHost']
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
env.DOCKER_HOST = toolchainDockerHost
|
||||
}
|
||||
}
|
||||
echo "Bucket and Image Repo Details - ${env.registry} ${env.buildRegistry} ${env.objBucket}"
|
||||
echo "Docker Host - ${env.DOCKER_HOST}"
|
||||
}
|
||||
|
||||
def perDeploymentVars(Map value_binding) {
|
||||
env.BU = value_binding.bu
|
||||
echo "${env.BU}"
|
||||
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
def inClusterName = 'https://kubernetes.default.svc'
|
||||
def prodArgoURL = 'prod-ops-argocd.meesho.com'
|
||||
def devArgoURL = 'stg-dev-argocd.meeshotest.in'
|
||||
def prodK8sCluster = [
|
||||
'supply': 'https://211689C65F4496AAA76FE19B29E24B6E.yl4.ap-southeast-1.eks.amazonaws.com',
|
||||
'demand': 'https://9059D138B6277A0EA592BA7F4B680CEC.gr7.ap-southeast-1.eks.amazonaws.com',
|
||||
'dataengg': 'https://806ADE97231CA65D2A0FFB780352630D.yl4.ap-southeast-1.eks.amazonaws.com',
|
||||
'datascience': 'https://E34D119516F751AFD1A61043B0514726.yl4.ap-southeast-1.eks.amazonaws.com',
|
||||
'central': 'https://C95FCEDF7CEE890F531E1D0488BEC6C3.gr7.ap-southeast-1.eks.amazonaws.com',
|
||||
'mcache': 'https://2FFADF214AD8BE58769C5F2797987E50.gr7.ap-southeast-1.eks.amazonaws.com'
|
||||
]
|
||||
def devK8sCluster = [
|
||||
'supply': inClusterName,
|
||||
'demand': inClusterName,
|
||||
'dataengg': inClusterName,
|
||||
'datascience': inClusterName,
|
||||
'central': inClusterName,
|
||||
'mcache': inClusterName
|
||||
]
|
||||
def accountDetails = [
|
||||
'prd': [
|
||||
'argoURL': prodArgoURL,
|
||||
'argoIncubator': 'prod-app-of-apps',
|
||||
'serverMap': prodK8sCluster
|
||||
],
|
||||
'int': [
|
||||
'argoURL': prodArgoURL,
|
||||
'argoIncubator': 'int-app-of-app',
|
||||
'serverMap': prodK8sCluster
|
||||
],
|
||||
'stg': [
|
||||
'argoURL': devArgoURL,
|
||||
'argoIncubator': 'app-of-apps',
|
||||
'serverMap': devK8sCluster
|
||||
],
|
||||
'ftr': [
|
||||
'argoURL': devArgoURL,
|
||||
'argoIncubator': 'ftr-app-of-apps',
|
||||
'serverMap': devK8sCluster
|
||||
]
|
||||
]
|
||||
env.clusterName = accountDetails[env.cicd_environment]['serverMap'][env.BU]
|
||||
env.argoAppsPath = 'applications'
|
||||
env.argoURL = accountDetails[env.cicd_environment]['argoURL']
|
||||
env.argoCreds = 'argocd-jenkins'
|
||||
env.argoIncubator = accountDetails[env.cicd_environment]['argoIncubator']
|
||||
env.argoAppNS = 'argocd'
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
def prodArgoURL = "argocd-${env.BU}-prd.meeshogcp.in"
|
||||
def prodArgoCreds = "argocd-${env.BU}-prd-creds"
|
||||
def preprodArgoURL = "argocd-shared-int.meeshogcp.in"
|
||||
def preprodArgoCreds = "argocd-shared-int-creds"
|
||||
def devArgoURL = 'argocd-dev.meeshogcp.in'
|
||||
def devArgoCreds = 'argocd-dev-creds'
|
||||
def accountDetails = [
|
||||
'prd': [
|
||||
'argoURL': prodArgoURL,
|
||||
'argoCreds': prodArgoCreds,
|
||||
'argoAppNS': "argocd-${env.BU}-prd",
|
||||
'clusterName': "k8s-${env.BU}-prd-ase1"
|
||||
],
|
||||
'int': [
|
||||
'argoURL': preprodArgoURL,
|
||||
'argoCreds': preprodArgoCreds,
|
||||
'argoAppNS': "argocd-shared-int",
|
||||
'clusterName': "k8s-shared-int-ase1"
|
||||
],
|
||||
'stg': [
|
||||
'argoURL': devArgoURL,
|
||||
'argoCreds': devArgoCreds,
|
||||
'argoAppNS': "argocd-dev",
|
||||
'clusterName': "k8s-${env.BU}-stg-ase1"
|
||||
],
|
||||
'ftr': [
|
||||
'argoURL': devArgoURL,
|
||||
'argoCreds': devArgoCreds,
|
||||
'argoAppNS': "argocd-dev",
|
||||
'clusterName': "k8s-${env.BU}-stg-ase1"
|
||||
]
|
||||
]
|
||||
|
||||
env.clusterName = accountDetails[env.cicd_environment]['clusterName']
|
||||
|
||||
if (env.cicd_environment == 'int') {
|
||||
env.argoAppsPath = "applications_v2/k8s-${env.BU}-int-ase1"
|
||||
} else {
|
||||
env.argoAppsPath = "applications_v2/${env.clusterName}"
|
||||
}
|
||||
|
||||
env.argoURL = accountDetails[env.cicd_environment]['argoURL']
|
||||
env.argoCreds = accountDetails[env.cicd_environment]['argoCreds']
|
||||
env.argoAppNS = accountDetails[env.cicd_environment]['argoAppNS']
|
||||
env.argoIncubator = "incubator-apps-k8s-${env.BU}-${env.cicd_environment}-ase1"
|
||||
}
|
||||
echo "${env.clusterName} ${env.argoURL} ${env.argoIncubator}"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def run(Map binding, String text) {
|
||||
return _construct(binding, text)
|
||||
}
|
||||
|
||||
def renderTemplate(Map binding, String templateFile, String fileName) {
|
||||
def template = libraryResource 'com/meesho/' + templateFile
|
||||
// Generic add_file support (language-agnostic): user repos declare files to bake
|
||||
// into the image under `add_file` in config.yaml -- either a single {path, target}
|
||||
// mapping or a list of them. renderTemplate always runs inside dir(repo_name), so
|
||||
// config.yaml resolves to the repo's config. The Dockerfile templates COPY each entry
|
||||
// into the image. Set for every render so the `add_files.each { ... }` guard never
|
||||
// hits a missing binding var. This is the one language-agnostic convention for
|
||||
// mounting extra files (e.g. the ab-client SDK's configs/abacus_experiments.yml ->
|
||||
// /opt/config/abacus_experiments.yml).
|
||||
binding['add_files'] = resolveAddFiles()
|
||||
def renderedTemplate = run(binding, template.toString())
|
||||
writeFile file:fileName, text: renderedTemplate
|
||||
}
|
||||
|
||||
// resolveAddFiles reads config.yaml (if present) and normalises the optional `add_file`
|
||||
// list into a list of [path, target] maps. `add_file` is a list of {path, target}
|
||||
// entries; each entry's target defaults to /opt/target when omitted; entries without a
|
||||
// path are skipped. A non-list add_file is ignored.
|
||||
def resolveAddFiles() {
|
||||
if (!fileExists('config.yaml')) {
|
||||
return []
|
||||
}
|
||||
def cfg = readYaml file: 'config.yaml'
|
||||
def entries = cfg?.add_file
|
||||
if (!(entries instanceof List)) {
|
||||
return []
|
||||
}
|
||||
def result = []
|
||||
entries.each { entry ->
|
||||
if (entry?.path) {
|
||||
result.add([path: entry.path, target: entry.target ?: '/opt/target'])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@NonCPS
|
||||
def _construct(Map binding, String text) {
|
||||
binding = new HashMap(binding)
|
||||
def engine = new groovy.text.SimpleTemplateEngine()
|
||||
def template = engine.createTemplate(text).make(binding)
|
||||
engine = null
|
||||
return template.toString()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def retryDockerPush(String cmd) {
|
||||
int maxAttempts = 5
|
||||
int attempt = 1
|
||||
while (attempt <= maxAttempts) {
|
||||
try {
|
||||
sh cmd
|
||||
break
|
||||
} catch (err) {
|
||||
if (attempt == maxAttempts) {
|
||||
error("Command failed after ${maxAttempts} attempts: ${err}")
|
||||
}
|
||||
echo "Command failed, retrying... (${attempt}/${maxAttempts})"
|
||||
sleep 3
|
||||
attempt++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def imageExists(String registry, String repoName, String tag) {
|
||||
int maxAttempts = 5
|
||||
int attempt = 1
|
||||
|
||||
while (attempt <= maxAttempts) {
|
||||
try {
|
||||
if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
def result = sh(
|
||||
script: "gcloud container images list-tags ${registry}/${repoName} --filter='tags:${tag}' --format='get(tags)'",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
return result != ""
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
echo "AWS not supported."
|
||||
return false
|
||||
}
|
||||
} catch (Exception e) {
|
||||
echo "Attempt ${attempt}/${maxAttempts} failed: Error checking image existence: ${e.toString()}"
|
||||
|
||||
if (attempt == maxAttempts) {
|
||||
echo "Max attempts reached. Assuming image does not exist or service is down."
|
||||
return false
|
||||
}
|
||||
|
||||
echo "Retrying in 5 seconds..."
|
||||
sleep 5
|
||||
attempt++
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def getCommitid(String repo_name) {
|
||||
dir(repo_name) {
|
||||
def gitCmd = env.INFRA_ENV == 'toolchain' ? 'git -c safe.directory="$(pwd)"' : 'git'
|
||||
def commitID = sh(returnStdout: true, script: "${gitCmd} log -1 --format=%h").trim()
|
||||
env.commit_id = sh(returnStdout: true, script: "${gitCmd} log -1 --format=%H").trim()
|
||||
return commitID
|
||||
}
|
||||
}
|
||||
|
||||
def getVersion(String repo_name) {
|
||||
dir(repo_name) {
|
||||
if (fileExists('pom.xml')) {
|
||||
return sh(returnStdout: true, script: 'xq -r .project.version pom.xml').trim()
|
||||
}
|
||||
else if (fileExists('package.json')) {
|
||||
return sh(returnStdout: true, script: 'jq -r .version package.json').trim()
|
||||
}
|
||||
else {
|
||||
return '1.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getModules(String repo_name) {
|
||||
dir(repo_name) {
|
||||
if (fileExists('pom.xml')) {
|
||||
modules = sh(returnStdout: true, script: 'xq -r .project.modules.module[] pom.xml 2>/dev/null || xq -r .project.modules.module pom.xml 2>/dev/null || echo empty').trim()
|
||||
if (modules == 'empty' || modules == 'null') {
|
||||
return null
|
||||
}
|
||||
modules = modules.split('\n') as List
|
||||
return modules
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getTag(String repo_name) {
|
||||
def version = getVersion(repo_name)
|
||||
def commitID = getCommitid(repo_name)
|
||||
def date = new Date()
|
||||
def timesha = date.getTime()
|
||||
def tag = "v${version}-${commitID}-${timesha}"
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
tag = "v${version}-${commitID}"
|
||||
}
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
def getTagShort(String repo_name) {
|
||||
def version = getVersion(repo_name)
|
||||
def commitID = getCommitid(repo_name)
|
||||
def tagShort = "v${version}-${commitID}"
|
||||
|
||||
return tagShort
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def getParam(String wd, String fileName = 'config.yaml') {
|
||||
dir(wd) {
|
||||
def config = readYaml file: fileName
|
||||
return config
|
||||
}
|
||||
}
|
||||
//read as string
|
||||
def getParamAsString(String wd, String fileName = 'config.yaml') {
|
||||
dir(wd) {
|
||||
// Read the entire file content as a string
|
||||
def yamlContent = readFile(file: fileName)
|
||||
return yamlContent
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def clone(String path, String repo_name, String branch_name) {
|
||||
log.info("Cloning repo - ${repo_name}, branch - ${branch_name} in path - ${path}")
|
||||
dir(path) {
|
||||
try {
|
||||
sh "rm -rf ${repo_name}"
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info('Repo not present, proceeding to clone the repo.')
|
||||
}
|
||||
try {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
if (branch_name) {
|
||||
sh "git clone -b ${branch_name} https://github.com/Meesho/${repo_name}.git"
|
||||
}
|
||||
else {
|
||||
sh "git clone https://github.com/Meesho/${repo_name}.git"
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg += "\n\nFAILED -\n ```Unable to clone repo - ${repo_name}, branch - ${branch_name} in path - ${path}.\n Full Erroror Details - ${e}```"
|
||||
env.error_msg_to_db += "Unable to Clone Repo ${repo_name};"
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def branchCheckOut(String path, String branch_name) {
|
||||
log.info("Checking out to branch - ${branch_name} in path - ${path}")
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh 'git fetch'
|
||||
try {
|
||||
sh "git checkout ${branch_name}"
|
||||
sh 'git pull --ff-only'
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info('Creating new branch')
|
||||
sh "git checkout -b ${branch_name}"
|
||||
}
|
||||
sh 'git branch'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def add(String path, String git_add_file) {
|
||||
log.info("Adding files - ${git_add_file} to git, in path - ${path}")
|
||||
try {
|
||||
dir(path) {
|
||||
sh "git add ${git_add_file}"
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg += "\n\nFAILED -\n ```Unable to add files - ${git_add_file} to git, in path - ${path}.\n Full Erroror Details - ${e}```"
|
||||
env.error_msg_to_db += 'Unable to Add Files;'
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def createTag(path, git_tag, tag_message) {
|
||||
log.info("Creating tag - ${git_tag} in git, in path - ${path}")
|
||||
try {
|
||||
dir(path) {
|
||||
sh "git tag ${git_tag} -m '${tag_message}'"
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg += "\n\nFAILED -\n ```Unable to create tag - ${git_tag} in git, in path - ${path}.\n Full Erroror Details - ${e}```"
|
||||
env.error_msg_to_db += "Unable to Create Tag ${git_tag};"
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def codeCommit(String path, String branch_name, String commit_message) {
|
||||
log.info("Commiting code with message - ${commit_message} in git, in path - ${path}")
|
||||
def global_arg = '--global'
|
||||
def gitName = 'svc-devops-meesho'
|
||||
def gitEmail = 'devops@meesho.com'
|
||||
def gitEnv = [
|
||||
"GIT_AUTHOR_NAME=${gitName}",
|
||||
"GIT_AUTHOR_EMAIL=${gitEmail}",
|
||||
"GIT_COMMITTER_NAME=${gitName}",
|
||||
"GIT_COMMITTER_EMAIL=${gitEmail}",
|
||||
]
|
||||
dir(path) {
|
||||
withEnv(gitEnv) {
|
||||
if (sh(returnStatus: true, script: "git diff-index --quiet ${branch_name} 2>/dev/null")) {
|
||||
try {
|
||||
sh "git commit -m '${commit_message}'"
|
||||
return 0
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg += "\n\nFAILED -\n ```Unable to commit code with message - ${commit_message} to git in path - ${path}.\n Full Erroror Details - ${e}```"
|
||||
env.error_msg_to_db += 'Unable to Commit;'
|
||||
log.error("${env.msg}")
|
||||
return 1
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info("No changes were made in branch - ${branch_name}")
|
||||
return 1
|
||||
// log.error("${env.msg}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def codePush(String path, String branch_name) {
|
||||
log.info("Pushing code in branch - ${branch_name} in path - ${path}")
|
||||
try {
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
try {
|
||||
sh "git push -f --set-upstream origin ${branch_name}"
|
||||
}
|
||||
catch (Exception e) {
|
||||
sh 'git pull --ff-only'
|
||||
sh 'git push -f'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg += "\n\nFAILED -\n ```Unable to push code in branch - ${branch_name} in path - ${path}.\n Full Erroror Details - ${e}```"
|
||||
env.error_msg_to_db += "Unable to push code in branch - ${branch_name};"
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def tagPush(String path) {
|
||||
log.info("Pushing tag in path - ${path}")
|
||||
try {
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh 'git push --tags'
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg += "\n\nFAILED -\n ```Unable to push tag from path - ${path}.\n Full Erroror Details - ${e}```"
|
||||
env.error_msg_to_db += 'Unable to Push tag;'
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def createPR(String app_name, String repo_name, String base_branch, String target_branch, String pr_message) {
|
||||
log.info("Creating PR with message - ${pr_message} in Github for repo ${repo_name}")
|
||||
def body = "{\"title\":\"${app_name} ${base_branch} Onboarding\",\"body\":\"${pr_message}\",\"head\":\"${target_branch}\",\"base\":\"${base_branch}\"}"
|
||||
def pr_num = 'empty'
|
||||
|
||||
try {
|
||||
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_CRED}", usernameVariable:'user', passwordVariable: 'token')]) {
|
||||
create_pr = httpRequest httpMode: 'POST',
|
||||
customHeaders: [
|
||||
[name: 'Accept', value: 'application/vnd.github+json'],
|
||||
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
|
||||
],
|
||||
requestBody: body,
|
||||
url: "https://api.github.com/repos/Meesho/${repo_name}/pulls",
|
||||
validResponseCodes: '201',
|
||||
timeout: 10
|
||||
def create_pr_json = readJSON(text: create_pr.content)
|
||||
try {
|
||||
error_filter = create_pr_json.errors.message[0]
|
||||
}
|
||||
catch (Exception e) {
|
||||
error_filter = 'empty'
|
||||
}
|
||||
if ( error_filter.contains('No commits between') ) {
|
||||
log.info("No changes were made in branch - ${target_branch}. Skipping - PR Creation...\n${create_pr_json}")
|
||||
}
|
||||
else if ( error_filter.contains('A pull request already exists') ) {
|
||||
log.info(error_filter)
|
||||
}
|
||||
else {
|
||||
pr_num = create_pr_json.number
|
||||
pr_url = create_pr_json.url
|
||||
log.info("PR Number - ${pr_num} and URL - ${pr_url}")
|
||||
}
|
||||
return pr_num.toString()
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "\n\nFAILED -\n Unable to create PR with message - ${pr_message}.\n Full Error Details - ${e}"
|
||||
def error_code = "${e}".split('Status code')[1]
|
||||
error_code = error_code.toString()
|
||||
error_code = error_code.split(' ')
|
||||
error_code = error_code[1]
|
||||
env.error_part_msg_to_db = "Unable to Create PR for base branch - ${base_branch}, target branch - ${target_branch}, Repo Name - ${repo_name}. Failed with status code ${error_code};" //Akshay has asked to remove it
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
def mergePR(String repo_name, String pr_num, String target_branch) {
|
||||
log.info("Merging PR ${pr_num} in repo - ${repo_name}")
|
||||
if ( "${pr_num}" == 'empty' || pr_num == null) {
|
||||
log.info("No changes were made in branch - ${target_branch}. Skipping - PR Merge...")
|
||||
}
|
||||
else {
|
||||
try {
|
||||
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_CRED}", usernameVariable:'user', passwordVariable: 'token')]) {
|
||||
merge_pr = httpRequest httpMode: 'PUT',
|
||||
customHeaders: [
|
||||
[name: 'Accept', value: 'application/vnd.github+json'],
|
||||
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
|
||||
],
|
||||
url: "https://api.github.com/repos/Meesho/${repo_name}/pulls/${pr_num}/merge",
|
||||
validResponseCodes: '200',
|
||||
timeout: 10
|
||||
|
||||
def merge_pr_json = readJSON(text: merge_pr.content)
|
||||
if ( merge_pr_json.message.contains('not mergeable') ) {
|
||||
env.msg += "\n\nFAILED -\n Unable to merge PR - ${pr_num}. PR URL - https://github.com/Meesho/${repo_name}/pulls/${pr_num}. ${merge_pr_json.message}"
|
||||
log.error("${env.msg}")
|
||||
error("${env.msg}")
|
||||
}
|
||||
else {
|
||||
log.info("PR Merge was SUCCESSFUL. Message - ${merge_pr_json.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "\n\nFAILED -\n Unable to merge PR - ${pr_num} \n Full Error Details - ${e}"
|
||||
def error_code = "${e}".split('Status code')[1]
|
||||
error_code = error_code.toString()
|
||||
error_code = error_code.split(' ')
|
||||
error_code = error_code[1]
|
||||
env.error_part_msg_to_db = "Unable to Merge PR - ${pr_num}, Repo Name - ${repo_name} status code ${error_code};" //Akshay has asked to remove it
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def deleteBranch(String path, String base_branch, String target_branch) {
|
||||
log.info("Deleting branch - ${target_branch}")
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
sh 'git fetch'
|
||||
try {
|
||||
sh "git checkout ${base_branch}"
|
||||
sh "git branch -d ${target_branch}"
|
||||
sh "git push -d origin ${target_branch}"
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = "\n\nFAILED -\n Unable to delete branch - ${target_branch}.\n Full Error Details - ${e}"
|
||||
env.error_msg_to_db = "Unable to Delete Branch ${target_branch};"
|
||||
log.error("${env.msg}")
|
||||
throw e
|
||||
}
|
||||
sh 'git branch'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def preDeleteBranch(String path, String base_branch, String target_branch) {
|
||||
log.info("Pre Deleting branch - ${target_branch}")
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
try {
|
||||
sh 'git fetch'
|
||||
sh "git checkout ${base_branch}"
|
||||
sh "git push -d origin ${target_branch}"
|
||||
}
|
||||
catch (Exception e) {
|
||||
echo "Pre Delete Branch - Unable to delete branch ${target_branch}"
|
||||
}
|
||||
sh 'git branch'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def fetchDiffFilesForPullRequest(String path , String target_branch){
|
||||
log.info("check diff from target branch - ${target_branch}")
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
try {
|
||||
sh "git fetch origin ${target_branch}:${target_branch}"
|
||||
sh "git branch"
|
||||
def changedFiles = sh(script: "git diff --name-only HEAD ${target_branch}", returnStdout: true).trim()
|
||||
echo "${changedFiles}"
|
||||
return changedFiles
|
||||
}
|
||||
catch (Exception e) {
|
||||
echo "failed to get the diff files from ${target_branch}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
def fetchDiffFilesForPushRequest(String path ){
|
||||
log.info("check diff of current and previous commit for ${path}")
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
try {
|
||||
sh "git fetch origin"
|
||||
|
||||
// Get the latest commit hash and the previous commit hash
|
||||
def currentCommit = sh(script: "git rev-parse HEAD", returnStdout: true).trim()
|
||||
def previousCommit = sh(script: "git rev-parse HEAD~1", returnStdout: true).trim()
|
||||
|
||||
// Capture the list of changed files in a Groovy variable
|
||||
def changedFiles = sh(script: "git diff --name-only ${previousCommit} ${currentCommit}", returnStdout: true).trim()
|
||||
|
||||
return changedFiles
|
||||
}
|
||||
catch (Exception e) {
|
||||
echo "failed to get the diff files for ${path}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def fetchLatestCommitId(String path, String branch) {
|
||||
log.info("Checking the latest commit for branch '${branch}' in path '${path}'")
|
||||
dir(path) {
|
||||
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
|
||||
try {
|
||||
// Fetch the latest changes for the specific branch
|
||||
sh "git fetch origin ${branch}:${branch}"
|
||||
|
||||
// Check out the specified branch
|
||||
sh "git checkout ${branch}"
|
||||
|
||||
// Get the latest commit hash for the branch
|
||||
def currentCommit = sh(script: "git rev-parse ${branch}", returnStdout: true).trim()
|
||||
|
||||
return currentCommit
|
||||
} catch (Exception e) {
|
||||
echo "Failed to get the latest commit for branch '${branch}' in path '${path}': ${e.message}"
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.meesho.utilities
|
||||
|
||||
def run(String memory_request, String cpu_request, String priority_v2) {
|
||||
echo 'Code to select node pool based on environment'
|
||||
switch (env.cicd_environment) {
|
||||
case 'prd':
|
||||
echo 'Code to select node pool based on memory and cpu request in prd'
|
||||
def mem_req_part = memory_request
|
||||
def cpu_req_part = cpu_request
|
||||
def priority = priority_v2
|
||||
echo "mem_req_part is ${mem_req_part}"
|
||||
echo "cpu_req_part is ${cpu_req_part}"
|
||||
if ( mem_req_part.contains('M') ) {
|
||||
mem_req = mem_req_part.replaceAll('Mi', '')
|
||||
mem_req = mem_req.replaceAll('M', '')
|
||||
try {
|
||||
mem_req = mem_req.toDouble()
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
mem_req = mem_req.toDouble()
|
||||
//mem_req = mem_req.toInteger()
|
||||
}
|
||||
}
|
||||
else if ( mem_req_part.contains('G') ) {
|
||||
mem_req = mem_req_part.replaceAll('Gi', '')
|
||||
mem_req = mem_req.replaceAll('G', '')
|
||||
try {
|
||||
mem_req = mem_req.toDouble() * 1024
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
mem_req = mem_req.toDouble() * 1024
|
||||
//mem_req = mem_req.toInteger()
|
||||
}
|
||||
}
|
||||
echo "memory_request is ${memory_request} ${mem_req}"
|
||||
|
||||
if ( cpu_req_part.contains('m') ) {
|
||||
cpu_req = cpu_req_part.replaceAll('m', '')
|
||||
try {
|
||||
cpu_req = cpu_req.toDouble()
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
cpu_req = cpu_req.toDouble()
|
||||
//cpu_req = cpu_req.toInteger()
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
cpu_req = cpu_req_part.toDouble() * 1000
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
cpu_req = cpu_req_part.toDouble() * 1000
|
||||
//cpu_req = cpu_req.toInteger()
|
||||
}
|
||||
}
|
||||
echo "cpu_request is ${cpu_request} ${cpu_req}"
|
||||
|
||||
def ratio = (mem_req / cpu_req).toDouble()
|
||||
if ( cpu_req > mem_req ) {
|
||||
ratio = 2
|
||||
}
|
||||
//ratio = ratio.toInteger()
|
||||
echo "Ratio - ${ratio}"
|
||||
if(priority.equalsIgnoreCase('cp1')||priority.equalsIgnoreCase('cp2')||priority.equalsIgnoreCase('cp3')||priority.equalsIgnoreCase('up1')||priority.equalsIgnoreCase('up2')||priority.equalsIgnoreCase('up3')||priority.equalsIgnoreCase('sp1')||priority.equalsIgnoreCase('sp2')||priority.equalsIgnoreCase('sp3')){
|
||||
low_priority="lite"
|
||||
if ( ratio >= 2.5 ) {
|
||||
ratiovalue = "tetra"
|
||||
}
|
||||
else {
|
||||
ratiovalue = "duo"
|
||||
}
|
||||
if ( cpu_req >=2200 ) {
|
||||
nodename = "sumo"
|
||||
}
|
||||
else{
|
||||
nodename= "mega"
|
||||
}
|
||||
nodeSelectorvalue = "${nodename}${ratiovalue}${low_priority}"
|
||||
println nodeSelectorvalue
|
||||
break
|
||||
}
|
||||
else{
|
||||
if ( ratio > 5.5 ) {
|
||||
ratiovalue = 'octa'
|
||||
}
|
||||
else if ( ratio >= 2.5 ) {
|
||||
ratiovalue = 'tetra'
|
||||
}
|
||||
else {
|
||||
ratiovalue = 'duo'
|
||||
}
|
||||
|
||||
if ( cpu_req >= 2200) {
|
||||
nodevalue = 'sumo'
|
||||
}
|
||||
else if ( cpu_req < 2200 && cpu_req >= 1000) {
|
||||
nodevalue = 'mega'
|
||||
}
|
||||
else {
|
||||
nodevalue = 'compact'
|
||||
}
|
||||
|
||||
switch ( env.BU?.toLowerCase() ) {
|
||||
case 'supply':
|
||||
if (nodevalue == 'sumo' && (ratiovalue == 'hexa' || ratiovalue == 'octa')){
|
||||
ratiovalue = 'tetra'
|
||||
}
|
||||
else if (nodevalue == 'mega' && (ratiovalue == 'quad' || ratiovalue == 'octa')){
|
||||
ratiovalue = 'tetra'
|
||||
}
|
||||
else if (nodevalue == 'compact' && ratiovalue == 'trio'){
|
||||
ratiovalue = 'tetra'
|
||||
}
|
||||
break
|
||||
case 'demand':
|
||||
if (nodevalue == 'mega' && ratiovalue == 'quad'){
|
||||
ratiovalue = 'tetra'
|
||||
}
|
||||
else if (nodevalue == 'compact' && (ratiovalue == 'octa' || ratiovalue == 'trio')){
|
||||
ratiovalue = 'tetra'
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
nodeSelectorvalue = "${nodevalue}${ratiovalue}"
|
||||
break
|
||||
|
||||
}
|
||||
case 'int':
|
||||
echo 'Shared node pool for int/pre-prod'
|
||||
nodeSelectorvalue = "preprod-cost-optimized"
|
||||
break
|
||||
case ['dev', 'ftr', 'stg']:
|
||||
echo 'Shared node pool for dev and ftr'
|
||||
nodeSelectorvalue = "${env.BU}-shared"
|
||||
break
|
||||
default:
|
||||
log.error('Unable to fetch environment')
|
||||
}
|
||||
return nodeSelectorvalue
|
||||
}
|
||||
Reference in New Issue
Block a user