Files
FrameTour-RenderWorker/Jenkinsfile
2025-09-24 11:38:17 +08:00

347 lines
12 KiB
Groovy

pipeline {
agent any
environment {
// 环境变量
PYTHON_VERSION = '3.9'
VENV_NAME = 'venv'
TEST_REPORTS_DIR = 'test-reports'
COVERAGE_DIR = 'coverage-reports'
// 设置Python模块路径
PYTHONPATH = "${WORKSPACE}"
}
stages {
stage('Preparation') {
steps {
script {
// 清理工作空间
echo 'Cleaning workspace...'
deleteDir()
// 检出代码
checkout scm
// 创建报告目录
sh """
mkdir -p ${TEST_REPORTS_DIR}
mkdir -p ${COVERAGE_DIR}
"""
}
}
}
stage('Environment Setup') {
steps {
script {
echo 'Setting up Python environment...'
sh """
# 创建虚拟环境
python${PYTHON_VERSION} -m venv ${VENV_NAME}
# 激活虚拟环境并安装依赖
. ${VENV_NAME}/bin/activate
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/simple
# 设置PYTHONPATH
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 升级pip
pip install --upgrade pip
# 安装项目依赖
pip install -r requirements.txt
# 安装测试依赖
pip install -r requirements-test.txt
# 验证FFmpeg可用性
which ffmpeg || echo "Warning: FFmpeg not found, integration tests may be skipped"
"""
}
}
}
stage('Code Quality Check') {
parallel {
stage('Linting') {
steps {
script {
echo 'Running code linting...'
sh """
. ${VENV_NAME}/bin/activate
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 运行flake8检查(使用项目配置.flake8)
flake8 entity/ services/ --output-file=${TEST_REPORTS_DIR}/flake8-report.txt --tee || true
# 运行black格式检查
black --check --diff --line-length 88 entity/ services/ > ${TEST_REPORTS_DIR}/black-report.txt || true
"""
}
}
}
stage('Type Checking') {
steps {
script {
echo 'Running type checking with mypy...'
sh """
. ${VENV_NAME}/bin/activate
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 运行mypy类型检查
mypy --explicit-package-bases services/ entity/ > ${TEST_REPORTS_DIR}/mypy-report.txt || true
"""
}
}
}
}
post {
always {
// 发布代码质量报告(等待所有并行任务完成后统一发布)
publishHTML([
allowMissing: true,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: TEST_REPORTS_DIR,
reportFiles: 'flake8-report.txt,black-report.txt,mypy-report.txt',
reportName: 'Code Quality Report'
])
}
}
}
stage('Unit Tests') {
steps {
script {
echo 'Running unit tests...'
sh """
. ${VENV_NAME}/bin/activate
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 运行单元测试
pytest tests/test_effects/ tests/test_ffmpeg_builder/ \\
--junitxml=${TEST_REPORTS_DIR}/unit-tests.xml \\
--html=${TEST_REPORTS_DIR}/unit-tests.html \\
--self-contained-html \\
--cov=entity \\
--cov=services \\
--cov-report=xml:${COVERAGE_DIR}/unit-coverage.xml \\
--cov-branch \\
-v \\
-m "not integration"
"""
}
}
post {
always {
// 发布单元测试结果
junit "${TEST_REPORTS_DIR}/unit-tests.xml"
// 发布HTML测试报告
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: TEST_REPORTS_DIR,
reportFiles: 'unit-tests.html',
reportName: 'Unit Tests Report'
])
}
}
}
stage('Integration Tests') {
when {
// 只在有FFmpeg的环境中运行集成测试
expression {
return sh(
script: 'which ffmpeg',
returnStatus: true
) == 0
}
}
steps {
script {
echo 'Running integration tests...'
sh """
. ${VENV_NAME}/bin/activate
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 运行集成测试
pytest tests/test_integration/ \\
--junitxml=${TEST_REPORTS_DIR}/integration-tests.xml \\
--html=${TEST_REPORTS_DIR}/integration-tests.html \\
--self-contained-html \\
--cov=entity \\
--cov=services \\
--cov-report=xml:${COVERAGE_DIR}/integration-coverage.xml \\
--cov-branch \\
--timeout=300 \\
-v \\
-m "integration"
"""
}
}
post {
always {
// 发布集成测试结果
junit "${TEST_REPORTS_DIR}/integration-tests.xml"
// 发布HTML集成测试报告
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: TEST_REPORTS_DIR,
reportFiles: 'integration-tests.html',
reportName: 'Integration Tests Report'
])
}
}
}
stage('Complete Test Suite') {
steps {
script {
echo 'Running complete test suite with coverage...'
sh """
. ${VENV_NAME}/bin/activate
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 运行完整测试套件
pytest tests/ \\
--junitxml=${TEST_REPORTS_DIR}/all-tests.xml \\
--html=${TEST_REPORTS_DIR}/all-tests.html \\
--self-contained-html \\
--cov=entity \\
--cov=services \\
--cov-report=xml:${COVERAGE_DIR}/coverage.xml \\
--cov-report=term-missing \\
--cov-branch \\
--cov-fail-under=70 \\
-v
"""
}
}
post {
always {
// 发布完整测试结果
junit "${TEST_REPORTS_DIR}/all-tests.xml"
// 发布代码覆盖率报告
publishCoverage([
adapters: [
[
mergeToOneReport: true,
path: "${COVERAGE_DIR}/coverage.xml"
]
],
sourceFileResolver: [
[
level: 'NEVER_STORE'
]
]
])
// 发布完整测试HTML报告
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: TEST_REPORTS_DIR,
reportFiles: 'all-tests.html',
reportName: 'Complete Test Report'
])
}
}
}
stage('Performance Tests') {
when {
// 只在主分支或发布分支运行性能测试
anyOf {
branch 'master'
branch 'main'
branch 'release/*'
}
}
steps {
script {
echo 'Running performance tests...'
sh """
. ${VENV_NAME}/bin/activate
export PYTHONPATH=\${PWD}:\$PYTHONPATH
# 运行性能测试
RUN_STRESS_TESTS=1 pytest tests/test_integration/test_ffmpeg_execution.py::TestFFmpegExecution::test_stress_test_large_effects_chain \\
--benchmark-json=${TEST_REPORTS_DIR}/benchmark.json \\
--html=${TEST_REPORTS_DIR}/performance-tests.html \\
--self-contained-html \\
-v \\
-m "stress" || true
"""
}
}
post {
always {
// 发布性能测试报告
publishHTML([
allowMissing: true,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: TEST_REPORTS_DIR,
reportFiles: 'performance-tests.html',
reportName: 'Performance Tests Report'
])
}
}
}
}
post {
always {
// 清理虚拟环境
sh """
rm -rf ${VENV_NAME}
"""
// 归档测试报告
archiveArtifacts artifacts: "${TEST_REPORTS_DIR}/**/*", allowEmptyArchive: true
archiveArtifacts artifacts: "${COVERAGE_DIR}/**/*", allowEmptyArchive: true
}
success {
echo 'All tests passed successfully!'
// 发送成功通知
script {
if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'main') {
// 这里可以添加Slack、邮件或其他通知
echo 'Sending success notification...'
}
}
}
failure {
echo 'Tests failed!'
// 发送失败通知
script {
// 这里可以添加Slack、邮件或其他通知
echo 'Sending failure notification...'
}
}
unstable {
echo 'Tests completed with warnings!'
}
cleanup {
// 清理临时文件
deleteDir()
}
}
}