ubuntu下使用Ollama和GitLab CI构建AI代码审查系统

前面linux系列配置了ubuntu 的ssh登录和vscode 的登录。我们再vscode 下远程登录上去配合AI来完成相关的ubuntu 的环境构建和代码编写。你可以把这篇博客的连接丢给你的VS Code 的AI。让他按照这个流程带你完成相关的配置。也可以使用webhooks结合AI-codereview_gitlab来实现。是个开源项目。但是gitlab不禁用webhook不是很安全。

由于公司服务器端安全策略屏蔽webHooks带的功能 所以我们使用GitLab CI 来构建。

环境准备


首先,我们需要安装Ollama并下载合适的模型。

# 安装Ollama(在Linux环境下 推理需要GPU 推理。我使用的是4090D 部署33B code模型 需要20GB显存,这些问题可以通过vs code 的AI辅助你完成对应的检查)
添加Ollama版本检查:ollama --version
curl -fsSL https://ollama.ai/install.sh | sh

# 启动Ollama服务

ollama serve

# 下载DeepSeek Coder模型

ollama pull deepseek-coder:33b

# 验证安装

curl http://localhost:11434/api/tags

#ollama 版本检查
ollama --version

GitLab Runner配置

为了在本地运行CI/CD pipeline,我们需要配置GitLab Runner。 这个配置是再gitlab里面的项目Settings->CI/CD的runner里面点击Create project runner添加。添加tag 一定得是你项目里面的。我起名是ai-review,再runner配置项里面取消Lock to current projects的勾选。创建成功后会返给你一个注册的执行命令,这个再linux下的runner执行。

# 注册Runner(linux下 系统模式 )
sudo gitlab-runner register \
  --url https://your-gitlab-url \
  --token your-registration-token \
  --executor shell \
  --name "AI Review Runner"

# 编辑配置文件/etc/gitlab-runner/config.toml
# 添加环境变量和shell配置
[[runners]]
  name = "AI Review Runner"
  executor = "shell"
  shell = "bash --noprofile --norc"
  environment = ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/home/gitlab-runner"]

项目设置

创建一个新的GitLab项目,添加必要的文件。 我是技术验证,所以我创建了一个新的项目

.gitlab-ci.yml  #文件名称,
#下面是文件内容
stages:
  - review

ai_code_review:
  stage: review
  script:
    - pip install python-gitlab ollama
    - python3 review.py --project-id $CI_PROJECT_ID --gitlab-url $CI_SERVER_URL --token $GITLAB_TOKEN
  only:
    - main
    - merge_requests
  except:
    - tags

review.py(核心脚本)

#!/usr/bin/env python3
# AI代码审查脚本
# 该脚本用于在GitLab CI/CD中自动审查代码变更
# 支持Merge Request和Push事件,使用Ollama调用AI模型生成中文审查意见

import argparse  # 用于解析命令行参数
import os  # 用于获取环境变量,如CI_COMMIT_SHA
import gitlab  # GitLab API客户端库
import ollama  # Ollama客户端库,用于调用本地AI模型

# 解析命令行参数
# CI脚本通过这些参数传递GitLab项目信息和认证令牌
parser = argparse.ArgumentParser(description='AI Code Review Script')
parser.add_argument('--project-id', required=True, help='GitLab project ID')  # 项目ID,从CI_PROJECT_ID获取
parser.add_argument('--mr-iid', help='Merge Request IID')  # MR的IID,如果是MR事件则提供
parser.add_argument('--gitlab-url', required=True, help='GitLab server URL')  # GitLab服务器URL
parser.add_argument('--token', required=True, help='GitLab access token')  # 访问令牌,用于API认证
args = parser.parse_args()

# 配置常量
# 这些值从命令行参数获取,确保脚本灵活配置
GITLAB_URL = args.gitlab_url
GITLAB_TOKEN = args.token
OLLAMA_MODEL = 'deepseek-coder:33b'  # 使用DeepSeek Coder模型,擅长代码分析
PROJECT_ID = args.project_id
MR_IID = args.mr_iid

# 初始化GitLab客户端
# 使用私有令牌认证,创建项目对象用于后续API调用
gl = gitlab.Gitlab(GITLAB_URL, private_token=GITLAB_TOKEN)
project = gl.projects.get(PROJECT_ID)

# 中文审查prompt模板
# 定义AI模型的提示词,指导模型如何审查代码
# 使用中文以获得中文回复,包含具体审查要求
REVIEW_PROMPT = """
你是一位资深的软件开发工程师,请仔细分析以下代码diff中的具体变更。

代码变更diff:
{diffs_text}

请具体指出这个diff中引入的问题,包括:
1. 新增或修改的代码是否有安全漏洞
2. 是否有语法错误或逻辑错误
3. 是否违反最佳实践
4. 任何改进建议

请直接引用diff中的代码行来说明问题,不要给出通用建议。
"""

# 主逻辑:根据事件类型处理审查
if MR_IID:
    # 处理Merge Request事件
    # 获取MR对象,提取变更内容
    mr = project.mergerequests.get(MR_IID)
    changes = mr.changes()  # 获取MR的变更详情
    # 格式化变更内容:文件路径 + diff
    code = '\n'.join([f"{change['new_path']}: {change['diff']}" for change in changes['changes']])
    # 填充prompt模板
    prompt = REVIEW_PROMPT.format(diffs_text=code)
    # 调用Ollama生成审查意见
    review = ollama.chat(model=OLLAMA_MODEL, messages=[{'role': 'user', 'content': prompt}])
    # 在MR上创建评论
    mr.notes.create({'body': review['message']['content']})
