# 파이프라인 설계 표준

> **버전**: 1.0.0  
> **최종 수정**: 2026-05-25

---

## 1. 개요

GUARDiA ITSM의 모든 CI/CD 파이프라인은 아래 8단계를 표준으로 한다.  
각 단계는 독립 스크립트로 분리되어 있으며, 실패 시 즉시 중단하고 ITSM에 결과를 통보한다.

```
┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  Stage 1     │───▶│  Stage 2     │───▶│  Stage 3     │───▶│  Stage 4     │
│  Checkout    │    │  Build       │    │  Test        │    │  Archive     │
└──────────────┘    └──────────────┘    └──────────────┘    └──────────────┘
                                                                      │
┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  Stage 8     │◀───│  Stage 7     │◀───│  Stage 6     │◀───│  Stage 5     │
│  ITSM        │    │  Health Check│    │  WAS Restart │    │  Deploy      │
│  Callback    │    │              │    │              │    │              │
└──────────────┘    └──────────────┘    └──────────────┘    └──────────────┘
```

---

## 2. 파이프라인 파라미터 표준

모든 파이프라인은 다음 파라미터를 공통으로 사용한다:

| 파라미터 | 타입 | 기본값 | 설명 |
|---------|------|-------|------|
| `ITSM_SESSION_ID` | String | — | GUARDiA 바이브 세션 ID |
| `ITSM_SR_ID` | String | — | 연결된 SR ID |
| `DEPLOY_ENV` | Choice | `dev` | 배포 환경 (dev/stg/prd) |
| `TARGET_SERVER` | String | — | 배포 대상 서버명 |
| `SKIP_TEST` | Boolean | `false` | 테스트 건너뜀 |
| `ROLLBACK_VERSION` | String | — | 롤백 버전 (빌드 번호) |

---

## 3. 환경별 파이프라인 정책

| 브랜치 | 환경 | 필수 단계 | 승인 게이트 | SonarQube |
|--------|------|----------|------------|-----------|
| `feature/*` | dev | Build + Test | 불필요 | 선택 |
| `develop` | dev/stg | Build + Test + Deploy | 불필요 | 선택 |
| `release/*` | stg | Full Pipeline | 불필요 | 필수 |
| `main` | prd | Full Pipeline | **필수** | 필수 |
| `hotfix/*` | prd | Full Pipeline (Fast) | **필수** | 선택 |

---

## 4. 단계별 표준 정의

### Stage 1: Checkout

```groovy
stage('Checkout') {
    steps {
        checkout([
            $class: 'GitSCM',
            branches: [[name: env.BRANCH_NAME ?: 'main']],
            extensions: [
                [$class: 'CleanBeforeCheckout'],
                [$class: 'CloneOption', depth: 1, shallow: true]
            ],
            userRemoteConfigs: [[
                url: env.GIT_REPO_URL,
                credentialsId: 'git-credentials'
            ]]
        ])
    }
}
```

### Stage 2: Build

```groovy
stage('Build') {
    steps {
        script {
            sh "bash ${WORKSPACE}/cicd/scripts/pipeline/build.sh"
        }
    }
    post {
        failure {
            sh "bash ${WORKSPACE}/cicd/scripts/notify/itsm_callback.sh FAILED '빌드 실패'"
        }
    }
}
```

**빌드 산출물 위치**:
- Java Maven: `target/*.jar`, `target/*.war`
- Java Gradle: `build/libs/*.jar`, `build/libs/*.war`
- Node.js: `dist/`, `build/`

### Stage 3: Test

```groovy
stage('Test') {
    when {
        expression { params.SKIP_TEST == false }
    }
    parallel {
        stage('Unit Test') {
            steps {
                sh "bash ${WORKSPACE}/cicd/scripts/pipeline/test.sh unit"
            }
        }
        stage('SonarQube') {
            when {
                anyOf {
                    branch 'release/*'
                    branch 'main'
                }
            }
            steps {
                withSonarQubeEnv('sonarqube') {
                    sh "bash ${WORKSPACE}/cicd/scripts/pipeline/test.sh sonar"
                }
                timeout(time: 10, unit: 'MINUTES') {
                    waitForQualityGate abortPipeline: true
                }
            }
        }
    }
}
```

### Stage 4: Archive

```groovy
stage('Archive') {
    steps {
        archiveArtifacts artifacts: '**/target/*.jar,**/target/*.war,**/build/libs/*.jar',
                         fingerprint: true,
                         allowEmptyArchive: false
    }
}
```

### Stage 5: Deploy

```groovy
stage('Deploy') {
    steps {
        withCredentials([sshUserPrivateKey(
            credentialsId: "ssh-${params.TARGET_SERVER}",
            keyFileVariable: 'SSH_KEY',
            usernameVariable: 'SSH_USER'
        )]) {
            sh """
                bash \${WORKSPACE}/cicd/scripts/pipeline/deploy.sh \
                    --server \${params.TARGET_SERVER} \
                    --env \${params.DEPLOY_ENV}
            """
        }
    }
}
```

### Stage 6: WAS Restart

```groovy
stage('WAS Restart') {
    steps {
        withCredentials([sshUserPrivateKey(
            credentialsId: "ssh-${params.TARGET_SERVER}",
            keyFileVariable: 'SSH_KEY',
            usernameVariable: 'SSH_USER'
        )]) {
            sh """
                bash \${WORKSPACE}/cicd/scripts/pipeline/was_restart.sh \
                    --server \${params.TARGET_SERVER} \
                    --was-type \${env.WAS_TYPE ?: 'tomcat'}
            """
        }
    }
    post {
        failure {
            sh "bash ${WORKSPACE}/cicd/scripts/pipeline/rollback.sh --reason 'WAS 재기동 실패'"
        }
    }
}
```

