Reasoning over Code Quality and Security in GitHub Pull Requests
Introduction
本指南说明如何将 OpenAI 推理模型集成到您的 GitHub Pull Request (PR) 工作流中,以自动审查代码的质量、安全性和企业标准合规性。通过在开发过程早期利用 AI 驱动的见解,您可以更早地发现问题,减少手动工作量,并在整个代码库中保持一致的最佳实践。
Why Integrate OpenAI Reasoning Models in PRs?
• 通过自动检测代码异味、安全漏洞和样式不一致来节省代码审查时间。 • 在整个组织中强制执行编码标准,以实现一致、可靠的代码。 • 为开发人员提供关于潜在改进的及时、由 AI 驱动的反馈。
Example Use Cases
• 审查者希望在合并前获得有关新代码更改安全性的反馈。 • 团队寻求强制执行标准编码指南,确保整个组织的代码质量一致。
Prerequisites
1. Generate an OpenAI “Project Key”
- 转到 platform.openai.com/api-keys 并单击以创建新的密钥。
- 将令牌安全地存储在 GitHub 存储库的密钥中,命名为 OPENAI_API_KEY。
2. Choose Your OpenAI Model
使用 OpenAI Reasoning Models 对代码更改进行深入分析。从最先进的模型开始,并根据需要优化您的提示。
3. Select a Pull Request
- 确认您的存储库已启用 GitHub Actions。
- 确保您有权配置存储库密钥或变量(例如,用于您的 PROMPT、MODELNAME 和 BEST_PRACTICES 变量)。
4. Define Enterprise Coding Standards
将您的标准存储为存储库变量 (BEST_PRACTICES)。这些可能包括: • 代码样式和格式 • 可读性和可维护性 • 安全性和合规性 • 错误处理和日志记录 • 性能和可伸缩性 • 测试和质量保证 • 文档和版本控制 • 可访问性和国际化
5. Define Prompt Content
构建一个元提示来指导 OpenAI 进行安全、质量和最佳实践检查。包括:
- 代码质量和标准
- 安全性和漏洞分析
- 容错和错误处理
- 性能和资源管理
- 分步验证
鼓励 OpenAI 提供彻底的逐行审查,并附带明确的建议。
Create Your GitHub Actions Workflow
此 GitHub Actions 工作流在每次针对主分支的拉取请求时触发,并包含两个作业。第一个作业收集所有已更改文件的差异(排除 .json 和 .png 文件),并将这些更改发送给 OpenAI 进行分析。OpenAI 提出的任何修复建议都将包含在 PR 的评论中。第二个作业根据您定义的企业标准评估 PR,并返回一个 Markdown 表格,总结代码对这些标准的遵守情况。您可以通过更新提示、模型名称和最佳实践等变量来轻松调整或优化工作流。
name: PR Quality and Security Check
on:
pull_request:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
quality-security-analysis:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
with:
fetch-depth: 0 # Ensure full history for proper diff
- name: Gather Full Code From Changed Files
run: |
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)
echo '{"original files": [' > original_files_temp.json
for file in $CHANGED_FILES; do
if [[ $file == \*.json ]] || [[ $file == *.png ]]; then
continue
fi
if [ -f "$file" ]; then
CONTENT=$(jq -Rs . < "$file")
echo "{\"filename\": \"$file\", \"content\": $CONTENT}," >> original_files_temp.json
fi
done
sed -i '$ s/,$//' original_files_temp.json
echo "]}" >> original_files_temp.json
- name: Display Processed Diff (Debug)
run: cat original_files_temp.json
- name: Get Diff
run: |
git diff origin/main...HEAD \
| grep '^[+-]' \
| grep -Ev '^(---|\+\+\+)' > code_changes_only.txt
jq -Rs '{diff: .}' code_changes_only.txt > diff.json
if [ -f original_files_temp.json ]; then
jq -s '.[0] * .[1]' diff.json original_files_temp.json > combined.json
mv combined.json diff.json
- name: Display Processed Diff (Debug)
run: cat diff.json
- name: Analyze with OpenAI
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
DIFF_CONTENT=$(jq -r '.diff' diff.json)
ORIGINAL_FILES=$(jq -r '."original files"' diff.json)
PROMPT="Please review the following code changes for any obvious quality or security issues. Provide a brief report in markdown format:\n\nDIFF:\n${DIFF\_CONTENT}\n\nORIGINAL FILES:\n${ORIGINAL_FILES}"
jq -n --arg prompt "$PROMPT" '{
"model": "gpt-4",
"messages": [
{ "role": "system", "content": "You are a code reviewer." },
{ "role": "user", "content": $prompt }
]
}' > request.json
curl -sS https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${OPENAI_API_KEY}" \
-d @request.json > response.json
- name: Extract Review Message
id: extract_message
run: |
ASSISTANT_MSG=$(jq -r '.choices[0].message.content' response.json)
{
echo "message<<EOF"
echo "$ASSISTANT_MSG"
echo "EOF"
} >> $GITHUB_OUTPUT
- name: Post Comment to PR
env:
COMMENT: ${{ steps.extract_message.outputs.message }}
GH_TOKEN: ${{ github.token }}
run: |
gh api \
repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \
-f body="$COMMENT"
enterprise-standard-check:
runs-on: ubuntu-latest
needs: [quality-security-analysis]
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0 # ensures we get both PR base and head
- name: Gather Full Code From Changed Files
run: |
# Identify changed files from the base (origin/main) to the pull request HEAD
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)
# Build a JSON array containing filenames and their content
echo '{"original files": [' > original_files_temp.json
for file in $CHANGED_FILES; do
# Skip .json and .txt files
if [[ $file == \*.json ]] || [[ $file == *.txt ]]; then
continue
fi
# If the file still exists (i.e., wasn't deleted)
if [ -f "$file" ]; then
CONTENT=$(jq -Rs . < "$file")
echo "{\"filename\": \"$file\", \"content\": $CONTENT}," >> original_files_temp.json
fi
done
# Remove trailing comma on the last file entry and close JSON
sed -i '$ s/,$//' original_files_temp.json
echo "]}" >> original_files_temp.json
- name: Analyze Code Against Best Practices
id: validate
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
set -e
# Read captured code
ORIGINAL_FILES=$(cat original_files_temp.json)
# Construct the prompt:
# - Summarize each best-practice category
# - Provide a rating for each category: 'extraordinary', 'acceptable', or 'poor'
# - Return a Markdown table titled 'Enterprise Standards'
PROMPT="You are an Enterprise Code Assistant. Review each code snippet below for its adherence to the following categories:
1) Code Style & Formatting
2) Security & Compliance
3) Error Handling & Logging
4) Readability & Maintainability
5) Performance & Scalability
6) Testing & Quality Assurance
7) Documentation & Version Control
8) Accessibility & Internationalization
Using \${{ vars.BEST_PRACTICES }} as a reference, assign a rating of 'extraordinary', 'acceptable', or 'poor' for each category. Return a markdown table titled 'Enterprise Standards' with rows for each category and columns for 'Category' and 'Rating'.
Here are the changed file contents to analyze:
$ORIGINAL_FILES"
# Create JSON request for OpenAI
jq -n --arg system_content "You are an Enterprise Code Assistant ensuring the code follows best practices." \
--arg user_content "$PROMPT" \
'{
"model": "${{ vars.MODELNAME }}",
"messages": [
{
"role": "system",
"content": $system_content
},
{
"role": "user",
"content": $user_content
}
]
}' > request.json
# Make the API call
curl -sS https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d @request.json > response.json
# Extract the model's message
ASSISTANT_MSG=$(jq -r '.choices[0].message.content' response.json)
# Store for next step
{
echo "review<<EOF"
echo "$ASSISTANT_MSG"
echo "EOF"
} >> $GITHUB_OUTPUT
- name: Post Table Comment
env:
COMMENT: ${{ steps.validate.outputs.review }}
GH_TOKEN: ${{ github.token }}
run: |
# If COMMENT is empty or null, skip posting
if [ -z "$COMMENT" ] || [ "$COMMENT" = "null" ]; then
echo "No comment to post."
exit 0
fi
gh api \
repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments \
-f body="$COMMENT"
Test the Workflow
Commit this workflow to your repository, then open a new PR. The workflow will run automatically, posting AI-generated feedback as a PR comment.
For a public example, see the OpenAI-Forum repository’s workflow: pr_quality_and_security_check.yml.