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 ==="
浙公网安备 33010602011771号