Rename com.meesho/org.meesho namespace to com.homelab/org.homelab
Renames src/com/meesho -> src/com/homelab, resources/com/meesho -> resources/com/homelab, resources/org/meesho -> resources/org/homelab (via git mv, preserving history), and sweeps every remaining occurrence of "meesho" (any casing) out of package declarations, imports, libraryResource() paths, and comments across the whole repo. Also drops the per-user allowlist in vars/eksCICD.groovy, which hardcoded real former-colleagues' emails and doesn't apply to a single-person homelab — that branch is now permanently skipped rather than deleted outright, to avoid hand-editing the escape-sequence-heavy echo blocks it guards (eksCICD.groovy itself is unused legacy code, not called by homelabPipeline.groovy). Does not touch the ~114 files that were already missing from the working tree but still tracked in the prior commit — that's unrelated pre-existing state, left as-is.
This commit is contained in:
+3
-3
@@ -1,6 +1,6 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.stages.deployJar
|
||||
import com.homelab.stages.deployJar
|
||||
|
||||
|
||||
def run(Map config){
|
||||
@@ -22,7 +22,7 @@ def run(Map config){
|
||||
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}"
|
||||
sh "rm -rf ${automation_repo_name}; git clone git@github.com:Homelab/${automation_repo_name}.git -b ${branch}"
|
||||
echo "automation repo cloned"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.homelab.stages
|
||||
|
||||
import com.homelab.utilities.constructTemplate
|
||||
|
||||
// Rewritten for this homelab. The original's run() delegated to a
|
||||
// language-specific build object (buildNode/buildPython/etc.) and its
|
||||
// release() function drove ArgoCD sync via Ringmaster, Slack, CDN
|
||||
// invalidation, GCP/AWS branching — none of that applies to one solo app
|
||||
// on one cluster. Tag bumping in the target Helm chart is its own
|
||||
// separate stage now (updateHelmTag.groovy) rather than bundled in here.
|
||||
//
|
||||
// Kept faithfully: the real buildGo.groovy's fallback rule (line ~156)
|
||||
// — if the repo has no Dockerfile, render one from a language template;
|
||||
// if it does, just use it. That fallback now covers go/node/python/
|
||||
// java/php (matching resources/com/homelab/<lang>-Dockerfile), selected
|
||||
// via config.dockerBuildVersion — e.g. 'go-1.22', 'node-20',
|
||||
// 'python-3.12', 'java-21', 'php-8.3'. Simplified versions of the real
|
||||
// templates: no Homelab private-registry/SSH-keyed module auth, no Sonar,
|
||||
// no JFrog — see each template's own header comment.
|
||||
def run(Map config) {
|
||||
def tag = "${env.BUILD_NUMBER}-${env.GIT_COMMIT?.take(7) ?: 'dev'}"
|
||||
env.TAG = tag
|
||||
def image = "harbor-core.harbor.svc.cluster.local/${config.harbor_project}/${config.repo_name}:${tag}"
|
||||
try {
|
||||
stage(stageName('Build & push image')) {
|
||||
container('docker-cli') {
|
||||
dir("${config.repo_name}") {
|
||||
if (!fileExists('Dockerfile')) {
|
||||
renderDockerfile(config)
|
||||
}
|
||||
sh "docker build -t ${image} ."
|
||||
sh "docker push ${image}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
env.msg = 'Error building/pushing image. Error: ' + e.toString()
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// Only reached when the repo has no Dockerfile of its own. Requires
|
||||
// config.dockerBuildVersion (e.g. 'go-1.22') — there's no sensible
|
||||
// default to fall back to if a repo has neither a Dockerfile nor this
|
||||
// set, unlike every other config key in this pipeline.
|
||||
def renderDockerfile(Map config) {
|
||||
if (!config.dockerBuildVersion) {
|
||||
error("buildDocker: no Dockerfile in repo and config.dockerBuildVersion not set — can't pick a base image. Either add a Dockerfile to the repo, or set dockerBuildVersion (e.g. 'go-1.22') in config.yaml or the Jenkinsfile call.")
|
||||
}
|
||||
def parts = config.dockerBuildVersion.split('-', 2)
|
||||
def lang = parts[0]
|
||||
def version = parts.size() > 1 ? parts[1] : null
|
||||
|
||||
def templates = [
|
||||
go : ['go-Dockerfile', '1.22'],
|
||||
node : ['node-Dockerfile', '20'],
|
||||
python: ['python-Dockerfile', '3.12'],
|
||||
java : ['java-Dockerfile', '21'],
|
||||
maven : ['java-Dockerfile', '21'],
|
||||
php : ['php-Dockerfile', '8.3'],
|
||||
]
|
||||
def entry = templates[lang]
|
||||
if (!entry) {
|
||||
error("buildDocker: unrecognised language '${lang}' in dockerBuildVersion '${config.dockerBuildVersion}'. Supported: ${templates.keySet().join(', ')}. Or just add a Dockerfile to the repo instead — that always takes priority over this fallback.")
|
||||
}
|
||||
def (templateFile, defaultVersion) = entry
|
||||
def resolvedVersion = version ?: defaultVersion
|
||||
|
||||
log.info("buildDocker: no Dockerfile in repo — rendering ${templateFile} for ${lang} ${resolvedVersion}")
|
||||
def constructObj = new constructTemplate()
|
||||
constructObj.renderTemplate([version: resolvedVersion], templateFile, 'Dockerfile')
|
||||
sh 'cat Dockerfile'
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.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
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.utilities.addSSHKey
|
||||
import com.homelab.utilities.gitActions
|
||||
import com.homelab.utilities.constructParam
|
||||
import com.homelab.utilities.dockerUtilities
|
||||
|
||||
|
||||
def buildDckr(Map config) {
|
||||
env.GOPRIVATE = 'github.com/Meesho'
|
||||
env.GOPRIVATE = 'github.com/Homelab'
|
||||
def buTeamMappingObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dockerParamObj = new getDockerParams()
|
||||
@@ -65,7 +65,7 @@ def buildDckr(Map config) {
|
||||
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')
|
||||
writeFile file: 'validate_configs.py', text: libraryResource('com/homelab/validate_configs_v2.py')
|
||||
sh 'python3 validate_configs.py'
|
||||
}
|
||||
} else {
|
||||
@@ -300,7 +300,7 @@ def sonar_scan(String repoName, boolean skipSonarAndQualityGate, String goVersio
|
||||
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}"
|
||||
scannerCommand = "sonar-scanner -Dsonar.projectKey=${repoName} -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${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)
|
||||
@@ -351,8 +351,8 @@ def downloadGoFromJFrog(String goVersion) {
|
||||
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'
|
||||
'https://jfrog-prd.homelabgcp.in' :
|
||||
'https://jfrog-dev.homelabgcp.in'
|
||||
|
||||
def repo = 'devops-tools-local'
|
||||
def goTarball = "go${goVersion}.linux-amd64.tar.gz"
|
||||
+7
-7
@@ -1,9 +1,9 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.stages.checkOut
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.stages.checkOut
|
||||
|
||||
/*
|
||||
Function to define the flow of entire build, this function will call different stages related to maven build
|
||||
@@ -149,10 +149,10 @@ def sonar_scan(String repo_name, boolean skip_sonar) {
|
||||
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}")
|
||||
sh(script: "gradle sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${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}")
|
||||
sh(script: "gradle sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
|
||||
}
|
||||
}
|
||||
else {
|
||||
+12
-12
@@ -1,12 +1,12 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.stages.checkOut
|
||||
import com.meesho.utilities.gitActions
|
||||
import com.meesho.utilities.constructParam
|
||||
import com.meesho.utilities.dockerUtilities
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.stages.checkOut
|
||||
import com.homelab.utilities.gitActions
|
||||
import com.homelab.utilities.constructParam
|
||||
import com.homelab.utilities.dockerUtilities
|
||||
/*
|
||||
Function to define the flow of entire build, this function will call different stages related to maven build
|
||||
*/
|
||||
@@ -204,7 +204,7 @@ def build(String repo_name, boolean skip_test, String args, String repoType) {
|
||||
if (ValidateConfig) {
|
||||
log.info('************ Validate Config for CAC application.yml files ************')
|
||||
dir("$repo_name") {
|
||||
writeFile file: 'validate_configs.py', text: libraryResource('com/meesho/validate_configs.py')
|
||||
writeFile file: 'validate_configs.py', text: libraryResource('com/homelab/validate_configs.py')
|
||||
//Capture output separately, then check status
|
||||
validation_output = sh(
|
||||
script: 'python3 validate_configs.py 2>&1 || true', // || true prevents immediate failure
|
||||
@@ -270,7 +270,7 @@ def build(String repo_name, boolean skip_test, String args, String repoType) {
|
||||
(is_validation_error ?
|
||||
validation_output :
|
||||
e.toString())
|
||||
env.msg = "Error Building the maven package. If validate script error then please refer to doc - https://meesho.atlassian.net/wiki/spaces/EW/pages/3915972744/Config+Schema+Validation+Common+Errors+And+Fixes . Also Please check console output for more details - ${e}"
|
||||
env.msg = "Error Building the maven package. If validate script error then please refer to doc - https://homelab.atlassian.net/wiki/spaces/EW/pages/3915972744/Config+Schema+Validation+Common+Errors+And+Fixes . Also Please check console output for more details - ${e}"
|
||||
env.error_msg_to_db = detailed_error_msg
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
@@ -294,13 +294,13 @@ def sonar_scan(String repo_name, boolean skip_sonar , boolean appConfigChanges)
|
||||
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} -Dsonar.ws.timeout=120")
|
||||
sh(script: "mvn sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.ws.timeout=120")
|
||||
}
|
||||
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: "mvn sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.projectName=${repo_name} -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.ws.timeout=120")
|
||||
sh(script: "mvn sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.projectName=${repo_name} -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.ws.timeout=120")
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.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
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.utilities.addSSHKey
|
||||
import com.homelab.utilities.dockerUtilities
|
||||
import com.homelab.utilities.getYamlParameter
|
||||
|
||||
def removePackageLock() {
|
||||
sh(script: 'rm -rf package-lock.json')
|
||||
@@ -43,17 +43,17 @@ def getAwsSecret(def secret_name, def destination_file, def team, def bu) {
|
||||
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}")
|
||||
getVaultSecret("vault kv get -format=json homelab/${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")
|
||||
sh(script:"aws secretsmanager get-secret-value --secret-id ${npmrc_file} --query SecretString --output text| jq -r .HOMELAB_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")
|
||||
getVaultSecret("vault kv get -format=json homelab/${env.cicd_environment}/${bu}/${team}/${npmrc_file} | jq -r .data.data.HOMELAB_NPMRC_SECRET > .npmrc")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ def getPemFile(def secret_name, def team, def bu) {
|
||||
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")
|
||||
getVaultSecret("vault kv get -format=json homelab/${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")
|
||||
}
|
||||
@@ -72,7 +72,7 @@ def getPemFile(def secret_name, def team, def bu) {
|
||||
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")
|
||||
getVaultSecret("vault kv get -format=json homelab/${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")
|
||||
@@ -87,8 +87,8 @@ def getEnvFile(def secret_name, def team, def bu, boolean useCacPath = false) {
|
||||
}
|
||||
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}"
|
||||
? "homelab/${env.cicd_environment}-cac/${bu}/${team}/${gcp_env_file}-client"
|
||||
: "homelab/${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")
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ def buildDckr(Map config) {
|
||||
// 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}"
|
||||
def s3_path = config.s3_path ?: "homelab-${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}")
|
||||
@@ -351,7 +351,7 @@ def buildDckr(Map config) {
|
||||
if (fileExists('.npmrc')) {
|
||||
npm_registry = sh(
|
||||
returnStdout: true,
|
||||
script: "grep '^@meesho:registry=' .npmrc | head -1 | cut -d'=' -f2 | tr -d '\\r\\n'"
|
||||
script: "grep '^@homelab:registry=' .npmrc | head -1 | cut -d'=' -f2 | tr -d '\\r\\n'"
|
||||
).trim()
|
||||
echo "Detected npm registry: ${npm_registry ?: 'default (none found)'}"
|
||||
} else {
|
||||
@@ -399,7 +399,7 @@ def buildDckr(Map config) {
|
||||
try {
|
||||
dir(repo_name) {
|
||||
addSSHKey.create()
|
||||
withCredentials([usernamePassword(credentialsId: "svc-devops-meesho-token", usernameVariable: 'GIT_USER', passwordVariable: 'GIT_TOKEN')]) {
|
||||
withCredentials([usernamePassword(credentialsId: "svc-devops-homelab-token", usernameVariable: 'GIT_USER', passwordVariable: 'GIT_TOKEN')]) {
|
||||
sh """
|
||||
echo "GITHUB_TOKEN=${GIT_TOKEN}" >> .env
|
||||
echo "GIT_COMMIT_SHA='${commit_sha}'" >> .env
|
||||
@@ -443,7 +443,7 @@ def buildDckr(Map config) {
|
||||
}
|
||||
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 'FROM asia-southeast1-docker.pkg.dev/homelab-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}
|
||||
@@ -488,7 +488,7 @@ def buildDckr(Map config) {
|
||||
}
|
||||
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 " +
|
||||
"asia-southeast1-docker.pkg.dev/homelab-devops-admin-0622/admin/devops/google-cloud-sdk:458.0.0-alpine " +
|
||||
"${env.buildRegistry}/build/node:${version}-slim-secure-multiarch_v2.0"
|
||||
|
||||
sh """
|
||||
@@ -549,8 +549,8 @@ def getVaultSecret(String 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}/")
|
||||
vault_cmd = vault_cmd.replace("homelab/${env.cicd_environment}-cac/", "homelab/toolchain/${env.TOOLCHAIN_ENV}/${env.cicd_environment}-cac/")
|
||||
vault_cmd = vault_cmd.replace("homelab/${env.cicd_environment}/", "homelab/toolchain/${env.TOOLCHAIN_ENV}/${env.cicd_environment}/")
|
||||
log.info("TOOLCHAIN OVERRIDE (Application Config):")
|
||||
log.info(" New Toolchain Vault CMD: ${vault_cmd}")
|
||||
} else {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
def run(String build_tool){
|
||||
try {
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
|
||||
def buildDckr(Map config){
|
||||
def btObj = new buTeamMapping()
|
||||
+9
-9
@@ -1,10 +1,10 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.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.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.utilities.addSSHKey
|
||||
import com.homelab.utilities.dockerUtilities
|
||||
/*
|
||||
Function to get the version from pom.xml
|
||||
input arguments:
|
||||
@@ -30,7 +30,7 @@ repo_name: String parameter to change the directory where pom.xml is located
|
||||
|
||||
// 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")
|
||||
// sh (script:"aws secretsmanager get-secret-value --secret-id ${npmrc_file} --query SecretString --output text| jq -r .HOMELAB_NPMRC_SECRET > .npmrc")
|
||||
// }
|
||||
|
||||
// def getPemFile(def secret_name){
|
||||
@@ -156,8 +156,8 @@ def buildDckr(Map config) {
|
||||
// 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', \
|
||||
// withCredentials([string(credentialsId: 'homelab-github-ssh-prv-key', variable: 'SSH_PRIVATE_KEY_S')]) {
|
||||
// withCredentials(bindings: [sshUserPrivateKey(credentialsId: 'homelab-ssh-github-key', \
|
||||
// keyFileVariable: 'SSH_PRIVATE_KEY', \
|
||||
// passphraseVariable: '', \
|
||||
// usernameVariable: '')]) {
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.meesho.utilities.constructTemplate
|
||||
import com.meesho.utilities.getDockerParams
|
||||
import com.meesho.utilities.addSSHKey
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.utilities.addSSHKey
|
||||
|
||||
|
||||
|
||||
def buildDckr(Map config) {
|
||||
env.RUSTPRIVATE = 'github.com/Meesho'
|
||||
env.RUSTPRIVATE = 'github.com/Homelab'
|
||||
def btObj = new buTeamMapping()
|
||||
def constructObj = new constructTemplate()
|
||||
def dparam_obj = new getDockerParams()
|
||||
@@ -212,7 +212,7 @@ def sonar_scan(String repo_name, boolean skip_sonar , String version ) {
|
||||
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}")
|
||||
sh(script: "mvn sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${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')]) {
|
||||
@@ -239,7 +239,7 @@ def sonar_scan(String repo_name, boolean skip_sonar , String version ) {
|
||||
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 ")
|
||||
sh(script:"sonar-scanner -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${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 {
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.homelab.stages
|
||||
|
||||
// Adapted from the original: same structure (dir-scoped checkout,
|
||||
// optional submodule init if .gitmodules exists), just the credential
|
||||
// default changed from Homelab's internal service account
|
||||
// (svc-devops-homelab) to this homelab's Gitea credential. Set GITHUB_CRED
|
||||
// in the pipeline env if you ever need to override it per-job.
|
||||
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 = 'gitea-ci-credentials'
|
||||
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()
|
||||
log.error(env.msg)
|
||||
currentBuild.result = env.FAILURE
|
||||
throw e
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -1,14 +1,14 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.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
|
||||
import com.homelab.utilities.getYamlParameter
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.gitActions
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.constructParam
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.utilities.nodePoolSelection
|
||||
|
||||
def run(String repo_name, def deployment_order, def tag, def build_team, def dockerBuildVersion, String notify_channel) {
|
||||
def userInput = ''
|
||||
@@ -438,7 +438,7 @@ def update_helm_repo(String repo_name, String deployment, String tag, String bui
|
||||
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.")
|
||||
error("Error: Critical vulnerabilities found in repo: " + repo_name + " \nPlease resolve the alerts marked with CRITICAL here and retry: https://github.com/Homelab/" + repo_name + "/security/dependabot and Retry.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ 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 argoUrl = (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'main' || env.CHANGE_TARGET == 'master' || env.CHANGE_TARGET == 'main') ? 'prod-ops-argocd.homelab.com' : 'stg-dev-argocd.homelabtest.in'
|
||||
def argoEnv = (envrn == 'ftr') ? env.ingress_val : envrn
|
||||
|
||||
log.info('########################### Pulling latest changes in ArgoCD. ###########################')
|
||||
@@ -831,7 +831,7 @@ def validateRequiredMetadata(def bindings) {
|
||||
|
||||
for (param in serviceOwners) {
|
||||
final String owner = bindings[param]
|
||||
final String url = "https://pulse.meeshogcp.in/api/anonymous-User/userexist?email=${owner}"
|
||||
final String url = "https://pulse.homelabgcp.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
|
||||
@@ -868,7 +868,7 @@ def dependabotCriticalCheck(def repoName) {
|
||||
[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",
|
||||
url: "https://api.github.com/repos/homelab/${repo}/dependabot/alerts?state=open&per_page=100",
|
||||
validResponseCodes: '200',
|
||||
timeout: 10
|
||||
alerts = readJSON(text: validateDependabot.content)
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
def run(Map param){
|
||||
//get the jar for deployment, get it from the params module
|
||||
@@ -18,7 +18,7 @@ def deploy(String server_ip, String repo_name, String app_name, String healthche
|
||||
stage('Deploying JAR'){
|
||||
sh "echo '$server_ip' > host_file.txt"
|
||||
echo "inventory created"
|
||||
def playbook_content = libraryResource 'com/meesho/deployJar.yaml'
|
||||
def playbook_content = libraryResource 'com/homelab/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")
|
||||
}
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.utilities.getYamlParameter
|
||||
import com.homelab.utilities.getYamlParameter
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.DateTimeFormatterBuilder
|
||||
|
||||
@@ -41,10 +41,10 @@ def run(String repo_name, def deployment_order, def tag, def build_team, def doc
|
||||
switch (env.cicd_environment) {
|
||||
case 'prd':
|
||||
case 'int':
|
||||
baseUrl = 'https://ringmaster-api.meeshogcp.in/api/v1/key/cicd/cd/update'
|
||||
baseUrl = 'https://ringmaster-api.homelabgcp.in/api/v1/key/cicd/cd/update'
|
||||
break
|
||||
default:
|
||||
baseUrl = 'https://ringmaster-api.admin.meeshogcp.in/api/v1/key/cicd/cd/update'
|
||||
baseUrl = 'https://ringmaster-api.admin.homelabgcp.in/api/v1/key/cicd/cd/update'
|
||||
}
|
||||
final String url = "${baseUrl}?workingEnv=${working_env}"
|
||||
final String header = "Content-Type: application/json"
|
||||
@@ -67,10 +67,10 @@ def run(String repo_name, def deployment_order, def tag, def build_team, def doc
|
||||
switch (env.cicd_environment) {
|
||||
case 'prd':
|
||||
case 'int':
|
||||
cicdBaseUrl = 'http://turbo-turtle.meeshogcp.in'
|
||||
cicdBaseUrl = 'http://turbo-turtle.homelabgcp.in'
|
||||
break
|
||||
default:
|
||||
cicdBaseUrl = 'http://turbo-turtle.admin.meeshogcp.in'
|
||||
cicdBaseUrl = 'http://turbo-turtle.admin.homelabgcp.in'
|
||||
}
|
||||
final String newCICD_JSON = writeJSON returnText: true, json: newCICD_Payload
|
||||
//log.info("New CICD JSON - ${newCICD_JSON}")
|
||||
+8
-8
@@ -1,10 +1,10 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.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
|
||||
import com.homelab.utilities.constructTemplate
|
||||
import com.homelab.utilities.gitActions
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
import com.homelab.utilities.getDockerParams
|
||||
import com.homelab.stages.multiBranchPipeline
|
||||
|
||||
def run(Map params) {
|
||||
def btObj = new buTeamMapping()
|
||||
@@ -35,8 +35,8 @@ def run(Map params) {
|
||||
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
|
||||
modifiedParams['host'] = helm_branch_name == 'feature' ? "INGRESS_PR_NUMBER-${deployment}.dev.internal.homelabtest.in" : "${deployment}.${it.key}.internal.homelabtest.in"
|
||||
modifiedParams['host'] = (helm_branch_name == 'pre-prod') ? "${deployment}.${modifiedParams.bu}.internal.homelab.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') {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
def run(String repo_name){
|
||||
stage(stageName("Check for Hot Fix")){
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.homelab.stages
|
||||
|
||||
// New stage — the homelab equivalent of the real system's config.yaml
|
||||
// convention. Verified by reading constructParam.groovy directly first:
|
||||
// it does NOT read config.yaml itself — helmGenerator.groovy renders
|
||||
// devops-lib's own resources/com/homelab/config.yaml TEMPLATE into each
|
||||
// SERVICE repo's own root as a real, committed config.yaml, and various
|
||||
// stages then read that file directly (runHooks.groovy's
|
||||
// hooks.<phase> block, buildNode.groovy's s3_path/pbac_scope_name, etc.).
|
||||
//
|
||||
// This is the simplified equivalent: if the checked-out repo has a
|
||||
// config.yaml at its root, read it and merge its keys into the
|
||||
// pipeline's config Map — repo-committed values override whatever the
|
||||
// Jenkinsfile call passed in. Mutates config in place (Groovy Maps are
|
||||
// passed by reference), so every later stage that already has a
|
||||
// reference to the same object sees the merge — nothing needs to be
|
||||
// reassigned or returned.
|
||||
//
|
||||
// Entirely optional — a repo with no config.yaml just keeps running on
|
||||
// the Jenkinsfile call's defaults, same as before this existed.
|
||||
def run(Map config) {
|
||||
stage(stageName('Load config.yaml')) {
|
||||
dir(config.repo_name) {
|
||||
if (fileExists('config.yaml')) {
|
||||
def repoConfig = readYaml file: 'config.yaml'
|
||||
if (repoConfig instanceof Map) {
|
||||
config.putAll(repoConfig)
|
||||
log.info("loadConfig: merged config.yaml — keys: ${repoConfig.keySet()}")
|
||||
}
|
||||
} else {
|
||||
log.info('loadConfig: no config.yaml in repo root, using Jenkinsfile call defaults only.')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import jxl.*
|
||||
import hudson.util.PersistedList
|
||||
@@ -19,7 +19,7 @@ def applicationOnboard(String foldername, String repo_name) {
|
||||
String folderName = "${foldername}"
|
||||
String repoName = "${repo_name}"
|
||||
String scriptPath = "Jenkinsfile"
|
||||
String gitRepo = "https://github.com/Meesho/${repo_name}.git"
|
||||
String gitRepo = "https://github.com/Homelab/${repo_name}.git"
|
||||
String mBPName = "${repo_name}-cicd"
|
||||
String credentialsId = env.GITHUB_CRED
|
||||
|
||||
@@ -51,7 +51,7 @@ def applicationOnboard(String foldername, String repo_name) {
|
||||
def defaultVersion = "master"
|
||||
def traits = []
|
||||
|
||||
GitHubSCMSource gitHubSCMSource = new GitHubSCMSource("Meesho", repoName, gitRepo, implicit)
|
||||
GitHubSCMSource gitHubSCMSource = new GitHubSCMSource("Homelab", repoName, gitRepo, implicit)
|
||||
gitHubSCMSource.credentialsId = credentialsId
|
||||
|
||||
BranchDiscoveryTrait branchDiscoveryTrait = new BranchDiscoveryTrait(3)
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.homelab.stages
|
||||
|
||||
// Rewritten for this homelab. The original posted to Homelab's real Slack
|
||||
// workspace, an internal deployment-tracker API, and Ringmaster (their
|
||||
// deployment-approval system) — none of which exist here. This just logs
|
||||
// to the build console, which is all a solo homelab pipeline needs;
|
||||
// swap in a real notification channel later if you ever want one (e.g.
|
||||
// a Gitea webhook back to a commit status, or your own Slack if you set
|
||||
// one up).
|
||||
def run(Map config) {
|
||||
stage(stageName('Notify')) {
|
||||
log.info("Build ${currentBuild.currentResult} for ${config.repo_name} — tag ${env.TAG} — ${env.BUILD_URL}")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.homelab.stages
|
||||
|
||||
// Simplified from the real devops-lib's vars/runHooks.groovy — same core
|
||||
// mechanism: repo-declared scripts under hooks.<phase> in config.yaml,
|
||||
// blocking by default with an explicit `blocking: false` opt-out to
|
||||
// advisory (log + continue), repo-relative path validation (no absolute
|
||||
// paths, no `..` traversal), interpreter resolution (explicit >
|
||||
// extension > shebang), python venv + requirements provisioning, a
|
||||
// timeout per hook. Dropped: the deploy-phase cdHookRunner reuse (we
|
||||
// don't have a separate deploy-phase repo checkout — everything happens
|
||||
// in one pipeline) and the Turbo-Turtle callback system (TT_* env vars
|
||||
// renamed to HOOK_* — same shape, no Homelab-specific meaning attached).
|
||||
//
|
||||
// Called as runHooksObj.run(config, 'pre_build') / 'post_build' from
|
||||
// vars/homelabPipeline.groovy, around the buildDocker stage.
|
||||
def run(Map config, String phase) {
|
||||
def hooksBlock = config?.hooks
|
||||
if (!(hooksBlock instanceof Map)) {
|
||||
return
|
||||
}
|
||||
def hooks = hooksBlock[phase]
|
||||
if (!(hooks instanceof List) || hooks.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
String repoName = config.repo_name
|
||||
hooks.eachWithIndex { hook, idx ->
|
||||
runOneHook(repoName, phase, idx, hook)
|
||||
}
|
||||
}
|
||||
|
||||
def runOneHook(String repoName, String phase, int idx, def hook) {
|
||||
String name = (hook?.name ?: "${phase}-${idx}").toString()
|
||||
String script = hook?.script?.toString()
|
||||
String interpreter = hook?.interpreter?.toString()
|
||||
String requirements = hook?.requirements?.toString()
|
||||
// Blocking by default; only an explicit `blocking: false` demotes to advisory.
|
||||
boolean blocking = !(hook?.blocking?.toString() == 'false')
|
||||
int timeoutSeconds = 600
|
||||
if (hook?.timeout_seconds) {
|
||||
try { timeoutSeconds = hook.timeout_seconds.toString().toInteger() } catch (ignored) { timeoutSeconds = 600 }
|
||||
}
|
||||
|
||||
if (!script) {
|
||||
error("runHooks: ${phase}[${idx}] '${name}' has no 'script' path in config.yaml.")
|
||||
}
|
||||
assertRepoRelative(script, "${phase}[${idx}] '${name}' script")
|
||||
if (requirements) {
|
||||
assertRepoRelative(requirements, "${phase}[${idx}] '${name}' requirements")
|
||||
}
|
||||
|
||||
stage(stageName("${phase}: ${name}")) {
|
||||
container('docker-cli') {
|
||||
dir(repoName) {
|
||||
if (!fileExists(script)) {
|
||||
error("runHooks: ${phase} hook '${name}' script not found in repo: ${script}")
|
||||
}
|
||||
List<String> hookEnv = [
|
||||
"HOOK_PHASE=${phase}",
|
||||
"HOOK_NAME=${name}",
|
||||
"HOOK_REPO=${repoName}",
|
||||
"HOOK_IMAGE_TAG=${env.TAG ?: ''}",
|
||||
]
|
||||
String runCmd = buildRunCommand(script, interpreter, requirements)
|
||||
log.info("runHooks: executing ${phase} hook '${name}' (${script}), blocking=${blocking}, timeout=${timeoutSeconds}s")
|
||||
withEnv(hookEnv) {
|
||||
try {
|
||||
timeout(time: timeoutSeconds, unit: 'SECONDS') {
|
||||
sh(script: runCmd)
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (blocking) {
|
||||
log.error("runHooks: blocking ${phase} hook '${name}' failed: ${e}")
|
||||
throw e
|
||||
}
|
||||
log.warning("runHooks: advisory ${phase} hook '${name}' failed (non-blocking): ${e}")
|
||||
currentBuild.description = (currentBuild.description ? currentBuild.description + " | " : "") + "hook(${name}) advisory-failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def buildRunCommand(String script, String interpreter, String requirements) {
|
||||
String interp = interpreter
|
||||
if (!interp) {
|
||||
if (script.endsWith('.py')) {
|
||||
interp = 'python3'
|
||||
} else if (script.endsWith('.sh')) {
|
||||
interp = 'bash'
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPython = (interp == 'python3' || interp == 'python' || script.endsWith('.py'))
|
||||
// docker:27-cli is minimal Alpine — only `sh` is guaranteed present.
|
||||
// bash/python3 need installing on demand, unlike the real system's
|
||||
// pod images which already bundle a full toolchain.
|
||||
String installLine = ''
|
||||
if (isPython) {
|
||||
installLine = 'apk add --no-cache python3 py3-pip py3-virtualenv >/dev/null'
|
||||
} else if (interp == 'bash') {
|
||||
installLine = 'apk add --no-cache bash >/dev/null'
|
||||
}
|
||||
|
||||
if (requirements && isPython) {
|
||||
String py = interp ?: 'python3'
|
||||
return """
|
||||
set -e
|
||||
${installLine}
|
||||
${py} -m venv .hook_venv
|
||||
. .hook_venv/bin/activate
|
||||
pip install --quiet --disable-pip-version-check -r ${requirements}
|
||||
${py} ${script}
|
||||
""".stripIndent().trim()
|
||||
}
|
||||
|
||||
if (interp) {
|
||||
return "set -e\n${installLine}\n${interp} ${script}"
|
||||
}
|
||||
// No interpreter resolved — rely on the script's shebang.
|
||||
return "set -e\nchmod +x ${script}\n./${script}"
|
||||
}
|
||||
|
||||
// Rejects absolute paths and parent-directory traversal so a hook can
|
||||
// only execute code that lives inside the checked-out repo.
|
||||
def assertRepoRelative(String p, String what) {
|
||||
if (p.startsWith('/')) {
|
||||
error("runHooks: ${what} path '${p}' must be repo-relative, not absolute.")
|
||||
}
|
||||
if (p == '..' || p.startsWith('../') || p.contains('/../')) {
|
||||
error("runHooks: ${what} path '${p}' must not traverse outside the repo ('..').")
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
def run(Map config) {
|
||||
try {
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.homelab.stages
|
||||
|
||||
// New stage — the homelab equivalent of devops-lib's real
|
||||
// refresh_and_sync (deployArgoCD.groovy step 4: `argocd app sync
|
||||
// --hard-refresh`). Without this, the pipeline stops at the tag-bump
|
||||
// commit and a human has to remember to click Sync in the ArgoCD UI —
|
||||
// their real system never leaves that step manual. Uses the ArgoCD REST
|
||||
// API directly via curl (scoped jenkins-ci token, not the argocd CLI
|
||||
// binary — avoids adding another container to dind-pod.yaml just for
|
||||
// this one call) against the server's internal cluster-DNS Service, not
|
||||
// the ingress — same pod-to-pod reasoning as pushing to Harbor.
|
||||
//
|
||||
// ARGOCD_TOKEN comes from the pod env (dind-pod.yaml, ESO-managed secret)
|
||||
// — not Jenkins' own credential store, staying consistent with the rest
|
||||
// of this pipeline. It's marked optional there, so if it's genuinely
|
||||
// empty (bootstrap token not generated yet), fail loudly here with a
|
||||
// clear message rather than a confusing curl auth error.
|
||||
//
|
||||
// Expects in config:
|
||||
// argo_app_name the Application's metadata.name, e.g. demo-go-app
|
||||
// argo_server_url e.g. http://argocd-admin-prd-server.argocd.svc.cluster.local
|
||||
def run(Map config) {
|
||||
stage(stageName('Sync ArgoCD Application')) {
|
||||
container('docker-cli') {
|
||||
if (!env.ARGOCD_TOKEN?.trim()) {
|
||||
log.error('ARGOCD_TOKEN is empty — the jenkins-ci account token has not been generated yet. See secretstores/argocd-jenkins-ci-token.yaml for the one-time bootstrap steps.')
|
||||
error('Skipping ArgoCD sync: no token available.')
|
||||
}
|
||||
sh """
|
||||
apk add --no-cache curl >/dev/null
|
||||
curl -sf -X POST \\
|
||||
-H "Authorization: Bearer \$ARGOCD_TOKEN" \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-d '{}' \\
|
||||
"${config.argo_server_url ?: 'http://argocd-admin-prd-server.argocd.svc.cluster.local'}/api/v1/applications/${config.argo_app_name}/sync"
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.homelab.stages
|
||||
|
||||
// New stage — no equivalent this simple existed before. The original's
|
||||
// version (deployArgoCD.groovy's update_helm_repo, ~900 lines) ran a full
|
||||
// PR workflow — branch, commit, push, create PR, merge PR, delete branch
|
||||
// — against Homelab's real GitHub org, driven by a BU/team templating
|
||||
// engine and canary-enforcement rules. Solo homelab, no reviewer to wait
|
||||
// on: this just clones, bumps the tag with yq, commits, and pushes
|
||||
// straight to main. ArgoCD picks up the change on its own next sync
|
||||
// (manual, same as everything else in this repo — see the sister repo's
|
||||
// README on sync policy).
|
||||
//
|
||||
// Expects in config:
|
||||
// repo_name the app's repo name — also the first path segment
|
||||
// under devops-helm-charts/values/
|
||||
// service_name second path segment; same as repo_name for a
|
||||
// single-service repo, different for a monorepo with
|
||||
// several services sharing one repo
|
||||
// helm_repo_url e.g. http://gitea.192.168.1.7.nip.io/mukul/devops-helm-charts.git
|
||||
// image_tag_yq_path yq path to the tag field, e.g. .deployment.image.tag
|
||||
// gitea_cred Jenkins credential ID for a Gitea push-capable token (default: gitea-ci-credentials)
|
||||
//
|
||||
// Values file path is computed, not passed directly:
|
||||
// devops-helm-charts/values/<repo_name>/<service_name>/values.yaml
|
||||
def run(Map config) {
|
||||
def valuesFile = "values/${config.repo_name}/${config.service_name}/values.yaml"
|
||||
stage(stageName('Update Helm chart image tag')) {
|
||||
withCredentials([usernamePassword(credentialsId: config.gitea_cred ?: 'gitea-ci-credentials', usernameVariable: 'GIT_USER', passwordVariable: 'GIT_PASS')]) {
|
||||
dir('helm-chart-repo') {
|
||||
deleteDir()
|
||||
def authedUrl = config.helm_repo_url.replaceFirst('http://', "http://\${GIT_USER}:\${GIT_PASS}@")
|
||||
sh """
|
||||
git clone ${authedUrl} .
|
||||
yq -i '${config.image_tag_yq_path} = "${env.TAG}"' ${valuesFile}
|
||||
git config user.email 'jenkins-ci@homelab.local'
|
||||
git config user.name 'jenkins-ci'
|
||||
git commit -am 'ci: bump ${config.repo_name}/${config.service_name} image tag to ${env.TAG}'
|
||||
git push origin main
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package com.meesho.stages
|
||||
package com.homelab.stages
|
||||
|
||||
import com.meesho.utilities.buTeamMapping
|
||||
import com.homelab.utilities.buTeamMapping
|
||||
|
||||
def run(String bu, String team,String module){
|
||||
stage("Validate BU and Team"){
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def create() {
|
||||
withCredentials([file(credentialsId: 'ssh-private-key', variable: 'FILE')]) {
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
Purpose: Utility function to return BU and their respective teams
|
||||
Author: Avinash kumar Lodhi
|
||||
*/
|
||||
package com.meesho.utilities
|
||||
package com.homelab.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'],
|
||||
+24
-24
@@ -1,10 +1,10 @@
|
||||
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def getWhitelistedRepos(fileName){
|
||||
dir('whitelist'){
|
||||
git(
|
||||
url: "https://github.com/Meesho/whitelists.git",
|
||||
url: "https://github.com/Homelab/whitelists.git",
|
||||
branch: "main",
|
||||
credentialsId: 'cicd-github-app',
|
||||
)}
|
||||
@@ -15,7 +15,7 @@ def getWhitelistedRepos(fileName){
|
||||
def getWhitelistedDeployable(fileName, keyName){
|
||||
dir('whitelist'){
|
||||
git(
|
||||
url: "https://github.com/Meesho/whitelists.git",
|
||||
url: "https://github.com/Homelab/whitelists.git",
|
||||
branch: "main",
|
||||
credentialsId: 'cicd-github-app',
|
||||
)}
|
||||
@@ -151,7 +151,7 @@ def run(Map config) {
|
||||
config.putAll(envrionment_config)
|
||||
}
|
||||
|
||||
env.GITHUB_CRED = 'svc-devops-meesho'
|
||||
env.GITHUB_CRED = 'svc-devops-homelab'
|
||||
env.cicd_environment = environment_map[branch_name]
|
||||
env.helm_repo_name = 'devops-helm-charts'
|
||||
env.argo_repo_name = 'devops-argo-config'
|
||||
@@ -160,9 +160,9 @@ def run(Map config) {
|
||||
if (env.CLOUD_PROVIDER == 'AWS') {
|
||||
def prodAccountID = '847438129436'
|
||||
def prodRegion = 'ap-southeast-1'
|
||||
def prodObjBucket = 'meesho-prod-artifacts'
|
||||
def prodObjBucket = 'homelab-prod-artifacts'
|
||||
def devAccountID = '766380763301'
|
||||
def devObjBucket = 'meesho-stg-artifacts'
|
||||
def devObjBucket = 'homelab-stg-artifacts'
|
||||
def devRegion = 'ap-south-1'
|
||||
def accountDetails = [
|
||||
'prd': [
|
||||
@@ -197,23 +197,23 @@ def run(Map config) {
|
||||
echo "${env.accountID}.dkr.ecr.${env.region}.amazonaws.com"
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
def prodVaultURL = 'https://vault-prd.meeshogcp.in'
|
||||
def prodVaultURL = 'https://vault-prd.homelabgcp.in'
|
||||
def prodVaultToken = 'vault-prd-token'
|
||||
def prodSonarURL = 'https://sonarqube-prd.meeshogcp.in'
|
||||
def prodSonarURL = 'https://sonarqube-prd.homelabgcp.in'
|
||||
def prodSonarToken = 'sonar-token-prod'
|
||||
def prodSonarEnv = 'sonarqube-test'
|
||||
def prodGoProxyUrl = 'https://athens-prd.meeshogcp.in'
|
||||
def prodGoProxyUrl = 'https://athens-prd.homelabgcp.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 prodGCPProject = "homelab-${config.bu}-prd-0622"
|
||||
def preprodGCPProject = "homelab-shared-int-0525"
|
||||
def devVaultURL = 'https://vault-dev.homelabgcp.in'
|
||||
def devVaultToken = 'vault-dev-token'
|
||||
def devSonarURL = "https://sonarqube-${config.bu}-dev.meeshogcp.in"
|
||||
def devSonarURL = "https://sonarqube-${config.bu}-dev.homelabgcp.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 devGoProxyUrl = 'https://athens-dev.homelabgcp.in'
|
||||
def devGCPProject = "homelab-${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 = [
|
||||
@@ -263,14 +263,14 @@ def run(Map config) {
|
||||
]
|
||||
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'
|
||||
env.registry = 'asia-southeast1-docker.pkg.dev/homelab-devops-admin-0622'
|
||||
if (env.INFRA_ENV == 'toolchain') {
|
||||
env.registry = 'asia-southeast1-docker.pkg.dev/meesho-central-dev-0622/toolchain'
|
||||
env.registry = 'asia-southeast1-docker.pkg.dev/homelab-central-dev-0622/toolchain'
|
||||
}
|
||||
env.buildRegistry = 'asia-southeast1-docker.pkg.dev/meesho-devops-admin-0622/admin'
|
||||
env.buildRegistry = 'asia-southeast1-docker.pkg.dev/homelab-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.objBucket = "gcs-infr-dvps-homelab-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']
|
||||
@@ -293,8 +293,8 @@ def perDeploymentVars(Map value_binding) {
|
||||
|
||||
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 prodArgoURL = 'prod-ops-argocd.homelab.com'
|
||||
def devArgoURL = 'stg-dev-argocd.homelabtest.in'
|
||||
def prodK8sCluster = [
|
||||
'supply': 'https://211689C65F4496AAA76FE19B29E24B6E.yl4.ap-southeast-1.eks.amazonaws.com',
|
||||
'demand': 'https://9059D138B6277A0EA592BA7F4B680CEC.gr7.ap-southeast-1.eks.amazonaws.com',
|
||||
@@ -341,11 +341,11 @@ def perDeploymentVars(Map value_binding) {
|
||||
env.argoAppNS = 'argocd'
|
||||
}
|
||||
else if (env.CLOUD_PROVIDER == 'GCP') {
|
||||
def prodArgoURL = "argocd-${env.BU}-prd.meeshogcp.in"
|
||||
def prodArgoURL = "argocd-${env.BU}-prd.homelabgcp.in"
|
||||
def prodArgoCreds = "argocd-${env.BU}-prd-creds"
|
||||
def preprodArgoURL = "argocd-shared-int.meeshogcp.in"
|
||||
def preprodArgoURL = "argocd-shared-int.homelabgcp.in"
|
||||
def preprodArgoCreds = "argocd-shared-int-creds"
|
||||
def devArgoURL = 'argocd-dev.meeshogcp.in'
|
||||
def devArgoURL = 'argocd-dev.homelabgcp.in'
|
||||
def devArgoCreds = 'argocd-dev-creds'
|
||||
def accountDetails = [
|
||||
'prd': [
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.homelab.utilities
|
||||
|
||||
// Ported from the real devops-lib's constructTemplate.groovy — same
|
||||
// SimpleTemplateEngine mechanism (${...} interpolation, <% %> control
|
||||
// flow), same @NonCPS requirement (the engine is a non-serialisable Java
|
||||
// object; calling this across a `parallel` boundary would break). Dropped
|
||||
// the Homelab-specific `add_file`/PBAC resolution — this homelab has no
|
||||
// equivalent convention yet; add it back here if that's ever needed.
|
||||
def run(Map binding, String text) {
|
||||
return _construct(binding, text)
|
||||
}
|
||||
|
||||
def renderTemplate(Map binding, String templateFile, String fileName) {
|
||||
def template = libraryResource 'com/homelab/' + templateFile
|
||||
def renderedTemplate = run(binding, template.toString())
|
||||
writeFile file: fileName, text: renderedTemplate
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def retryDockerPush(String cmd) {
|
||||
int maxAttempts = 5
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def getCommitid(String repo_name) {
|
||||
dir(repo_name) {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def getParam(String wd, String fileName = 'config.yaml') {
|
||||
dir(wd) {
|
||||
+8
-8
@@ -1,4 +1,4 @@
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def clone(String path, String repo_name, String branch_name) {
|
||||
log.info("Cloning repo - ${repo_name}, branch - ${branch_name} in path - ${path}")
|
||||
@@ -12,10 +12,10 @@ def clone(String path, String repo_name, String branch_name) {
|
||||
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"
|
||||
sh "git clone -b ${branch_name} https://github.com/Homelab/${repo_name}.git"
|
||||
}
|
||||
else {
|
||||
sh "git clone https://github.com/Meesho/${repo_name}.git"
|
||||
sh "git clone https://github.com/Homelab/${repo_name}.git"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,8 +79,8 @@ def createTag(path, git_tag, tag_message) {
|
||||
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 gitName = 'svc-devops-homelab'
|
||||
def gitEmail = 'devops@homelab.com'
|
||||
def gitEnv = [
|
||||
"GIT_AUTHOR_NAME=${gitName}",
|
||||
"GIT_AUTHOR_EMAIL=${gitEmail}",
|
||||
@@ -163,7 +163,7 @@ def createPR(String app_name, String repo_name, String base_branch, String targe
|
||||
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
|
||||
],
|
||||
requestBody: body,
|
||||
url: "https://api.github.com/repos/Meesho/${repo_name}/pulls",
|
||||
url: "https://api.github.com/repos/Homelab/${repo_name}/pulls",
|
||||
validResponseCodes: '201',
|
||||
timeout: 10
|
||||
def create_pr_json = readJSON(text: create_pr.content)
|
||||
@@ -212,13 +212,13 @@ def mergePR(String repo_name, String pr_num, String target_branch) {
|
||||
[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",
|
||||
url: "https://api.github.com/repos/Homelab/${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}"
|
||||
env.msg += "\n\nFAILED -\n Unable to merge PR - ${pr_num}. PR URL - https://github.com/Homelab/${repo_name}/pulls/${pr_num}. ${merge_pr_json.message}"
|
||||
log.error("${env.msg}")
|
||||
error("${env.msg}")
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.meesho.utilities
|
||||
package com.homelab.utilities
|
||||
|
||||
def run(String memory_request, String cpu_request, String priority_v2) {
|
||||
echo 'Code to select node pool based on environment'
|
||||
@@ -1,68 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user