### Stage 7: Health Check

```groovy
stage('Health Check') {
    steps {
        retry(3) {
            sh """
                bash \${WORKSPACE}/cicd/scripts/pipeline/health_check.sh \
                    --url \${env.HEALTH_CHECK_URL} \
                    --timeout 60
            """
        }
    }
    post {
        failure {
            sh "bash ${WORKSPACE}/cicd/scripts/pipeline/rollback.sh --reason '헬스체크 실패'"
        }
    }
}
```

### Stage 8: ITSM Callback

```groovy
stage('ITSM Callback') {
    steps {
        sh """
            bash \${WORKSPACE}/cicd/scripts/notify/itsm_callback.sh \
                SUCCESS \
                "배포 완료 (빌드 #\${env.BUILD_NUMBER})"
        """
    }
    post {
        failure {
            echo 'ITSM 콜백 실패 — 수동 확인 필요'
        }
    }
}
```

---

## 5. 공통 post 블록

모든 파이프라인에 반드시 포함해야 하는 공통 후처리:

```groovy
post {
    always {
        // 워크스페이스 정리
        cleanWs(
            cleanWhenAborted: true,
            cleanWhenFailure: true,
            cleanWhenSuccess: true
        )
    }
    success {
        echo "파이프라인 성공: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
    }
    failure {
        sh """
            bash \${WORKSPACE}/cicd/scripts/notify/itsm_callback.sh \
                FAILED "파이프라인 실패: \${env.STAGE_NAME}"
        """
    }
    unstable {
        sh """
            bash \${WORKSPACE}/cicd/scripts/notify/itsm_callback.sh \
                UNSTABLE "테스트 불안정: \${env.STAGE_NAME}"
        """
    }
}
```

---

## 6. 승인 게이트 (운영 배포)

`main`, `hotfix/*` 브랜치의 운영 배포 시 승인 게이트를 거친다.

```groovy
stage('Production Approval') {
    when {
        anyOf {
            branch 'main'
            branch 'hotfix/*'
        }
    }
    steps {
        script {
            // ITSM에 승인 요청 발송
            sh "bash ${WORKSPACE}/cicd/scripts/notify/itsm_callback.sh PENDING_APPROVAL '운영 배포 승인 요청'"

            // 승인 대기 (30분 타임아웃)
            timeout(time: 30, unit: 'MINUTES') {
                input message: "운영 배포를 승인하시겠습니까?",
                      ok: "배포 승인",
                      submitterParameter: "APPROVER"
            }
        }
    }
}
```

---

## 7. 롤백 정책

| 단계 | 자동 롤백 | 조건 |
|------|----------|------|
| WAS Restart | ✓ | WAS 기동 후 60초 내 응답 없음 |
| Health Check | ✓ | HTTP 상태코드 != 200 (3회 재시도 후) |
| 수동 롤백 | — | `!rollback` 봇 명령 또는 Jenkins 수동 트리거 |

롤백 파이프라인 파라미터:
- `ROLLBACK_VERSION`: 이전 빌드 번호 (빌드 번호 = 아티팩트 버전)
- `ROLLBACK_REASON`: 롤백 사유 (ITSM 등록용)

---

## 8. 파이프라인 타임아웃 표준

| 단계 | 타임아웃 | 비고 |
|------|---------|------|
| Checkout | 5분 | |
| Build | 30분 | 대형 프로젝트 60분 허용 |
| Test | 20분 | 단위 테스트 기준 |
| SonarQube | 10분 | Quality Gate 대기 포함 |
| Archive | 5분 | |
| Deploy | 10분 | rsync/SCP 전송 |
| WAS Restart | 5분 | |
| Health Check | 5분 | 3회 재시도 포함 |
| 전체 파이프라인 | 90분 | 초과 시 강제 중단 |

```groovy
options {
    timeout(time: 90, unit: 'MINUTES')
    buildDiscarder(logRotator(numToKeepStr: '30'))
    disableConcurrentBuilds()
}
```

---

## 9. 환경변수 표준

파이프라인에서 사용하는 환경변수는 Jenkins → Manage Jenkins → System → Global properties 에 등록한다.

| 변수명 | 용도 | 예시 |
|-------|------|------|
| `ITSM_URL` | GUARDiA ITSM API URL | `http://itsm.agency.go.kr:8000` |
| `ITSM_CALLBACK_URL` | 파이프라인 결과 콜백 URL | `${ITSM_URL}/api/vibe/callback` |
| `SONAR_HOST_URL` | SonarQube 서버 URL | `http://sonar.agency.go.kr:9000` |
| `ARTIFACT_REPO` | 아티팩트 저장소 | `/opt/artifacts` |
| `SCRIPTS_ROOT` | 파이프라인 스크립트 루트 | `/var/lib/jenkins/scripts` |

---

## 10. 빌드 번호 & 아티팩트 버전

```groovy
environment {
    // 아티팩트 버전 = 브랜치명 + 빌드번호 + 커밋 해시 앞 8자리
    APP_VERSION = "${env.BRANCH_NAME}-${env.BUILD_NUMBER}-${env.GIT_COMMIT[0..7]}"
    // 배포 대상 파일명
    ARTIFACT_NAME = "${env.JOB_NAME}-${APP_VERSION}.jar"
}
```
