引言

在现代软件开发中,持续集成和持续部署(CI/CD)已成为标准实践。对于需要在多个平台上运行的应用程序,确保代码在不同操作系统上的兼容性尤为重要。本文将介绍如何使用Jenkins和Jenkinsfile创建跨平台(Windows和Linux)的自动化测试流水线,帮助开发团队快速发现并解决平台特定的问题。

本文环境为 Windows11 和 WSL2。

在 AI 的辅助下,根据需求,可以快速生成一份 Jenkinsfile,再结合实际应用场景,不断地迭代完善。

效果展示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

环境搭建:在WSL2中配置Jenkins

Docker Compose配置

首先,我们使用Docker在WSL2环境中部署Jenkins。以下是docker-compose.yml配置文件:

version: '3.8'
services:
  jenkins:
    image: jenkins/jenkins:lts-jdk17
    container_name: jenkins
    ports:
      - "8081:8080"
      - "50000:50000"
    volumes:
      - jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
    user: "1000:1000"  # WSL2中通常使用1000:1000
    environment:
      - JENKINS_HOME=/var/jenkins_home
      - JAVA_OPTS=-Xms512m -Xmx1g
      - JENKINS_OPTS=--httpPort=8080
      - TZ=Asia/Shanghai
      - DOCKER_HOST=unix:///var/run/docker.sock
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8081/login || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 90s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: '2.0'
        reservations:
          memory: 512M
          cpus: '0.5'
    restart: unless-stopped
    networks:
      - jenkins

networks:
  jenkins:
    driver: bridge

volumes:
  jenkins_home:
    driver: local

启动Jenkins容器

确保当前用户已添加到docker组,然后启动Jenkins容器:

sudo usermod -aG docker $USER
docker-compose up -d

初始化Jenkins

启动后,可以通过以下命令查看初始管理员密码:

docker logs -f jenkins

系统会生成一个初始密码,如:b91fb528a2ec464288d95a7783cc4fac,用于首次登录Jenkins。

安装必要插件

为了支持我们的流水线,需要安装以下插件:

  1. Git Parameter Plug-In:用于在构建时选择Git分支
  2. Allure Jenkins Plugin:用于生成测试报告

对于Allure插件,还需要在Jenkins的"Manage Jenkins"-“Tools”-"Allure Commandline installations"中添加Allure命令行工具。

跨平台测试流水线设计

我们的目标是创建两个独立但结构相似的流水线,分别针对Windows和Linux平台。这样可以:

  1. 并行测试不同平台,加快反馈速度
  2. 隔离平台特定的问题
  3. 确保代码在所有目标平台上正常工作

流水线共同特性

两个流水线共享以下特性:

  • 使用Git参数插件选择测试分支
  • 可配置测试目标路径
  • 自动检测代码变更并触发构建
  • 生成Allure测试报告
  • 构建命名包含平台、分支和提交信息
  • 错误处理和清理机制

Linux流水线详解

基本结构

pipeline {
    agent {
        label 'linux_label'
    }

    // 配置触发器 - 代码更新后自动触发
    triggers {
        // 轮询 SCM,检查代码变更(每2分钟检查一次,错开Windows流水线的触发时间)
        pollSCM('1-59/2 * * * *')
    }

    // 定义可配置的参数
    parameters {
        // 分支选择参数
        gitParameter(name: 'BRANCH', /* 其他配置 */)
        // 测试目标参数
        string(name: 'TEST_TARGET', defaultValue: 'tests/')
    }
    
    // 各个阶段...
}

关键阶段

  1. 平台检测:确认当前运行环境
stage('Platform Detection') {
    steps {
        script {
            echo "=== Linux Platform Pipeline ==="
            env.CURRENT_PLATFORM = 'linux'
        }
    }
}
  1. 获取Git信息:获取当前提交的详细信息
stage('Get Git Info') {
    steps {
        script {
            // 获取Git提交信息的代码
            gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
            gitMessage = sh(returnStdout: true, script: 'git log -1 --pretty=format:"%s"').trim()
            
            env.GIT_COMMIT_SHORT = gitCommit.length() > 7 ? gitCommit.take(7) : gitCommit
            env.GIT_COMMIT_MESSAGE = gitMessage
        }
    }
}
  1. 设置构建名称:使用平台、分支和提交信息创建有意义的构建名称
stage('Set Build Name') {
    steps {
        script {
            // 获取触发用户
            def user = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause)?.userId ?: "Auto-Trigger"
            
            // 处理分支名称
            def branch_name = params.BRANCH ?: (env.GIT_BRANCH ? env.GIT_BRANCH.split('/').last() : 'main')
            
            // 设置构建名称和描述
            currentBuild.displayName = "#${BUILD_NUMBER}-Linux-${branch_name}-${env.GIT_COMMIT_SHORT}-${user}"
            currentBuild.description = "Platform: Linux | Branch: ${branch_name} | Commit: ${env.GIT_COMMIT_MESSAGE}"
        }
    }
}
  1. 环境设置:配置Linux测试环境
