pipeline { agent any environment { // Credentials ORACLE_DSN = credentials('oracle-dsn') ORACLE_USER = credentials('oracle-user') ORACLE_PASSWORD = credentials('oracle-password') TELEGRAM_BOT_TOKEN = credentials('telegram-bot-token') GITEA_URL = 'https://gittea.cloud-handson.com' GITEA_USER = 'joungmin' GITEA_TOKEN = credentials('gitea-token') } stages { // ===================================================== // STAGE 0: PREPARATION (가상환경 생성 및 패키지 설치) // ===================================================== stage('Preparation') { steps { echo '📦 Preparing Python environment...' sh ''' python3 -m venv venv . venv/bin/activate pip install --upgrade pip pip install pylint flake8 black isort bandit semgrep safety detect-secrets pytest pytest-cov oracledb ''' } } // ===================================================== // STAGE 1: CODE QUALITY // ===================================================== stage('Code Quality: Linting') { steps { echo '📋 Running linters...' sh ''' . venv/bin/activate pylint --rcfile=.pylintrc *.py --output-format=json > pylint-report.json || true flake8 . --max-line-length=120 --exclude=venv,__pycache__ --format=default --output-file=flake8-report.txt || true black --check . || true isort --check-only --profile=black . || true ''' } post { always { // Warnings Next Generation 플러그인이 설치되어 있어야 합니다. recordIssues( tools: [ pyLint(pattern: 'pylint-report.json'), flake8(pattern: 'flake8-report.txt') ] ) } } } stage('Security: Static Analysis') { steps { echo '🔒 Running static security analysis...' sh ''' . venv/bin/activate bandit -r . -f json -o bandit-report.json || true semgrep --config=auto --json --output=semgrep-report.json || true safety check -r requirements.txt --json --output=safety-report.json || true detect-secrets scan --exclude-files '.git/.*' --output-format=json > secrets-report.json || true ''' } } stage('Unit Tests') { steps { echo '🧪 Running unit tests...' sh ''' . venv/bin/activate pytest tests/ -v --junitxml=test-results.xml --cov=. --cov-report=xml || true ''' } post { always { junit 'test-results.xml' } } } stage('Build') { steps { echo '📦 Building application...' sh ''' . venv/bin/activate pip freeze > requirements.locked.txt ''' } post { success { archiveArtifacts artifacts: '*.py,requirements*.txt', allowEmptyArchive: true } } } stage('Deploy to Staging') { when { branch 'main' } steps { echo '🚀 Deploying to staging...' // SSH 설정이 되어 있는 경우에만 작동합니다. echo 'Deployment steps would go here.' } } } post { always { echo '📊 Pipeline completed' script { def statusIcon = currentBuild.currentResult == 'SUCCESS' ? '✅' : '❌' // 텔레그램 메시지 전송 (Bad Substitution 방지를 위해 홑따옴표 사용) sh """ curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ -d "chat_id=@your_channel" \ -d "text=${statusIcon} Pipeline: ${env.JOB_NAME} #${env.BUILD_NUMBER} completed." """ cleanWs() } } failure { echo '💥 Build failed!' // 로컬 메일 서버가 없으면 이 부분에서 에러가 날 수 있으므로 주의하세요. // mail to: 'joungmin@example.com', subject: "Failed: ${env.JOB_NAME}", body: "Check ${env.BUILD_URL}" } } }