Jenkins 集成 QNX 编译、GTest 单元测试及权限配置全指南

本文基于实际项目场景(parkingplanningprocess 代码仓库开发、QNX 编译、产物自动上传至 Algorithm Integration 仓库),整理 Jenkins 从插件安装、环境配置、任务创建到权限分配、单元测试集成的完整流程,全程使用免费插件,可直接落地复用。已提前安装核心插件,无需额外付费,适配小团队协同开发需求。

一、前置准备:已安装的 Jenkins 插件(核心+可选)

本次配置已完成以下插件安装,无需重复操作,插件均为免费开源,可满足项目全流程需求:

核心必备插件(缺一不可)

  • Git Plugin:核心功能为拉取 parkingplanningprocess 代码仓库代码,支持分支、tag 拉取。

  • Git Parameter Plugin:关键插件,实现 Jenkins 网页端下拉选择分支或 tag,无需手动输入,提升操作便捷性。

  • Pipeline Plugin:流水线核心插件,通过 Jenkinsfile 实现构建流程的代码化、可维护、可版本化。

  • Pipeline: Git:配合 Pipeline 插件使用,实现流水线中 Git 相关操作(拉取代码、获取 commit 信息等)。

  • Credentials Plugin:管理 Git 账号密码、SSH 密钥等敏感信息,避免明文暴露,提升安全性。

  • SSH Agent Plugin:若使用 SSH 方式拉取/推送代码,该插件可自动加载 SSH 密钥,无需手动配置。

  • Timestamper:为 Jenkins 构建日志添加时间戳,便于定位构建过程中的问题,快速排查报错。

可选推荐插件(提升体验)

  • Generic Webhook Trigger:如需实现自动触发构建(如代码提交后自动构建),可启用该插件,支持通过 webhook 触发。

  • Build Name and Description Setter:美化构建名称和描述,可自定义构建显示信息(如分支名称、构建时间),便于快速识别构建记录。

二、Jenkins 环境前置要求

Jenkins 执行机需提前配置以下环境,确保构建流程正常运行:

  1. 安装 QNX 编译环境(如 qnx7xx),确保能正常运行项目根目录下的 Build.sh 编译脚本。

  2. 配置 Git 环境,确保 Jenkins 能正常 git clone、pull、push 两个核心仓库(parkingplanningprocess 和 Algorithm Integration)。

  3. 赋予 Jenkins 执行机对 Algorithm Integration 仓库的写权限(用于上传编译产物)。

  4. (可选)安装 Jenkins 中文插件 Localization: Chinese (Simplified),将界面汉化,降低操作门槛(安装后重启 Jenkins 即可生效)。

三、Jenkins 任务创建(Pipeline 流水线,推荐)

采用 Pipeline 流水线模式,通过 Jenkinsfile 固化构建流程,支持版本化管理,后续修改只需调整脚本,无需重复配置界面。

步骤 1:创建参数化构建(网页端选分支/tag)

  1. 新建任务 → 选择「Pipeline 流水线」,输入任务名称(如 parkingplanningprocess-build)。

  2. 勾选「参数化构建过程」,点击「添加参数」,选择「Git Parameter」。

  3. 配置 Git Parameter:

    • Name:填写 BRANCH_TAG(后续 Jenkinsfile 会引用该参数)。

    • Parameter Type:选择「Branch or Tag」,支持下拉选择分支或 tag。

    • Repository URL:填写 parkingplanningprocess 仓库的 Git 地址。

    • Default Value:填写 master(默认拉取 master 分支,可修改)。

  4. 保存参数配置,此时构建页面会出现下拉框,可选择任意分支或 tag 进行构建。

步骤 2:完整 Jenkinsfile 脚本(直接复制使用)

该脚本实现以下功能:拉取代码 → 运行 GTest 单元测试 → QNX 编译 → 生成版本追溯头文件 → 上传产物至 Algorithm Integration 仓库 → 提交推送产物及追溯信息。