else:
    # 处理Push事件(审查最新commit)
    commit_sha = os.getenv('CI_COMMIT_SHA')  # 从CI环境变量获取commit SHA
    if commit_sha:
        # 获取commit对象
        commit = project.commits.get(commit_sha)
        # 获取commit的diff变更
        diffs = commit.diff()  # 返回diff列表,每个diff包含文件路径和变更内容
        # 格式化diff文本:文件路径 + diff内容
        diffs_text = '\n'.join([f"{diff['new_path']}: {diff['diff']}" for diff in diffs])
        # Debug输出:检查diff长度和内容(用于调试)
        print(f"Debug: Diffs text length: {len(diffs_text)}")
        print(f"Debug: First 500 chars of diffs: {diffs_text[:500]}")
        # 填充prompt模板
        prompt = REVIEW_PROMPT.format(diffs_text=diffs_text)
        # 调用Ollama生成审查意见
        review = ollama.chat(model=OLLAMA_MODEL, messages=[{'role': 'user', 'content': prompt}])
        # 在commit上创建评论
        commit.comments.create({'note': review['message']['content']})
    else:
        # 如果没有commit SHA,输出错误信息
        print("No commit SHA available for push review")

# 脚本执行完成
print("Review completed")

CI/CD集成

在GitLab项目设置中添加CI/CD变量:

  • GITLAB_TOKEN: 你的GitLab访问令牌 在自己的头像->Access Tokens页面(我配置的权限是:api, read_user, read_repository, write_repository)
  • GITLAB_URL:你的仓库地址,不要包含项目名称

确保变量设置为protected和masked。 //不考虑安全问题也可以不设置。也可以

测试与调试

提交代码触发CI:

git add .
git commit -m "Initial commit"
git push origin main

检查CI日志,如果有问题,添加debug输出。

实际案例


# test_security.py - 包含SQL注入、路径遍历等漏洞
def add_user(username, password):
    query = f"INSERT INTO users VALUES ('{username}', '{password}')"  # SQL注入风险
    # ...

AI会检测并报告这些问题。在gitlab上选择对应的项目,然后点击Project->Commits->就可以看到每次提交了。然后在点开某次提交就可以看到AI添加的commits了
添加常见问题排查:检查Runner状态:sudo gitlab-runner status查看CI日志中的错误。

现在添加2个脚本用于检测守护和工作状态

check_services.sh

#!/bin/bash
echo "=== AI Code Review System Auto-Start ==="
echo ""

started_any=false

# Check and start Ollama
echo "1. Checking Ollama Service:"
if systemctl is-active --quiet ollama; then
    echo "   ✓ Already running"
else
    echo "   ✗ Not running, starting..."
    sudo systemctl start ollama
    sleep 2
    if systemctl is-active --quiet ollama; then
        echo "   ✓ Started successfully"
        started_any=true
    else
        echo "   ✗ Failed to start"
    fi
fi
echo ""

# Check and start GitLab Runner
echo "2. Checking GitLab Runner:"
if pgrep -f "gitlab-runner run" > /dev/null; then
    echo "   ✓ Already running"
else
    echo "   ✗ Not running, starting..."
    nohup gitlab-runner run > /home/duwenlong/gitlab-runner.log 2>&1 &
    sleep 2
    if pgrep -f "gitlab-runner run" > /dev/null; then
        echo "   ✓ Started successfully"
        started_any=true
    else
        echo "   ✗ Failed to start"
    fi
fi
echo ""

if $started_any; then
    echo "Services started. Waiting for full initialization..."
    sleep 5
    echo "Rechecking status:"
    /home/duwenlong/check_services.sh  # Call the check script
else
    echo "All services already running."
fi

echo ""
echo "=== Auto-Start Complete ==="

repair_services.sh

#!/bin/bash
echo "=== AI Code Review System Repair Script ==="
echo ""

# Function to kill conflicting processes
kill_conflicts() {
    echo "Killing conflicting Ollama processes..."
    pkill -f "ollama serve"
    sleep 2
    echo "Killing old GitLab Runner processes..."
    pkill -f "gitlab-runner run"
    sleep 2
}

# Kill conflicts first
kill_conflicts

# Start Ollama via systemd
echo "Starting Ollama service..."
sudo systemctl start ollama
sleep 3
if systemctl is-active --quiet ollama; then
    echo "✓ Ollama started successfully"
else
    echo "✗ Ollama failed, trying manual start..."
    nohup /home/duwenlong/Downloads/bin/ollama serve > /home/duwenlong/ollama.log 2>&1 &
    sleep 3
    if pgrep -f "ollama serve" > /dev/null; then
        echo "✓ Ollama started manually"
    else
        echo "✗ Ollama still failed"
    fi
fi

# Start GitLab Runner
echo "Starting GitLab Runner..."
nohup gitlab-runner run > /home/duwenlong/gitlab-runner.log 2>&1 &
sleep 3
if pgrep -f "gitlab-runner run" > /dev/null; then
    echo "✓ GitLab Runner started"
else
    echo "✗ GitLab Runner failed"
fi

# Final check
echo ""
echo "Final status check:"
/home/duwenlong/check_services.sh

echo ""
echo "=== Repair Complete ==="
posted @ 2026-01-07 14:28  杜文龙  阅读(53)  评论(0)    收藏  举报