pipeline { agent none options { timestamps() disableConcurrentBuilds() skipDefaultCheckout() // stage별 agent의 자동 SCM checkout 방지 (Deploy 노드는 git 접근 불필요, unstash로만 WAR 수신) buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20')) } environment { GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new' WEBHOOK_URL = 'http://172.30.1.50:18000/api/hooks/01ba51b01d3c4c98ae8f3183a23a84ed713197857d024b5da4f303458195eb32' } stages { stage('Build (djb-vm)') { agent { label 'djb-vm' } environment { JAVA_HOME = '/apps/opts/jdk8' GRADLE_HOME = '/apps/opts/gradle-8.7' GRADLE_USER_HOME = '/apps/opts/gradle-home' NODE_HOME = '/apps/opts/node-v24' PATH = "/apps/opts/jdk8/bin:/apps/opts/gradle-8.7/bin:/apps/opts/node-v24/bin:/apps/opts/bin:${env.PATH}" } stages { stage('Checkout') { steps { checkout scm } } stage('Checkout dependencies') { steps { sh ''' set -eu cd "$WORKSPACE/.." mkdir -p eapim-online for REPO in elink-online-core elink-online-core-jpa elink-online-transformer elink-online-common elink-online-emsclient; do TARGET="eapim-online/$REPO" if [ ! -d "$TARGET/.git" ]; then rm -rf "$TARGET" git clone --depth=1 --branch master \ "ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \ "$TARGET" else git -C "$TARGET" fetch --depth=1 origin master git -C "$TARGET" reset --hard origin/master git -C "$TARGET" clean -fdx fi done for REPO in elink-portal-common eapim-admin-djb; do if [ ! -d "$REPO/.git" ]; then rm -rf "$REPO" git clone --depth=1 --branch master \ "ssh://git@172.30.1.50:2222/djb-eapim/$REPO.git" \ "$REPO" else git -C "$REPO" fetch --depth=1 origin master git -C "$REPO" reset --hard origin/master git -C "$REPO" clean -fdx fi done ''' } } stage('Verify toolchain') { steps { sh ''' set -eu java -version gradle --version ''' } } stage('Build WAR') { steps { sh 'gradle clean build -x test --no-daemon -Pprofile=weblogic' } post { success { sh ''' set -eu cd build/libs sha256sum eapim-admin.war > eapim-admin.war.sha256 ''' archiveArtifacts artifacts: 'build/libs/eapim-admin.war,build/libs/eapim-admin.war.sha256', fingerprint: true stash name: 'war', includes: 'build/libs/eapim-admin.war' } } } } } stage('Deploy (weblogic)') { agent { label 'weblogic' } environment { JENKINS_NODE_COOKIE = 'dontKillMe' // background weblogic를 빌드 종료 시 죽이지 않게 WL_HOME = '/app/eapim/adminportal' WL_DEPLOY_DIR = '/app/eapim/adminportal' WL_WAR_NAME = 'eapim-admin.war' WL_HTTP_PORT = '39120' WL_NOHUP = '/logs/weblogic/domains/eapimDomain/nohup.emsSvr11.out' } stages { stage('Stop WebLogic') { steps { sh '"$WL_HOME/stopEms11.sh"' // 동기: 완전 종료까지 블록, 미기동 시에도 안전 } } stage('Deploy WAR') { steps { unstash 'war' sh ''' set -eu cp build/libs/eapim-admin.war "$WL_DEPLOY_DIR/$WL_WAR_NAME" ls -la "$WL_DEPLOY_DIR" ''' } } stage('Start WebLogic and readiness') { steps { sh ''' set -eu "$WL_HOME/startEms11.sh" # nohup & 로 백그라운드 기동, 즉시 리턴 DEADLINE=$(($(date +%s) + 300)) STATUS=000 while [ "$(date +%s)" -lt "$DEADLINE" ]; do STATUS=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 3 \ "http://localhost:$WL_HTTP_PORT/monitoring/loginForm.do" 2>/dev/null || echo "000") case "$STATUS" in 200|302|401) echo "Readiness OK (/monitoring/loginForm.do HTTP $STATUS)"; break ;; esac sleep 3 done case "$STATUS" in 200|302|401) ;; *) echo "Readiness failed within 300s, last HTTP=$STATUS" [ -f "$WL_NOHUP" ] && tail -120 "$WL_NOHUP" exit 1 ;; esac ''' } } } } } post { success { node('weblogic') { sh ''' set +e payload=$(printf '{"text":"[%s #%s](%s) SUCCESS"}' "$JOB_NAME" "$BUILD_NUMBER" "$BUILD_URL") curl -sS --fail --max-time 5 -H 'Content-Type: application/json' -X POST --data "$payload" "$WEBHOOK_URL" >/dev/null || echo "Webhook failed" ''' } } failure { node('weblogic') { sh ''' set +e payload=$(printf '{"text":"[%s #%s](%s) FAILURE"}' "$JOB_NAME" "$BUILD_NUMBER" "$BUILD_URL") curl -sS --fail --max-time 5 -H 'Content-Type: application/json' -X POST --data "$payload" "$WEBHOOK_URL" >/dev/null || echo "Webhook failed" ''' } } } }