pipeline {
    agent any
​
    parameters {
        gitParameter(name: 'BRANCH_TAG', type: 'BRANCH_TAG', defaultValue: 'master', description: '选择分支或tag(如master、feature/xxx、v1.0)')
    }
​
    environment {
        // 源仓库:parkingplanningprocess(代码开发仓库)
        SRC_REPO = 'git@xxx:parkingplanningprocess.git' // 替换为实际仓库地址
        // 目标仓库:Algorithm Integration(产物存放仓库)
        DEST_REPO = 'git@xxx:AlgorithmIntegration.git' // 替换为实际仓库地址
        // 目标分支:个人开发分支
        DEST_BRANCH = 'dev/xuejun.liu/develop'
        // QNX 编译产物目录(与项目 Build.sh 输出目录一致)
        BUILD_OUTPUT = 'build/install'
    }
​
    stages {
        // 阶段1:拉取 parkingplanningprocess 对应分支/Tag 代码
        stage('代码拉取') {
            steps {
                git branch: "${params.BRANCH_TAG}", url: "${SRC_REPO}"
                script {
                    // 记录当前构建的 commit、分支、构建时间(用于追溯)
                    GIT_COMMIT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
                    GIT_BRANCH = "${params.BRANCH_TAG}"
                    BUILD_TIME = sh(script: 'date "+%Y-%m-%d %H:%M:%S"', returnStdout: true).trim()
                }
            }
        }
​
        // 阶段2:GTest 单元测试(新增,测试不通过则终止构建)
        stage('单元测试') {
            steps {
                sh './Build.sh test' // 运行自定义的测试模式,需提前配置 Build.sh
            }
        }
​
        // 阶段3:QNX 编译(执行项目原有 Build.sh 脚本)
        stage('QNX 编译') {
            steps {
                sh '''
                    chmod +x Build.sh
                    ./Build.sh // 执行 QNX 编译,产物输出至 BUILD_OUTPUT 目录
                '''
            }
        }
​
        // 阶段4:生成版本追溯头文件(记录构建信息,便于后续追溯)
        stage('生成版本追溯头文件 build_info.h') {
            steps {
                sh '''
                    cat > ${BUILD_OUTPUT}/build_info.h << EOF
#ifndef BUILD_INFO_H
#define BUILD_INFO_H
​
#define SRC_REPO     "parkingplanningprocess"
#define BRANCH       "${GIT_BRANCH}"
#define COMMIT       "${GIT_COMMIT}"
#define BUILD_TIME   "${BUILD_TIME}"
#define JOB_NAME     "${JOB_NAME}"
#define BUILD_NUMBER "${BUILD_NUMBER}"
​
#endif
EOF
                '''
            }
        }
​
        // 阶段5:拉取目标仓库 Algorithm Integration 对应分支
        stage('拉取目标 Algorithm Integration 仓库') {
            steps {
                dir('AlgorithmIntegration') {
                    git branch: "${DEST_BRANCH}", url: "${DEST_REPO}"
                    sh 'git pull' // 拉取最新代码,避免冲突
                }
            }
        }
​
        // 阶段6:拷贝 QNX 编译产物至目标仓库
        stage('拷贝编译产物') {
            steps {
                sh '''
                    // 清空原有产物,避免旧文件残留
                    rm -rf AlgorithmIntegration/parkingplanningprocess_output
                    mkdir -p AlgorithmIntegration/parkingplanningprocess_output
                    // 拷贝所有产物(config、.a静态库、include头文件、build_info.h)
                    cp -r ${BUILD_OUTPUT}/* AlgorithmIntegration/parkingplanningprocess_output/
                '''
            }
        }
​
        // 阶段7:提交产物并推送到目标分支
        stage('提交并推送到目标分支') {
            steps {
                dir('AlgorithmIntegration') {
                    sh '''
                        git add parkingplanningprocess_output/
                        git commit -m "CI: 自动更新 parkingplanningprocess 编译产物
                        分支:${GIT_BRANCH}
                        提交:${GIT_COMMIT}
                        时间:${BUILD_TIME}"
                        git push origin ${DEST_BRANCH}
                    '''
                }
            }
        }
    }
​
    // 构建后通知(成功/失败提示)
    post {
        success {
            echo "✅ 构建成功!产物已推送到 AlgorithmIntegration: ${DEST_BRANCH}"
        }
        failure {
            echo "❌ 构建失败!请查看控制台日志排查问题(重点关注单元测试、QNX 编译步骤)"
        }
    }
}
​

