Skip to content

feat: AI code review using ollama and qwen3:14b #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: init-proj
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions .github/workflows/ai-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: Ollama Model Setup and PR Review

on:
pull_request:
branches:
- llm
workflow_dispatch:

permissions:
contents: read
pull-requests: write
issues: write

jobs:
ollama_workflow:
name: Ollama Setup, Model Download, and PR Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'

steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install Ollama (amd64 bundle)
id: install_ollama
run: |
echo "--- Installing Ollama ---"
curl -fsSL https://ollama.com/install.sh | sh
echo "Ollama installation complete."

- name: Start Ollama Service, Pull Model, and Prepare for Review
id: setup_ollama_and_pull_model
run: |
echo "--- Starting Ollama service in background ---"
nohup ollama serve &> ollama_serve.log &
OLLAMA_PID=$!
echo "Ollama server PID: $OLLAMA_PID"

echo "Waiting for Ollama service to be ready..."
until curl http://localhost:11434/api/tags > /dev/null 2>&1; do
sleep 1
done
echo "Ollama service is ready at http://localhost:11434."

echo "--- Pulling qwen3:14b model ---"
START_TIME=$(date +%s)
ollama pull qwen3:14b
END_TIME=$(date +%s)
DOWNLOAD_DURATION=$((END_TIME - START_TIME))
echo "::notice file=ollama_pull_duration.log::Model download time: ${DOWNLOAD_DURATION} seconds"
echo "download_duration=${DOWNLOAD_DURATION}" >> $GITHUB_OUTPUT
echo "ollama_pid=$OLLAMA_PID" >> $GITHUB_OUTPUT
env:
OLLAMA_HOST: 0.0.0.0:11434

- name: Display Measured Download Duration
run: |
echo "-------------------------------------------------------------------"
echo "Summary of Ollama Model Operation Times:"
echo "Model Download Duration: ${{ steps.setup_ollama_and_pull_model.outputs.download_duration }} seconds"
echo "Note: Initial model load time will occur during the first inference (PR review)."
echo "-------------------------------------------------------------------"

- name: Get PR diff
run: |
git fetch origin ${{ github.base_ref }}
git diff origin/${{ github.base_ref }}...HEAD > pr_diff.txt

- name: Review PR with Ollama and Custom Prompt
id: review_with_ollama
if: github.event_name == 'pull_request'
run: |
DIFF_FILE_PATH="pr_diff.txt"
if [ -f "$DIFF_FILE_PATH" ] && [ -s "$DIFF_FILE_PATH" ]; then
PR_DIFF=$(cat "$DIFF_FILE_PATH")

CUSTOM_PROMPT="You are an expert code reviewer. Your task is to analyze the provided git diff, identify potential issues, suggest improvements, and summarize the key changes. Pay close attention to:
- Readability and code style adherence.
- Potential bugs or edge cases.
- Security vulnerabilities.
- Performance implications.
- Adherence to best practices.
- Missing tests or documentation.

Here is the git diff:
\`\`\`diff
$PR_DIFF
\`\`\`

Provide your review in a concise and actionable manner, using markdown formatting including code blocks where necessary. Start with a brief summary, then list specific findings and suggestions. Output only the review comments for the code changes. Do not include your reasoning or thinking process.
End with a summary of the most critical issues found."

echo "--- Sending diff to Ollama for review ---"
echo "$CUSTOM_PROMPT" | ollama run qwen3:14b > ollama_raw_review.txt

echo "--- Ollama PR Review Result ---"
echo "::group::Ollama Review Output"
cat ollama_raw_review.txt
echo "::endgroup::"
else
echo "No diff content found or diff file is empty. Skipping PR review."
echo "" > ollama_raw_review.txt
fi
env:
OLLAMA_HOST: 0.0.0.0:11434

- name: Remove LLM thinking process from review
if: github.event_name == 'pull_request'
run: |
awk '
BEGIN {skip=0}
/^Thinking\.\.\./ {skip=1; next}
/^\.\.\.done thinking\./ {skip=0; next}
skip==0 {print}
' ollama_raw_review.txt > ollama_clean_review.txt

- name: Set review output as environment variable
id: set_review_output
if: github.event_name == 'pull_request'
run: |
echo "REVIEW_RESULT<<EOF" >> $GITHUB_ENV
cat ollama_clean_review.txt >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV

- name: Create PR Comment
uses: actions/github-script@v6
with:
script: |
const reviewOutput = process.env.REVIEW_RESULT;
if (reviewOutput && reviewOutput.trim() !== "") {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## 🤖 Ollama Code Review (qwen3:14b)\n\n${reviewOutput}`
});
} else {
console.log('No review content generated. Skipping PR comment.');
}
env:
REVIEW_RESULT: ${{ env.REVIEW_RESULT }}
if: always() && github.event_name == 'pull_request' && env.REVIEW_RESULT != ''