stage('Setup Linux Environment') {
    steps {
        script {
            sh '''
                echo "=== Conda Environment Setup ==="
                eval "$(conda shell.bash hook 2>/dev/null)" > /dev/null
                conda activate env3.10
                echo "Python: $(which python) ($(python --version))"
            '''
        }
    }
}
  1. 运行单元测试:执行测试并生成报告
stage('Run Unit Tests on Linux') {
    steps {
        script {
            // 清理之前的测试结果
            sh '''
                rm -rf allure-results
                mkdir -p allure-results
            '''
            
            // 执行测试
            try {
                sh '''
                    eval "$(conda shell.bash hook 2>/dev/null)" > /dev/null
                    conda activate env3.10
                    python -m pytest ''' + params.TEST_TARGET + ''' -v -s --alluredir=allure-results
                '''
                
                currentBuild.result = 'SUCCESS'
            } catch (Exception e) {
                currentBuild.result = 'UNSTABLE'
                echo "Unit tests have failed test cases on Linux: ${e.message}"
            }
        }
    }
    post {
        always {
            // 发布测试报告
            allure results: [[path: 'allure-results']]
        }
    }
}

Windows流水线详解

关键差异

Windows流水线与Linux流水线结构相似,但有以下关键差异:

  1. 使用不同的执行器
agent {
    label 'win_label'
}
  1. 不同的命令执行方式:使用bat而不是sh
// Linux中
gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()

// Windows中
gitCommit = bat(returnStdout: true, script: '@git rev-parse HEAD 2>nul').trim()
  1. Windows特定的环境设置
stage('Setup Windows Environment') {
    steps {
        script {
            bat '''
                echo Checking Python environment on Windows...
                where python
                python --version

                echo Getting virtual environment activation script path...
                python -c "import os, sys; print(os.path.join(os.path.dirname(sys.executable), 'Scripts', 'activate.bat'), end='')" > activate_path.txt
            '''
        }
    }
}
  1. Windows特定的测试执行
bat '''
    echo Starting unit tests on Windows...
    set /p ACTIVATE_PATH=<activate_path.txt
    call "%ACTIVATE_PATH%" envPy3.12
    python --version
    python -m pytest ''' + params.TEST_TARGET + ''' -v -s --alluredir=allure-results
'''
  1. Windows特定的文件操作
// Linux中
sh 'rm -rf allure-results'

// Windows中
bat 'if exist allure-results rmdir /s /q allure-results'

流水线高级特性

错开触发时间

为避免同时触发两个流水线导致资源竞争,我们错开了SCM轮询时间:

// Linux流水线
pollSCM('1-59/2 * * * *')  // 奇数分钟触发

// Windows流水线
pollSCM('H/2 * * * *')     // 每两分钟触发一次,时间由Jenkins决定

构建选项

两个流水线都配置了相同的构建选项:

options {
    // 保留构建日志的策略
    buildDiscarder(logRotator(numToKeepStr: '100', artifactNumToKeepStr: '50'))
    // 超时处理
    timeout(time: 60, unit: 'MINUTES')
    // 跳过默认的 checkout
    skipDefaultCheckout(false)
    // 时间戳
    timestamps()
}

构建后操作

根据构建结果执行不同的操作:

post {
    success {
        echo "Unit tests executed successfully! All test cases passed."
    }
    unstable {
        echo "Unit tests completed, but some test cases failed. Please check the test report."
    }
    failure {
        echo "Unit test execution failed. Please check build logs and test reports."
    }
    always {
        // 清理临时文件
    }
}

最佳实践与经验总结

  1. 平台特定代码隔离:将平台特定的命令和路径处理隔离在各自的流水线中
  2. 统一测试报告:使用Allure等工具统一不同平台的测试报告格式
  3. 错开触发时间:避免资源竞争
  4. 优雅处理失败:即使测试失败也生成报告,方便排查问题
  5. 清晰的构建命名:包含平台、分支和提交信息,便于快速识别
  6. 环境变量管理:使用环境变量传递信息,避免重复计算

常见问题及解决方案

在WSL环境中使用Jenkins时,可能会遇到一些网络或权限相关的问题。例如,在WSL命令行中无法下载agent.jar文件:

curl.exe -sO http://127.0.0.1:8081/jnlpJars/agent.jar  # 无法下载

这种情况可能是由于WSL的网络配置问题导致的,可以尝试从Windows下载后复制到WSL环境。

结论

通过使用Jenkins和Jenkinsfile创建跨平台测试流水线,我们可以:

  1. 自动化测试在不同平台上的执行
  2. 快速发现平台特定的兼容性问题
  3. 提高代码质量和可靠性
  4. 加速开发和发布周期

这种方法特别适合需要在多个平台上运行的应用程序,如跨平台桌面应用、库或框架。通过持续集成和自动化测试,开发团队可以更加专注于功能开发,同时保持高质量的代码库。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