四、GTest 单元测试集成(不影响原有 QNX 编译)

为项目添加 GTest 单元测试,确保代码质量,测试不通过则终止构建,避免不合格产物上传。

步骤 1:添加 GTest 源码至项目

进入 parkingplanningprocess 仓库根目录,执行以下命令,将 GTest 源码放入第三方依赖目录:

git clone https://github.com/google/googletest.git thirdparty/googletest

步骤 2:修改 CMakeLists.txt(添加测试配置)

在项目根目录的 CMakeLists.txt 底部添加以下内容,启用 GTest 构建:

# --------------------------
# GTest 单元测试集成
# --------------------------
if(BUILD_TESTS)
    add_subdirectory(thirdparty/googletest)
    include_directories(${gtest_SOURCE_DIR}/include ${gmock_SOURCE_DIR}/include)
​
    # 测试可执行文件(添加需要测试的源文件和测试用例文件)
    add_executable(unit_test
        test/test_your_code.cpp  # 测试用例文件,需自行编写
        src/xxx.c                # 待测试的业务源文件,替换为实际文件
    )
​
    # 链接 GTest 库和线程库
    target_link_libraries(unit_test gtest gtest_main pthread)
endif()

步骤 3:修改 Build.sh(增加测试模式)

在 Build.sh 底部添加测试模式,单独编译并运行单元测试,不影响原有 QNX 编译:

# ==============================
# GTest 单元测试(x86模式,单独运行)
# ==============================
if [ "$1" = "test" ]; then
    mkdir -p build_test
    cd build_test
    cmake .. -DBUILD_TESTS=ON  # 启用测试构建
    make -j8                   # 多线程编译测试用例
    ./unit_test                # 运行单元测试,失败则退出
    exit 0
fi

手动测试命令:\./Build\.sh test,测试通过则继续,失败则终止。

步骤 4:Jenkins 显示测试报告(可选)

安装免费插件 JUnit Plugin(显示测试结果)和 Cobertura Plugin(显示代码覆盖率),在 Jenkinsfile 的 post 阶段添加以下内容,即可在 Jenkins 网页查看测试报告:

post {
    always {
        junit 'build_test/*.xml'       // 展示测试用例执行结果
        cobertura 'build_test/coverage.xml' // 展示代码覆盖率
    }
}

五、Jenkins 重启方法(常用3种)

配置插件、修改核心设置后,需重启 Jenkins 使配置生效,推荐以下3种方式,按需选择:

方式 1:网页端图形化重启(最简单)

打开 Jenkins 首页,在地址栏后添加:http://你的Jenkins地址/restart,点击确认重启即可。

备用地址: - 安全重启(等待当前构建完成后重启):/safeRestart - 强制停止:/stop

方式 2:网页菜单重启(中文界面)

进入 Jenkins → 系统管理 → 找到「重启 Jenkins」按钮,点击确认即可(安装中文插件后可见)。

方式 3:服务器命令行重启(Linux/Docker)

  • Linux(systemd 安装): systemctl restart jenkins \# 重启 systemctl status jenkins \# 查看重启状态

  • Docker 部署: docker ps \| grep jenkins \# 查看Jenkins容器名 docker restart 容器名 \# 重启容器