- name: Stop Ollama Service (Cleanup)
if: always()
run: |
echo "--- Stopping Ollama service ---"
OLLAMA_PID="${{ steps.setup_ollama_and_pull_model.outputs.ollama_pid }}"
if [ -n "$OLLAMA_PID" ] && ps -p "$OLLAMA_PID" > /dev/null; then
kill "$OLLAMA_PID"
echo "Ollama service with PID $OLLAMA_PID stopped."
else
echo "Ollama service not running or already stopped."
fi

- name: Show diff file
run: |
cat pr_diff.txt || echo "No diff file found"
echo "Diff file size: $(wc -c < pr_diff.txt)"
102 changes: 102 additions & 0 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Static Analysis

on:
pull_request:
branches: [ main ]
paths:
- '**.go'
- '**.js'
- '**.jsx'
- '.github/workflows/static-analysis.yml'

jobs:
lint_and_fix_go:
name: Go Static Analysis
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'

- name: Cache Go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
./code/go.sum
key: ${{ runner.os }}-go-${{ hashFiles('./code/go.sum') }}

- name: Ensure Go module exists and tidy
run: |
if [ ! -f go.mod ]; then
go mod init github.com/${{ github.repository }}
fi
go mod tidy
working-directory: ./code

- name: Install reviewdog
run: |
curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh | sh -s -- -b /usr/local/bin

- name: Install golangci-lint
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.57.2
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
working-directory: ./code

- name: Run golangci-lint and report via reviewdog
run: |
golangci-lint run --out-format=checkstyle ./... | reviewdog -f=checkstyle -name="golangci-lint" -reporter=github-pr-review -fail-on-error=true
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
working-directory: ./code

- name: Upload golangci-lint summary
if: always()
uses: actions/upload-artifact@v4
with:
name: golangci-lint-summary
path: ./code

- name: Summarize lint results
if: always()
uses: actions/github-script@v7
with:
script: |
core.summary.addRaw("## Go Static Analysis Run in ./code\n")


lint_js:
name: JavaScript Static Analysis
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4

- name: Find all JS/TS projects
id: find_projects
run: |
find . -name package.json -not -path "*/node_modules/*" > projects.txt
cat projects.txt

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'

- name: Run ESLint via reviewdog (PR review)
uses: reviewdog/action-eslint@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
reporter: github-pr-review
eslint_flags: '**/*.{js,jsx,ts,tsx} --no-error-on-unmatched-pattern'
fail_level: error
workdir: ./js-code
26 changes: 26 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
linters:
enable:
- gofmt
- goimports
- gosimple
- govet
- ineffassign
- misspell
- staticcheck
- unused
- errcheck

linters-settings:
gofmt:
simplify: true
goimports:
local-prefixes: github.com/keploy/code-review-agent

issues:
exclude-rules:
- path: _test\.go
linters:
- errcheck

run:
timeout: 5m
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Code Review Agent


1 change: 1 addition & 0 deletions code/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package code
3 changes: 0 additions & 3 deletions go.mod

This file was deleted.

19 changes: 19 additions & 0 deletions js-code/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// runs-on: ubuntu-latest
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"no-unused-vars": "warn",
"semi": ["error", "always"],
"no-console": "off"

}
}
Empty file added js-code/main.js
Empty file.
15 changes: 15 additions & 0 deletions js-code/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "js-code",
"version": "1.0.0",
"description": "JavaScript code for static analysis",
"main": "main.js",
"scripts": {
"lint": "eslint . --ext .js,.jsx"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"eslint": "^8.0.0"
}
}
5 changes: 0 additions & 5 deletions main.go

This file was deleted.