From 3301d0928896f7fed6943260962eec3f64e15788 Mon Sep 17 00:00:00 2001 From: hiondal Date: Mon, 3 Mar 2025 16:58:14 +0900 Subject: [PATCH] release --- deployment/Jenkinsfile | 34 +++++++- deployment/Jenkinsfile_SonarQube | 137 ------------------------------- 2 files changed, 32 insertions(+), 139 deletions(-) delete mode 100644 deployment/Jenkinsfile_SonarQube diff --git a/deployment/Jenkinsfile b/deployment/Jenkinsfile index 54066c1..c6cf160 100644 --- a/deployment/Jenkinsfile +++ b/deployment/Jenkinsfile @@ -13,10 +13,12 @@ podTemplate( containerTemplate(name: 'node', image: 'node:20-slim', ttyEnabled: true, command: 'cat'), containerTemplate(name: 'podman', image: "mgoltzsche/podman", ttyEnabled: true, command: 'cat', privileged: true), containerTemplate(name: 'azure-cli', image: 'hiondal/azure-kubectl:latest', command: 'cat', ttyEnabled: true), - containerTemplate(name: 'envsubst', image: "hiondal/envsubst", command: 'sleep', args: '1h') + containerTemplate(name: 'envsubst', image: "hiondal/envsubst", command: 'sleep', args: '1h'), + containerTemplate(name: 'sonar-scanner', image: 'sonarsource/sonar-scanner-cli:latest', command: 'cat', ttyEnabled: true) ], volumes: [ - emptyDirVolume(mountPath: '/root/.azure', memory: false) + emptyDirVolume(mountPath: '/root/.azure', memory: false), + emptyDirVolume(mountPath: '/opt/sonar-scanner/.sonar/cache', memory: false) ] ) { node(PIPELINE_ID) { @@ -24,6 +26,7 @@ podTemplate( def imageTag = getImageTag() def manifest = "deploy.yaml" def namespace + def sonarScannerHome = '/opt/sonar-scanner' stage("Get Source") { checkout scm @@ -31,6 +34,33 @@ podTemplate( namespace = "${props.namespace}" } + stage('Code Analysis & Quality Gate') { + container('node') { + sh "npm install" + sh "npm test -- --coverage --passWithNoTests" //test code 없어도 통과되게 함 + } + + container('sonar-scanner') { + withSonarQubeEnv('SonarQube') { + sh """ + ${sonarScannerHome}/bin/sonar-scanner \ + -Dsonar.projectKey=lifesub-web \ + -Dsonar.sources=src \ + -Dsonar.tests=src \ + -Dsonar.test.inclusions=src/**/*.test.js,src/**/*.test.jsx \ + -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info + """ + } + } + + timeout(time: 10, unit: 'MINUTES') { + def qg = waitForQualityGate() + if (qg.status != 'OK') { + error "Pipeline aborted due to quality gate failure: ${qg.status}" + } + } + } + stage("Setup AKS") { container('azure-cli') { withCredentials([azureServicePrincipal('azure-credentials')]) { diff --git a/deployment/Jenkinsfile_SonarQube b/deployment/Jenkinsfile_SonarQube deleted file mode 100644 index c6cf160..0000000 --- a/deployment/Jenkinsfile_SonarQube +++ /dev/null @@ -1,137 +0,0 @@ -def PIPELINE_ID = "${env.BUILD_NUMBER}" - -def getImageTag() { - def dateFormat = new java.text.SimpleDateFormat('yyyyMMddHHmmss') - def currentDate = new Date() - return dateFormat.format(currentDate) -} - -podTemplate( - label: "${PIPELINE_ID}", - serviceAccount: 'jenkins', - containers: [ - containerTemplate(name: 'node', image: 'node:20-slim', ttyEnabled: true, command: 'cat'), - containerTemplate(name: 'podman', image: "mgoltzsche/podman", ttyEnabled: true, command: 'cat', privileged: true), - containerTemplate(name: 'azure-cli', image: 'hiondal/azure-kubectl:latest', command: 'cat', ttyEnabled: true), - containerTemplate(name: 'envsubst', image: "hiondal/envsubst", command: 'sleep', args: '1h'), - containerTemplate(name: 'sonar-scanner', image: 'sonarsource/sonar-scanner-cli:latest', command: 'cat', ttyEnabled: true) - ], - volumes: [ - emptyDirVolume(mountPath: '/root/.azure', memory: false), - emptyDirVolume(mountPath: '/opt/sonar-scanner/.sonar/cache', memory: false) - ] -) { - node(PIPELINE_ID) { - def props - def imageTag = getImageTag() - def manifest = "deploy.yaml" - def namespace - def sonarScannerHome = '/opt/sonar-scanner' - - stage("Get Source") { - checkout scm - props = readProperties file: "deployment/deploy_env_vars" - namespace = "${props.namespace}" - } - - stage('Code Analysis & Quality Gate') { - container('node') { - sh "npm install" - sh "npm test -- --coverage --passWithNoTests" //test code 없어도 통과되게 함 - } - - container('sonar-scanner') { - withSonarQubeEnv('SonarQube') { - sh """ - ${sonarScannerHome}/bin/sonar-scanner \ - -Dsonar.projectKey=lifesub-web \ - -Dsonar.sources=src \ - -Dsonar.tests=src \ - -Dsonar.test.inclusions=src/**/*.test.js,src/**/*.test.jsx \ - -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info - """ - } - } - - timeout(time: 10, unit: 'MINUTES') { - def qg = waitForQualityGate() - if (qg.status != 'OK') { - error "Pipeline aborted due to quality gate failure: ${qg.status}" - } - } - } - - stage("Setup AKS") { - container('azure-cli') { - withCredentials([azureServicePrincipal('azure-credentials')]) { - sh """ - az login --service-principal -u \$AZURE_CLIENT_ID -p \$AZURE_CLIENT_SECRET -t \$AZURE_TENANT_ID - az aks get-credentials --resource-group ictcoe-edu --name ${props.teamid}-aks --overwrite-existing - kubectl create namespace ${namespace} --dry-run=client -o yaml | kubectl apply -f - - """ - } - } - } - - stage('Build & Push Image') { - container('podman') { - withCredentials([usernamePassword( - credentialsId: 'acr-credentials', - usernameVariable: 'USERNAME', - passwordVariable: 'PASSWORD' - )]) { - def imagePath = "${props.registry}/${props.image_org}/lifesub-web:${imageTag}" - - sh """ - podman login ${props.registry} --username \$USERNAME --password \$PASSWORD - - podman build \ - --build-arg PROJECT_FOLDER="." \ - --build-arg REACT_APP_MEMBER_URL="${props.react_app_member_url}" \ - --build-arg REACT_APP_MYSUB_URL="${props.react_app_mysub_url}" \ - --build-arg REACT_APP_RECOMMEND_URL="${props.react_app_recommend_url}" \ - --build-arg BUILD_FOLDER="deployment" \ - --build-arg EXPORT_PORT="${props.export_port}" \ - -f deployment/Dockerfile-lifesub-web \ - -t ${imagePath} . - - podman push ${imagePath} - """ - } - } - } - - stage('Generate & Apply Manifest') { - container('envsubst') { - sh """ - export namespace=${namespace} - export lifesub_web_image_path=${props.registry}/${props.image_org}/lifesub-web:${imageTag} - export replicas=${props.replicas} - export export_port=${props.export_port} - export resources_requests_cpu=${props.resources_requests_cpu} - export resources_requests_memory=${props.resources_requests_memory} - export resources_limits_cpu=${props.resources_limits_cpu} - export resources_limits_memory=${props.resources_limits_memory} - - envsubst < deployment/${manifest}.template > deployment/${manifest} - cat deployment/${manifest} - """ - } - - container('azure-cli') { - sh """ - kubectl apply -f deployment/${manifest} - - echo "Waiting for deployment to be ready..." - kubectl -n ${namespace} wait --for=condition=available deployment/lifesub-web --timeout=300s - - echo "Waiting for service external IP..." - while [[ -z \$(kubectl -n ${namespace} get svc lifesub-web -o jsonpath='{.status.loadBalancer.ingress[0].ip}') ]]; do - sleep 5 - done - echo "Service external IP: \$(kubectl -n ${namespace} get svc lifesub-web -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" - """ - } - } - } -} \ No newline at end of file