六、队友权限配置(最小权限原则)

为队友开放 Jenkins 权限,仅赋予「构建、查看日志、下载产物」权限,禁止修改配置、删除任务,保障系统安全。

步骤 1:安装权限插件(免费)

安装 Role-based Authorization Strategy 插件(角色权限控制),已安装核心插件后,直接在插件管理中搜索安装即可。

步骤 2:创建队友账号

  1. Jenkins → 系统管理 → 管理用户 → 新建用户。

  2. 填写用户名(如 zhang.san)、密码、邮箱,不开启公开注册,由管理员统一创建。

步骤 3:开启角色权限模式

系统管理 → 全局安全配置 → 授权策略 → 选择「Role-Based Strategy」,保存后刷新页面。

步骤 4:创建角色(最小权限)

  1. 系统管理 → Manage and Assign Roles → Manage Roles。

  2. 全局角色(Global roles):新建角色 dev_global,仅勾选「Overall → Read」(能登录、看界面)、「Credentials → View」(能看凭据,不能改)。

  3. 项目角色(Item roles):新建角色 dev_parking,配置如下:

    • Project pattern:填写 parkingplanningprocess(或 .*parking.* 匹配所有泊车相关任务)。

    • 权限勾选:Job → Read(看任务)、Job → Build(构建)、Run → Read(看日志)、Artifact → Read(下载产物)、Git Parameter → View(看分支下拉框)。

    • 不勾选:Job/Configure、Job/Delete、Administer(禁止修改配置、删除任务)。

步骤 5:分配角色给队友

Manage and Assign Roles → Assign Roles: - 全局角色:给队友勾选 dev_global。 - 项目角色:给队友勾选 dev_parking。 保存后,队友退出重登即可生效。

七、构建地址分享(3种常用方式)

构建完成后,可将构建地址分享给队友,方便查看日志、下载产物,无需手动传递。

方式 1:直接复制链接(最常用)

  • 项目主页(队友可选分支、构建):http://你的JenkinsIP:8080/job/parkingplanningprocess/

  • 某次构建详情:http://你的JenkinsIP:8080/job/parkingplanningprocess/构建号/(构建号为数字,如 123)

  • 控制台日志直达:http://你的JenkinsIP:8080/job/parkingplanningprocess/构建号/console

方式 2:匿名只读(内网推荐)

若只想让队友查看、不允许操作,可开启匿名只读:

系统管理 → 全局安全配置 → 匿名用户权限,勾选「Overall → Read」「Job → Read」「Run → Read」「Artifact → Read」,不勾选 Build、Configure,保存后队友无需登录即可查看。

方式 3:自动推送链接至群聊(高级)

安装对应聊天工具插件(钉钉:DingTalk Notification;企业微信:WeChat Work Notification),在 Jenkinsfile 的 post 阶段添加推送代码,构建完成后自动将链接发送至群聊。

八、常见问题排查

  • 插件搜不到:网络问题导致,可通过 Jenkins 插件官网(https://plugins.jenkins.io/)下载 .hpi 离线包,在「插件管理 → Advanced → 上传 .hpi」安装,重启生效。

  • 队友看不到分支下拉框:确认给队友分配的角色勾选了「Git Parameter → View」权限,退出重登即可。

  • 构建失败:优先查看控制台日志,重点排查单元测试失败、QNX 编译报错、Git 权限不足(凭据配置错误)。

  • 产物上传失败:确认 Jenkins 执行机有 Algorithm Integration 仓库的写权限,目标分支正确。

总结

本文基于已安装的 Jenkins 核心插件,完成了 parkingplanningprocess 项目的全流程配置,涵盖「分支选择 → 单元测试 → QNX 编译 → 产物上传 → 权限管理 → 地址分享」,所有操作均使用免费插件,不破坏原有项目结构和编译流程,可直接落地复用。后续可根据团队需求,添加自动触发、测试报告优化等功能,