mirror of
https://github.com/hustcer/deepseek-review.git
synced 2026-05-13 05:16:05 +08:00
Compare commits
6 Commits
feature/pr
...
v1.19
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
938790c65b | ||
|
|
a4d125ecba | ||
|
|
930e0ae68f | ||
|
|
d0b2ea125a | ||
|
|
9852113028 | ||
|
|
9ad3373cd5 |
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
@@ -15,6 +15,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
- feature/test
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'docs/**'
|
||||
|
||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -1,6 +1,32 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.19.0] - 2025-07-23
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix "variable not found" error (#185)
|
||||
- Fix getting Nu binary path for Nushell 0.106
|
||||
|
||||
### Deps
|
||||
|
||||
- Upgrade Nu to v0.106 (#186)
|
||||
|
||||
## [1.18.0] - 2025-06-11
|
||||
|
||||
### Features
|
||||
|
||||
- Set default `temperature` to **0.3** for code review (#181)
|
||||
|
||||
### Miscellaneous Tasks
|
||||
|
||||
- Refine diff flag descriptions in docs and scripts (#177)
|
||||
- Upgrade `Nu` to 0.105 and pin [`hustcer/setup-nu`](https://github.com/hustcer/setup-nu) to v3.19 (#183)
|
||||
|
||||
### Deps
|
||||
|
||||
- Upgrade `nutest` to v1.1.0 (#179)
|
||||
|
||||
## [1.17.0] - 2025-04-11
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
2
Justfile
2
Justfile
@@ -28,7 +28,7 @@ alias cr := code-review
|
||||
|
||||
# Used to handle the path separator issue
|
||||
DEEPSEEK_REVIEW_PATH := parent_directory(justfile())
|
||||
NU_DIR := parent_directory(`(which nu).path.0`)
|
||||
NU_DIR := parent_directory(`$nu.current-exe`)
|
||||
_query_plugin := if os_family() == 'windows' { 'nu_plugin_query.exe' } else { 'nu_plugin_query' }
|
||||
|
||||
# To pass arguments to a dependency, put the dependency
|
||||
|
||||
@@ -58,9 +58,9 @@ runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup Nu
|
||||
uses: hustcer/setup-nu@v3
|
||||
uses: hustcer/setup-nu@v3.19
|
||||
with:
|
||||
version: 0.103.0
|
||||
version: 0.106.0
|
||||
|
||||
- name: DeepSeek Code Review
|
||||
shell: nu {0}
|
||||
|
||||
4
cr
4
cr
@@ -21,8 +21,8 @@ def main [
|
||||
--model(-m): string, # Model name, or read from CHAT_MODEL env var, `deepseek-chat` by default
|
||||
--base-url(-b): string, # DeepSeek API base URL, fallback to BASE_URL env var
|
||||
--chat-url(-U): string, # DeepSeek Model chat full API URL, e.g. http://localhost:11535/api/chat
|
||||
--sys-prompt(-s): string # Optional, System prompt message, fallback to SYSTEM_PROMPT env var
|
||||
--user-prompt(-u): string # Default to $DEFAULT_OPTIONS.USER_PROMPT
|
||||
--sys-prompt(-s): string # Default to $DEFAULT_OPTIONS.SYS_PROMPT,
|
||||
--user-prompt(-u): string # Default to $DEFAULT_OPTIONS.USER_PROMPT,
|
||||
--include(-i): string, # Comma separated file patterns to include in the code review
|
||||
--exclude(-x): string, # Comma separated file patterns to exclude in the code review
|
||||
--temperature(-T): float, # Temperature for the model, between `0` and `2`, default value `0.3`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "deepseek-review",
|
||||
"version": "1.17.0",
|
||||
"actionVer": "v1.17",
|
||||
"version": "1.19.0",
|
||||
"actionVer": "v1.19",
|
||||
"author": "hustcer",
|
||||
"license": "MIT",
|
||||
"github": "https://github.com/hustcer/deepseek-review",
|
||||
|
||||
@@ -51,8 +51,8 @@ export def compare-ver [v1: string, v2: string] {
|
||||
# If you want to compare more parts use the following code:
|
||||
# for i in 0..([2 ($a | length) ($b | length)] | math max)
|
||||
for i in 0..2 {
|
||||
let x = $a | get -i $i | default 0
|
||||
let y = $b | get -i $i | default 0
|
||||
let x = $a | get -o $i | default 0
|
||||
let y = $b | get -o $i | default 0
|
||||
if $x > $y { return 1 }
|
||||
if $x < $y { return (-1) }
|
||||
}
|
||||
@@ -102,7 +102,7 @@ export def 'from env' []: string -> record {
|
||||
# Compact the record by removing empty columns
|
||||
export def compact-record []: record -> record {
|
||||
let record = $in
|
||||
let empties = $record | columns | filter {|it| $record | get $it | is-empty }
|
||||
let empties = $record | columns | where {|it| $record | get $it | is-empty }
|
||||
$record | reject ...$empties
|
||||
}
|
||||
|
||||
|
||||
23
nu/config.nu
23
nu/config.nu
@@ -23,21 +23,20 @@ def file-exists [file: string] {
|
||||
# Check if the prompt keys exist in the config.yml file
|
||||
def check-prompts [options: record] {
|
||||
check-prompt $options user
|
||||
# System prompt is optional, so we don't exit if it's missing
|
||||
# check-prompt $options system
|
||||
check-prompt $options system
|
||||
}
|
||||
|
||||
# Check if the specified type of prompt key exists in the config.yml file
|
||||
def check-prompt [options: record, type: string] {
|
||||
let prompt_key = $options.settings | get -i $'($type)-prompt' | default ''
|
||||
let prompt_key = $options.settings | get -o $'($type)-prompt' | default ''
|
||||
if ($prompt_key | is-empty) {
|
||||
print $'(ansi r)The ($type) prompt key is missing in `settings.($type)-prompt` config.yml file.(ansi reset)'
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
let prompt = $options.prompts | get -i $type
|
||||
let prompt = $options.prompts | get -o $type
|
||||
| default []
|
||||
| where name == $prompt_key
|
||||
| get -i 0.prompt
|
||||
| get -o 0.prompt
|
||||
if ($prompt | is-empty) {
|
||||
print $'The ($type) prompt (ansi r)($prompt_key)(ansi reset) is missing in `prompts.($type)` of config.yml file.'
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
@@ -60,11 +59,11 @@ def check-providers [options: record] {
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
# Each provider should have name, token and models field
|
||||
$options.providers | each {|it|
|
||||
let empties = [name token models] | filter { |field| $it | get -i $field | is-empty }
|
||||
$options.providers | each {|p|
|
||||
let empties = [name token models] | where { |field| $p | get -o $field | is-empty }
|
||||
if ($empties | is-not-empty) {
|
||||
print $'Field (ansi r)`($empties | str join ,)`(ansi reset) should not be empty for provider:'
|
||||
$it | table -e -t psql | print
|
||||
$p | table -e -t psql | print
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
}
|
||||
@@ -106,7 +105,7 @@ def get-model-envs [settings: record, model?: string = ''] {
|
||||
let provider = $settings.providers
|
||||
| default []
|
||||
| where name == $name
|
||||
| get -i 0
|
||||
| get -o 0
|
||||
| default {}
|
||||
let model_name = $provider.models
|
||||
| default []
|
||||
@@ -115,7 +114,7 @@ def get-model-envs [settings: record, model?: string = ''] {
|
||||
} else {
|
||||
$it.name == $model or $it.alias? == $model }
|
||||
}
|
||||
| get -i 0.name
|
||||
| get -o 0.name
|
||||
| default $model
|
||||
|
||||
{ CHAT_TOKEN: $provider.token?, BASE_URL: $provider.base-url?, CHAT_URL: $provider.chat-url?, CHAT_MODEL: $model_name }
|
||||
@@ -133,12 +132,12 @@ export def --env config-load [
|
||||
let user_prompt = $all_settings.prompts?.user?
|
||||
| default []
|
||||
| where name == ($settings.user-prompt? | default '')
|
||||
| get -i 0.prompt
|
||||
| get -o 0.prompt
|
||||
|
||||
let system_prompt = $all_settings.prompts?.system?
|
||||
| default []
|
||||
| where name == ($settings.system-prompt? | default '')
|
||||
| get -i 0.prompt
|
||||
| get -o 0.prompt
|
||||
|
||||
let model_envs = get-model-envs $all_settings $model
|
||||
|
||||
|
||||
30
nu/review.nu
30
nu/review.nu
@@ -46,7 +46,8 @@ const DEFAULT_OPTIONS = {
|
||||
MODEL: 'deepseek-chat',
|
||||
TEMPERATURE: 0.3,
|
||||
BASE_URL: 'https://api.deepseek.com',
|
||||
USER_PROMPT: 'You are a professional code review assistant responsible for analyzing code changes. Identify potential issues such as code style violations, logical errors, security vulnerabilities, and provide improvement suggestions. Clearly list the problems and recommendations in a concise manner. Please review the following code changes:',
|
||||
USER_PROMPT: 'Please review the following code changes:',
|
||||
SYS_PROMPT: 'You are a professional code review assistant responsible for analyzing code changes in GitHub Pull Requests. Identify potential issues such as code style violations, logical errors, security vulnerabilities, and provide improvement suggestions. Clearly list the problems and recommendations in a concise manner.',
|
||||
}
|
||||
|
||||
# Use DeepSeek AI to review code changes locally or in GitHub Actions
|
||||
@@ -64,8 +65,8 @@ export def --env deepseek-review [
|
||||
--model(-m): string, # Model name, or read from CHAT_MODEL env var, `deepseek-chat` by default
|
||||
--base-url(-b): string, # DeepSeek API base URL, fallback to BASE_URL env var
|
||||
--chat-url(-U): string, # DeepSeek Model chat full API URL, e.g. http://localhost:11535/api/chat
|
||||
--sys-prompt(-s): string # Optional, System prompt message, fallback to SYSTEM_PROMPT env var
|
||||
--user-prompt(-u): string # Default to $DEFAULT_OPTIONS.USER_PROMPT
|
||||
--sys-prompt(-s): string # Default to $DEFAULT_OPTIONS.SYS_PROMPT,
|
||||
--user-prompt(-u): string # Default to $DEFAULT_OPTIONS.USER_PROMPT,
|
||||
--include(-i): string, # Comma separated file patterns to include in the code review
|
||||
--exclude(-x): string, # Comma separated file patterns to exclude in the code review
|
||||
--temperature(-T): float, # Temperature for the model, between `0` and `2`, default value `0.3`
|
||||
@@ -113,7 +114,7 @@ export def --env deepseek-review [
|
||||
print $hint; print -n (char nl)
|
||||
if ($pr_number | is-empty) {
|
||||
print 'Current Settings:'; hr-line
|
||||
$setting | compact-record | reject -i repo | print; print -n (char nl)
|
||||
$setting | compact-record | reject -o repo | print; print -n (char nl)
|
||||
}
|
||||
|
||||
let content = (
|
||||
@@ -125,15 +126,16 @@ export def --env deepseek-review [
|
||||
exit $ECODE.SUCCESS
|
||||
}
|
||||
print $'Review content length: (ansi g)($length)(ansi reset), current max length: (ansi g)($max_length)(ansi reset)'
|
||||
let sys_prompt = $sys_prompt | default $env.SYSTEM_PROMPT?
|
||||
let sys_prompt = $sys_prompt | default $env.SYSTEM_PROMPT? | default $DEFAULT_OPTIONS.SYS_PROMPT
|
||||
let user_prompt = $user_prompt | default $env.USER_PROMPT? | default $DEFAULT_OPTIONS.USER_PROMPT
|
||||
mut messages = if ($sys_prompt | is-empty) { [] } else { [{ role: 'system', content: $sys_prompt }] }
|
||||
$messages = $messages | append { role: 'user', content: $"($user_prompt)\n($content)" }
|
||||
let payload = {
|
||||
model: $model,
|
||||
stream: $stream,
|
||||
messages: $messages
|
||||
temperature: $temperature,
|
||||
messages: [
|
||||
{ role: 'system', content: $sys_prompt },
|
||||
{ role: 'user', content: $"($user_prompt):\n($content)" }
|
||||
]
|
||||
}
|
||||
if $debug { print $'(char nl)Code Changes:'; hr-line; print $content }
|
||||
print $'(char nl)Waiting for response from (ansi g)($url)(ansi reset) ...'
|
||||
@@ -149,9 +151,9 @@ export def --env deepseek-review [
|
||||
print $'✖️ Code review failed!Error: '; hr-line; print $response
|
||||
exit $ECODE.SERVER_ERROR
|
||||
}
|
||||
let message = $response | get -i choices.0.message
|
||||
let message = $response | get -o choices.0.message
|
||||
let reason = $message | coalesce-reasoning
|
||||
let review = $message.content? | default ($response | get -i message.content)
|
||||
let review = $message.content? | default ($response | get -o message.content)
|
||||
let result = ['<details>' '<summary> Reasoning Details</summary>' $reason "</details>\n" $review] | str join "\n"
|
||||
if ($review | is-empty) {
|
||||
print $'✖️ Code review failed!No review result returned from ($base_url) ...'
|
||||
@@ -190,7 +192,7 @@ def write-review-to-file [
|
||||
'# DeepSeek Code Review Result', ''
|
||||
$"Generated at: (date now | format date '%Y/%m/%d %H:%M:%S')", ''
|
||||
'## Code Review Settings', ''
|
||||
($setting | compact-record | reject -i repo | transpose key val | to md --pretty)
|
||||
($setting | compact-record | reject -o repo | transpose key val | to md --pretty)
|
||||
'', '## Review Detail', '', $result, '', ...$token_usage
|
||||
]
|
||||
try {
|
||||
@@ -262,10 +264,10 @@ def streaming-output [
|
||||
| try { lines } catch { print $'(ansi r)Error Happened ...(ansi reset)'; exit $ECODE.SERVER_ERROR }
|
||||
| each {|line|
|
||||
if ($line | is-empty) { return }
|
||||
if ($IGNORED_MESSAGES | get -i $line | default false) { return }
|
||||
if ($IGNORED_MESSAGES | get -o $line | default false) { return }
|
||||
let $last = $line | parse-line
|
||||
if $debug { $last | to json | kv set last-reply }
|
||||
$last | get -i choices.0.delta | default ($last | get -i message) | if ($in | is-not-empty) {
|
||||
$last | get -o choices.0.delta | default ($last | get -o message) | if ($in | is-not-empty) {
|
||||
let delta = $in
|
||||
if ($delta | coalesce-reasoning | is-not-empty) { kv set reasoning ((kv get reasoning) + 1) }
|
||||
if (kv get reasoning) == 1 { print $'(char nl)Reasoning Details:'; hr-line }
|
||||
@@ -277,7 +279,7 @@ def streaming-output [
|
||||
|
||||
if $debug and (kv get last-reply | is-not-empty) {
|
||||
print $'(char nl)(char nl)Model & Token Usage:'; hr-line
|
||||
kv get last-reply | from json | select -i model usage | table -e | print
|
||||
kv get last-reply | from json | select -o model usage | table -e | print
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user