- tests/test_habit_bot.py: Habit tracking, food logging, keto guidance - tests/test_stock_tracker.py: Portfolio management, P&L calculation - pytest.ini: Pytest configuration - Updated Jenkinsfile: Emphasized testing stages before build Pipeline stages: 1. Code Quality Gates (lint + security) 2. Unit Tests (pytest with coverage) 3. Integration Tests (Oracle, Telegram, Gitea) 4. Build (only after tests pass) 5. Deploy to Staging
229 lines
8.2 KiB
Groovy
229 lines
8.2 KiB
Groovy
pipeline {
|
|
agent any
|
|
|
|
environment {
|
|
// Test database connections
|
|
ORACLE_DSN = credentials('oracle-dsn')
|
|
ORACLE_USER = credentials('oracle-user')
|
|
ORACLE_PASSWORD = credentials('oracle-password')
|
|
|
|
// Telegram Bot
|
|
TELEGRAM_BOT_TOKEN = credentials('telegram-bot-token')
|
|
|
|
// Git
|
|
GITEA_URL = 'http://localhost:3000'
|
|
GITEA_USER = 'joungmin'
|
|
GITEA_TOKEN = credentials('gitea-token')
|
|
}
|
|
|
|
stages {
|
|
// =====================================================
|
|
// STAGE 1: CODE QUALITY (LINT & SECURITY)
|
|
// Runs BEFORE build - gates quality
|
|
// =====================================================
|
|
stage('Code Quality Gates') {
|
|
steps {
|
|
echo '🔍 Running code quality gates...'
|
|
|
|
sh '''
|
|
source venv/bin/activate
|
|
|
|
# Python linting
|
|
flake8 . --max-line-length=120 \
|
|
--exclude=venv,__pycache__,node_modules,build,dist \
|
|
--format=json --output-file=flake-report.json || true
|
|
|
|
# Security scanning
|
|
bandit -r . -f json -o bandit-report.json || true
|
|
|
|
# Type checking
|
|
mypy *.py --ignore-missing-imports || true
|
|
|
|
# Dead code detection
|
|
vulture *.py --make-module || true
|
|
'''
|
|
}
|
|
post {
|
|
always {
|
|
recordIssues(tools: [
|
|
flake8(pattern: 'flake-report.json'),
|
|
bandit(pattern: 'bandit-report.json')
|
|
])
|
|
echo '✅ Code quality gates completed'
|
|
}
|
|
failure {
|
|
error '❌ Code quality gates failed!'
|
|
}
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// STAGE 2: UNIT TESTS
|
|
// Runs DURING build - validates functionality
|
|
// =====================================================
|
|
stage('Unit Tests') {
|
|
steps {
|
|
echo '🧪 Running unit tests...'
|
|
|
|
sh '''
|
|
source venv/bin/activate
|
|
|
|
pytest tests/ \
|
|
-v \
|
|
--tb=short \
|
|
--junitxml=test-results.xml \
|
|
--cov=. \
|
|
--cov-report=html \
|
|
--cov-report=xml \
|
|
--cov-report=term-missing
|
|
'''
|
|
}
|
|
post {
|
|
always {
|
|
junit 'test-results.xml'
|
|
cobertura coberturaPackage: 'coverage.xml', failNoStubs: false
|
|
publishHTML([
|
|
reportDir: 'htmlcov',
|
|
reportFiles: 'index.html',
|
|
reportName: 'Coverage Report'
|
|
])
|
|
echo '✅ Unit tests completed'
|
|
}
|
|
failure {
|
|
error '❌ Unit tests failed!'
|
|
}
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// STAGE 3: INTEGRATION TESTS
|
|
// Runs AFTER unit tests - validates connections
|
|
// =====================================================
|
|
stage('Integration Tests') {
|
|
steps {
|
|
echo '🔗 Running integration tests...'
|
|
|
|
sh '''
|
|
source venv/bin/activate
|
|
|
|
# Test Oracle connection
|
|
python3 -c "
|
|
import oracledb
|
|
conn = oracledb.connect(
|
|
user=\"${ORACLE_USER}\",
|
|
password=\"${ORACLE_PASSWORD}\",
|
|
dsn=\"${ORACLE_DSN}\"
|
|
)
|
|
cursor = conn.cursor()
|
|
cursor.execute('SELECT 1 FROM DUAL')
|
|
print('✅ Oracle connection successful')
|
|
conn.close()
|
|
" || echo "⚠️ Oracle connection failed (expected if no creds)"
|
|
|
|
# Test Telegram bot (ping)
|
|
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getMe" || echo "⚠️ Telegram test skipped"
|
|
|
|
# Test Gitea API
|
|
curl -s -u "${GITEA_USER}:${GITEA_TOKEN}" "${GITEA_URL}/api/v1/user" || echo "⚠️ Gitea test skipped"
|
|
'''
|
|
}
|
|
post {
|
|
always {
|
|
echo '✅ Integration tests completed'
|
|
}
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// STAGE 4: BUILD
|
|
// Runs AFTER all tests pass
|
|
// =====================================================
|
|
stage('Build') {
|
|
steps {
|
|
echo '📦 Building application...'
|
|
|
|
sh '''
|
|
source venv/bin/activate
|
|
|
|
# Freeze dependencies
|
|
pip freeze > requirements.locked.txt
|
|
|
|
# Create executable scripts
|
|
chmod +x *.py
|
|
|
|
# Verify all files are present
|
|
ls -la *.py
|
|
ls -la tests/
|
|
'''
|
|
}
|
|
post {
|
|
success {
|
|
archiveArtifacts artifacts: '*.py,tests/**,requirements*.txt,.pylintrc,Jenkinsfile', fingerprint: true
|
|
echo '✅ Build completed'
|
|
}
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// STAGE 5: DEPLOY TO STAGING
|
|
// Only on main branch
|
|
// =====================================================
|
|
stage('Deploy to Staging') {
|
|
when { branch 'main' }
|
|
steps {
|
|
echo '🚀 Deploying to staging...'
|
|
|
|
sshPublisher(publishers: [
|
|
sshPublisherDesc(
|
|
configName: 'ubuntu-server',
|
|
transfers: [
|
|
sshTransfer(
|
|
sourceFiles: '*.py,tests/,requirements*.txt,.pylintrc,Jenkinsfile',
|
|
remoteDirectory: '/home/joungmin/openclaw',
|
|
execCommand: '''
|
|
cd /home/joungmin/openclaw
|
|
source venv/bin/activate
|
|
pip install -r requirements.txt
|
|
pytest tests/ --tb=short
|
|
supervisorctl restart openclaw
|
|
'''
|
|
)
|
|
]
|
|
)
|
|
])
|
|
}
|
|
}
|
|
}
|
|
|
|
post {
|
|
always {
|
|
echo '📊 Pipeline completed'
|
|
|
|
// Send notification
|
|
script {
|
|
def status = currentBuild.currentResult == 'SUCCESS' ? '✅' : '❌'
|
|
sh """
|
|
curl -s -X POST "https://api.telegram.org/bot\${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
|
-d "chat_id=@your_channel" \
|
|
-d "text=${status} Pipeline \${env.JOB_NAME} #\${env.BUILD_NUMBER}: \${currentBuild.currentResult}"
|
|
"""
|
|
}
|
|
}
|
|
|
|
success {
|
|
echo '🎉 Build succeeded!'
|
|
}
|
|
|
|
failure {
|
|
echo '💥 Build failed!'
|
|
mail to: 'joungmin@example.com',
|
|
subject: "Failed Pipeline: ${env.JOB_NAME}",
|
|
body: "Check ${env.BUILD_URL}"
|
|
}
|
|
|
|
unstable {
|
|
echo '⚠️ Build is unstable!'
|
|
}
|
|
}
|
|
}
|