mirror of
https://github.com/hustcer/deepseek-review.git
synced 2026-05-13 05:16:05 +08:00
Compare commits
19 Commits
feature/lo
...
v1.15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
308b582471 | ||
|
|
22e1082798 | ||
|
|
98510dd05d | ||
|
|
985a75f4b2 | ||
|
|
990b275f72 | ||
|
|
f0521e7f9c | ||
|
|
3ea2007572 | ||
|
|
fa7541f78e | ||
|
|
7f5575257d | ||
|
|
d53983d8ee | ||
|
|
991d9e8de3 | ||
|
|
ff5bb86a59 | ||
|
|
daecd2734c | ||
|
|
95ca66de3e | ||
|
|
eb198fae3d | ||
|
|
5ebbddb801 | ||
|
|
9901bcbeb1 | ||
|
|
4e787e2430 | ||
|
|
8e91c18ef8 |
75
.github/workflows/cr.yml
vendored
75
.github/workflows/cr.yml
vendored
@@ -25,43 +25,43 @@ jobs:
|
||||
uses: hustcer/deepseek-review@develop
|
||||
with:
|
||||
max-length: 50000
|
||||
# model: 'deepseek-v3' # Infinigence's DeepSeek V3 model
|
||||
model: 'deepseek-r1' # Infinigence's DeepSeek R1 model
|
||||
base-url: 'https://cloud.infini-ai.com/maas/v1' # Infinigence's API base URL
|
||||
# model: 'deepseek-ai/DeepSeek-V3' # SiliconFlow's DeepSeek V3 model
|
||||
# model: 'deepseek-ai/DeepSeek-R1' # SiliconFlow's DeepSeek R1 model
|
||||
# base-url: 'https://api.siliconflow.cn/v1' # SiliconFlow's API base URL
|
||||
# model: 'deepseek-v3' # Infinigence's DeepSeek V3 model
|
||||
# model: 'deepseek-r1' # Infinigence's DeepSeek R1 model
|
||||
# base-url: 'https://cloud.infini-ai.com/maas/v1' # Infinigence's API base URL
|
||||
# model: 'deepseek-ai/DeepSeek-V3' # SiliconFlow's DeepSeek V3 model
|
||||
model: 'deepseek-ai/DeepSeek-R1' # SiliconFlow's DeepSeek R1 model
|
||||
base-url: 'https://api.siliconflow.cn/v1' # SiliconFlow's API base URL
|
||||
# Store the chat token in GitHub Secrets, don't expose it in the workflow file
|
||||
chat-token: ${{ secrets.CHAT_TOKEN }}
|
||||
sys-prompt: >
|
||||
As a senior DevOps engineer, perform comprehensive review of shell scripts with focus on:
|
||||
As a senior Nushell engineer, perform comprehensive script review with focus on:
|
||||
|
||||
1. Core Requirements:
|
||||
- Validate POSIX compatibility
|
||||
- Check for proper error handling
|
||||
- Verify safe variable usage
|
||||
- Assess resource management
|
||||
### 1. Core Requirements:
|
||||
- Validate Nu 0.90+ compatibility
|
||||
- Check structured data handling
|
||||
- Verify pipeline efficiency
|
||||
- Assess module organization
|
||||
|
||||
2. Security Analysis:
|
||||
- Shell injection prevention
|
||||
- Safe file operations
|
||||
- Proper permissions handling
|
||||
- Secure command execution
|
||||
### 2. Security Analysis:
|
||||
- Command injection prevention
|
||||
- Data leakage prevention
|
||||
- Safe external command usage
|
||||
- Proper permission validation
|
||||
|
||||
3. Performance Optimization:
|
||||
- Efficient process management
|
||||
- Proper use of subshells
|
||||
- Stream handling best practices
|
||||
- Avoidance of unnecessary forks
|
||||
### 3. Performance Optimization:
|
||||
- Pipeline optimization
|
||||
- Memory usage patterns
|
||||
- Builtin vs external command usage
|
||||
- Parallel execution opportunities
|
||||
|
||||
Rules:
|
||||
- Target bash/sh compatibility
|
||||
- Highlight security vulnerabilities
|
||||
- Suggest performance improvements
|
||||
- Keep feedback actionable
|
||||
- Use technical shell terminology
|
||||
**Rules:**
|
||||
- Target Nu 0.90+ features
|
||||
- Highlight data flow vulnerabilities
|
||||
- Suggest structured data optimizations
|
||||
- Keep feedback Nu-specific
|
||||
- Use modern shell terminology
|
||||
|
||||
Required output structure:
|
||||
**Required output structure:**
|
||||
#### Script Analysis
|
||||
- Key observations
|
||||
|
||||
@@ -73,19 +73,18 @@ jobs:
|
||||
|
||||
**Overall Quality:** Rating (1-5)
|
||||
|
||||
Use the following reference data:
|
||||
```yaml
|
||||
checklist:
|
||||
- Compatibility: ["POSIX compliance", "Shell-specific features", "Portability"]
|
||||
- Security: ["Input validation", "Safe eval usage", "Permission checks"]
|
||||
- Reliability: ["Error handling", "Exit codes", "Signal trapping"]
|
||||
- Performance: ["Process management", "I/O operations", "Subshell usage"]
|
||||
- Compatibility: ["Nu version", "Cross-platform support", "Plugin dependencies"]
|
||||
- Security: ["Input sanitization", "Temporary file handling", "Env exposure"]
|
||||
- Reliability: ["Error propagation", "Null handling", "Type validation"]
|
||||
- Performance: ["Lazy evaluation", "Batch processing", "Stream handling"]
|
||||
|
||||
examples:
|
||||
- issue: "❗ Unquoted variable expansion in line 42 (shell injection risk)"
|
||||
- issue: "⚠️ Missing error handling for rm operation in line 15"
|
||||
- suggestion: "Replace backticks with $() for better readability and nesting"
|
||||
- suggestion: "Use exec for file handling to reduce file descriptors"
|
||||
- issue: "❗ Unfiltered external command arguments in line 15 (command injection risk)"
|
||||
- issue: "⚠️ Plaintext credentials in environment variables"
|
||||
- suggestion: "Replace `each { }` with `par-each` for parallel processing"
|
||||
- suggestion: "Use builtin `from json` instead of jq for better performance"
|
||||
|
||||
response_template: |
|
||||
#### Script Analysis
|
||||
|
||||
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
@@ -1,6 +1,7 @@
|
||||
# Description: This workflow runs tests for hustcer/deepseek-review.
|
||||
# REF:
|
||||
# - https://github.com/vyadh/nutest/blob/main/.github/workflows/tests.yaml
|
||||
# - https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables
|
||||
|
||||
name: Run Tests
|
||||
|
||||
|
||||
29
CHANGELOG.md
29
CHANGELOG.md
@@ -1,6 +1,35 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.15.0] - 2025-03-23
|
||||
|
||||
### Features
|
||||
|
||||
- Add example code review prompts for frontend, java and rust to `config.example.yml` (#138)
|
||||
- Post a comment to the PR to notify the user when no `CHAT_TOKEN` is provided (#143)
|
||||
- Add nushell version check and notify for update (#144)
|
||||
- Add `--config` option to specify config file path for local code review (#146)
|
||||
- Support local DeepSeek model running on Ollama (#152)
|
||||
- Add repo of current directory code review support (#161)
|
||||
|
||||
### Miscellaneous Tasks
|
||||
|
||||
- Publish test summary (#133)
|
||||
- Update tests status badge to README
|
||||
- Update code review prompt for current nushell repo (#139)
|
||||
- Use SiliconFlow's DeepSeek API
|
||||
- Some code refactor (#149)
|
||||
- Add `just test` task to run tests locally
|
||||
|
||||
### Refactor
|
||||
|
||||
- Simplify `is-safe-git` common util (#150)
|
||||
- Enhance the glob pattern handling in `glob-to-regex` function (#151)
|
||||
|
||||
### Deps
|
||||
|
||||
- Upgrade `Nushell` to `v0.103.0`
|
||||
|
||||
## [1.12.0] - 2025-02-16
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
5
Justfile
5
Justfile
@@ -21,6 +21,7 @@ set dotenv-load := true
|
||||
set positional-arguments := true
|
||||
|
||||
# Just commands aliases
|
||||
alias t := test
|
||||
alias cr := code-review
|
||||
|
||||
# Use `just --evaluate` to show env vars
|
||||
@@ -48,6 +49,10 @@ code-review *OPTIONS:
|
||||
@overlay use {{ join(DEEPSEEK_REVIEW_PATH, 'nu', 'review.nu') }}; \
|
||||
deepseek-review {{OPTIONS}}
|
||||
|
||||
# Run the test cases locally by nutest
|
||||
test:
|
||||
@use $'($nu.default-config-dir)/lib/nutest' *; run-tests
|
||||
|
||||
# Plugins need to be registered only once after nu v0.61
|
||||
_setup:
|
||||
@register -e json {{ join(NU_DIR, _query_plugin) }}
|
||||
|
||||
79
README.md
79
README.md
@@ -22,6 +22,7 @@
|
||||
- Streaming Output Support for Local Code Review
|
||||
- Review Remote GitHub PRs Directly from Your Local CLI
|
||||
- Review Commit Changes with DeepSeek for Any Local Repository by CLI
|
||||
- Support On-demand Changes Generation via `git show`/`git diff` Command for Further Code Review
|
||||
- Cross-platform Compatibility: Designed to function seamlessly across all platforms capable of running [Nushell](https://github.com/nushell/nushell)
|
||||
|
||||
### Both GH Action & Local
|
||||
@@ -174,7 +175,7 @@ Usage:
|
||||
|
||||
Flags:
|
||||
-d, --debug: Debug mode
|
||||
-r, --repo <string>: GitHub repo name, e.g. hustcer/deepseek-review, or local repo path / alias
|
||||
-r, --repo <string>: GitHub repo name, e.g. hustcer/deepseek-review
|
||||
-n, --pr-number <string>: GitHub PR number
|
||||
-k, --gh-token <string>: Your GitHub token, fallback to GITHUB_TOKEN env var
|
||||
-t, --diff-to <string>: Diff to git REF
|
||||
@@ -183,11 +184,13 @@ Flags:
|
||||
-l, --max-length <int>: Maximum length of the content for review, 0 means no limit.
|
||||
-m, --model <string>: Model name, or read from CHAT_MODEL env var, `deepseek-chat` by default
|
||||
-b, --base-url <string>: DeepSeek API base URL, fallback to BASE_URL env var
|
||||
-U, --chat-url <string>: DeepSeek Model chat full API URL, e.g. http://localhost:11535/api/chat
|
||||
-s, --sys-prompt <string>: Default to $DEFAULT_OPTIONS.SYS_PROMPT,
|
||||
-u, --user-prompt <string>: Default to $DEFAULT_OPTIONS.USER_PROMPT,
|
||||
-i, --include <string>: Comma separated file patterns to include in the code review
|
||||
-x, --exclude <string>: Comma separated file patterns to exclude in the code review
|
||||
-T, --temperature <float>: Temperature for the model, between `0` and `2`, default value `1.0`
|
||||
-C, --config <string>: Config file path, default to `config.yml`
|
||||
-h, --help: Display the help message for this command
|
||||
|
||||
Parameters:
|
||||
@@ -197,34 +200,68 @@ Parameters:
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
To perform code reviews locally, you need to modify the configuration file. A sample configuration file [`config.example.yml`](https://github.com/hustcer/deepseek-review/blob/main/config.example.yml) is already provided in the repository. Copy it to `config.yml` and adjust it according to your actual setup.
|
||||
To perform code review locally, you need to modify the configuration file. The repository already provides a configuration example [`config.example.yml`](https://github.com/hustcer/deepseek-review/blob/main/config.example.yml). Copy it to `config.yml` and modify it according to your actual needs. **Read the comments in the configuration file carefully**, as they explain the purpose of each configuration item.
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> The `config.yml` configuration file is only used locally and will not be utilized in GitHub
|
||||
> Workflow. Please securely store any sensitive information in it and avoid committing it
|
||||
> to the code repository.
|
||||
> The `config.yml` configuration file is **only used locally** and will not be utilized in GitHub Workflow. **Sensitive information** in this file should be properly secured and **never committed** to the code repository.
|
||||
>
|
||||
|
||||
### Usage Examples
|
||||
**Create Command Alias**
|
||||
|
||||
For convenience in performing code review across any local repository, create a command alias. For example:
|
||||
|
||||
```sh
|
||||
# For Nushell: Modify config.nu and add:
|
||||
alias cr = nu /absolute/path/to/deepseek-review/cr --config /absolute/path/to/deepseek-review/config.yml
|
||||
|
||||
# For zsh/bash: Modify ~/.zshrc or ~/.bashrc and add:
|
||||
alias cr="nu /absolute/path/to/deepseek-review/cr --config /absolute/path/to/deepseek-review/config.yml"
|
||||
|
||||
# After sourcing the modified profile, use `cr` for code review
|
||||
```
|
||||
|
||||
### Review Local Repository
|
||||
|
||||
To review a local repository:
|
||||
|
||||
- Navigate to the Git repository directory.
|
||||
- Use the `cr` command to review current modifications, provided that `config.yml` is correctly configured.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
```sh
|
||||
# Perform code review on the `git diff` changes in current directory
|
||||
cr
|
||||
# Perform code review on the `git diff f536acc` changes in current directory
|
||||
cr --diff-from f536acc
|
||||
# Perform code review on the `git diff f536acc 0dd0eb5` changes in current directory
|
||||
cr --diff-from f536acc --diff-to 0dd0eb5
|
||||
# Review the changes in current directory using the `--patch-cmd` flag
|
||||
cr --patch-cmd 'git diff head~3'
|
||||
cr -c 'git show head~3'
|
||||
cr -c 'git diff 2393375 71f5a31'
|
||||
cr -c 'git diff 2393375 71f5a31 nu/*'
|
||||
cr -c 'git diff 2393375 71f5a31 :!nu/*'
|
||||
# Dangerous commands like `cr -c 'git show head~3; rm ./*'` will not be allowed
|
||||
```
|
||||
|
||||
### Review Remote GitHub PR Locally
|
||||
|
||||
When reviewing a remote GitHub PR locally:
|
||||
|
||||
- Always specify the PR number via `--pr-number`
|
||||
- Use `--repo` to indicate the target repository (e.g., `hustcer/deepseek-review`). If `--repo` is omitted, the tool reads `settings.default-github-repo` from `config.yml`.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
```sh
|
||||
# Perform code review on the `git diff` changes in the local DEFAULT_LOCAL_REPO repo
|
||||
nu cr
|
||||
# Perform code review on the `git diff f536acc` changes in the local DEFAULT_LOCAL_REPO repo
|
||||
nu cr --diff-from f536acc
|
||||
# Perform code review on the `git diff f536acc 0dd0eb5` changes in the local DEFAULT_LOCAL_REPO repo
|
||||
nu cr --diff-from f536acc --diff-to 0dd0eb5
|
||||
# Review the changes in the local `DEFAULT_LOCAL_REPO` repo using the `--patch-cmd` flag
|
||||
nu cr --patch-cmd 'git diff head~3'
|
||||
nu cr -c 'git show head~3'
|
||||
nu cr -c 'git diff 2393375 71f5a31'
|
||||
nu cr -c 'git diff 2393375 71f5a31 nu/*'
|
||||
nu cr -c 'git diff 2393375 71f5a31 :!nu/*'
|
||||
# Dangerous commands like `nu cr -c 'git show head~3; rm ./*'` will not be allowed
|
||||
# Perform code review on PR #31 in the remote DEFAULT_GITHUB_REPO repo
|
||||
nu cr --pr-number 31
|
||||
cr --pr-number 31
|
||||
# Perform code review on PR #31 in the remote hustcer/deepseek-review repo
|
||||
nu cr --pr-number 31 --repo hustcer/deepseek-review
|
||||
cr --pr-number 31 --repo hustcer/deepseek-review
|
||||
# Perform code review on PR #31 and exclude changes of pnpm-lock.yaml
|
||||
cr --pr-number 31 --exclude pnpm-lock.yaml
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
- 本地代码审查的时候支持流式输出
|
||||
- 通过本地 CLI 直接审查远程 GitHub PR
|
||||
- 通过本地 CLI 使用 DeepSeek 分析任何本地仓库的提交变更
|
||||
- 通过本地 CLI 使用 DeepSeek 审查任何本地仓库的提交变更
|
||||
- 允许通过自定义 `git show`/`git diff` 命令生成变更记录并进行审查
|
||||
- 跨平台:理论上只要能运行 [Nushell](https://github.com/nushell/nushell) 即可使用本工具
|
||||
|
||||
### 本地或 GH Action
|
||||
@@ -171,7 +172,7 @@ Usage:
|
||||
|
||||
Flags:
|
||||
-d, --debug: Debug mode
|
||||
-r, --repo <string>: GitHub repo name, e.g. hustcer/deepseek-review, or local repo path / alias
|
||||
-r, --repo <string>: GitHub repo name, e.g. hustcer/deepseek-review
|
||||
-n, --pr-number <string>: GitHub PR number
|
||||
-k, --gh-token <string>: Your GitHub token, fallback to GITHUB_TOKEN env var
|
||||
-t, --diff-to <string>: Diff to git REF
|
||||
@@ -180,11 +181,13 @@ Flags:
|
||||
-l, --max-length <int>: Maximum length of the content for review, 0 means no limit.
|
||||
-m, --model <string>: Model name, or read from CHAT_MODEL env var, `deepseek-chat` by default
|
||||
-b, --base-url <string>: DeepSeek API base URL, fallback to BASE_URL env var
|
||||
-U, --chat-url <string>: DeepSeek Model chat full API URL, e.g. http://localhost:11535/api/chat
|
||||
-s, --sys-prompt <string>: Default to $DEFAULT_OPTIONS.SYS_PROMPT,
|
||||
-u, --user-prompt <string>: Default to $DEFAULT_OPTIONS.USER_PROMPT,
|
||||
-i, --include <string>: Comma separated file patterns to include in the code review
|
||||
-x, --exclude <string>: Comma separated file patterns to exclude in the code review
|
||||
-T, --temperature <float>: Temperature for the model, between `0` and `2`, default value `1.0`
|
||||
-C, --config <string>: Config file path, default to `config.yml`
|
||||
-h, --help: Display the help message for this command
|
||||
|
||||
Parameters:
|
||||
@@ -194,33 +197,63 @@ Parameters:
|
||||
|
||||
### 环境配置
|
||||
|
||||
在本地进行代码审查需要先修改配置文件,仓库里已经有了 [`config.example.yml`](https://github.com/hustcer/deepseek-review/blob/main/config.example.yml) 配置文件示例,将其拷贝到 `config.yml` 然后根据自己的实际情况进行修改即可。
|
||||
在本地进行代码审查需要先修改配置文件,仓库里已经有了 [`config.example.yml`](https://github.com/hustcer/deepseek-review/blob/main/config.example.yml) 配置文件示例,将其拷贝到 `config.yml` 然后根据自己的实际情况进行修改即可,在修改配置文件的过程中请仔细阅读其中的注释,注释会说明每个配置项的作用。
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> `config.yml` 配置文件仅在本地使用,在 GitHub Workflow 里面不会使用,里面的敏感信息请
|
||||
> 妥善保存,不要提交到代码仓库里面
|
||||
>
|
||||
|
||||
### 使用举例
|
||||
**创建命令别名**
|
||||
|
||||
为了方便您可以在任意本地仓库进行代码审查需要创建一个别名,比如:
|
||||
|
||||
```sh
|
||||
# Nushell: 修改其 config.nu 配置文件,添加:
|
||||
alias cr = nu /absolute/path/to/deepseek-review/cr --config /absolute/path/to/deepseek-review/config.yml
|
||||
# 对于 zsh 或 bash分别修改 ~/.zshrc or ~/.bashrc and add:
|
||||
alias cr="nu /absolute/path/to/deepseek-review/cr --config /absolute/path/to/deepseek-review/config.yml"
|
||||
# After sourcing the profile you have edit, you can use `cr` now
|
||||
```
|
||||
|
||||
之后就可以通过 `cr` 命令来进行代码审查了。
|
||||
|
||||
### 审查本地仓库
|
||||
|
||||
对本地仓库进行代码审查时需要先切换到 Git 仓库所在目录,然后通过 `cr` 命令即可对当前目录的当前修改进行代码审查,前提是您已经对 `config.yml` 进行了正确的配置。
|
||||
|
||||
**使用举例**
|
||||
|
||||
```sh
|
||||
# 对本地当前目录所在仓库 `git diff` 修改内容进行代码审查
|
||||
cr
|
||||
# 对本地当前目录所在仓库 `git diff f536acc` 修改内容进行代码审查
|
||||
cr --diff-from f536acc
|
||||
# 对本地当前目录所在仓库 `git diff f536acc 0dd0eb5` 修改内容进行代码审查
|
||||
cr --diff-from f536acc --diff-to 0dd0eb5
|
||||
# 通过 --patch-cmd 参数对本地当前目录所在仓库变更内容进行审查
|
||||
cr --patch-cmd 'git diff head~3'
|
||||
cr -c 'git show head~3'
|
||||
cr -c 'git diff 2393375 71f5a31'
|
||||
cr -c 'git diff 2393375 71f5a31 nu/*'
|
||||
cr -c 'git diff 2393375 71f5a31 :!nu/*'
|
||||
# 像 `cr -c 'git show head~3; rm ./*'` 这样危险的命令将会被禁止
|
||||
```
|
||||
|
||||
### 本地审查远程 GitHub PR
|
||||
|
||||
在本地对远程 GitHub 仓库的 PR 进行审查的时候一定要通过 `--pr-number` 传入待审查的 PR 编号,以及 `--repo` 指明待审查的仓库,比如 `hustcer/deepseek-review`, 如果没有指定 `--repo` 参数则从 config.yml 里面的 `settings.default-github-repo` 配置项读取待审查的仓库。
|
||||
|
||||
**使用举例**
|
||||
|
||||
```sh
|
||||
# 对本地 DEFAULT_LOCAL_REPO 仓库 `git diff` 修改内容进行代码审查
|
||||
nu cr
|
||||
# 对本地 DEFAULT_LOCAL_REPO 仓库 `git diff f536acc` 修改内容进行代码审查
|
||||
nu cr --diff-from f536acc
|
||||
# 对本地 DEFAULT_LOCAL_REPO 仓库 `git diff f536acc 0dd0eb5` 修改内容进行代码审查
|
||||
nu cr --diff-from f536acc --diff-to 0dd0eb5
|
||||
# 通过 --patch-cmd 参数对本地 DEFAULT_LOCAL_REPO 仓库变更内容进行审查
|
||||
nu cr --patch-cmd 'git diff head~3'
|
||||
nu cr -c 'git show head~3'
|
||||
nu cr -c 'git diff 2393375 71f5a31'
|
||||
nu cr -c 'git diff 2393375 71f5a31 nu/*'
|
||||
nu cr -c 'git diff 2393375 71f5a31 :!nu/*'
|
||||
# 像 `nu cr -c 'git show head~3; rm ./*'` 这样危险的命令将会被禁止
|
||||
# 对远程 DEFAULT_GITHUB_REPO 仓库编号为 31 的 PR 进行代码审查
|
||||
nu cr --pr-number 31
|
||||
cr --pr-number 31
|
||||
# 对远程 hustcer/deepseek-review 仓库编号为 31 的 PR 进行代码审查
|
||||
nu cr --pr-number 31 --repo hustcer/deepseek-review
|
||||
cr --pr-number 31 --repo hustcer/deepseek-review
|
||||
# 对 PR 进行审查的时候排除 pnpm-lock.yaml 文件的变更
|
||||
cr --pr-number 31 --exclude pnpm-lock.yaml
|
||||
```
|
||||
|
||||
## 许可
|
||||
|
||||
@@ -60,7 +60,7 @@ runs:
|
||||
- name: Setup Nu
|
||||
uses: hustcer/setup-nu@v3
|
||||
with:
|
||||
version: 0.102.0
|
||||
version: 0.103.0
|
||||
|
||||
- name: DeepSeek Code Review
|
||||
shell: nu {0}
|
||||
|
||||
@@ -27,8 +27,6 @@ settings:
|
||||
# This token is used to fetch the PR changes from GitHub API
|
||||
# Default value will be ${{ github.token }} if used in GitHub Actions
|
||||
github-token: 'YOUR_GITHUB_TOKEN'
|
||||
# Default local repository to review, could be overrode by '-r' or '--repo'
|
||||
default-local-repo: 'review'
|
||||
# Default GitHub repository to review, could be overrode by '-r' or '--repo' if used with `-n` or `--pr-number`
|
||||
default-github-repo: 'hustcer/deepseek-review'
|
||||
# Include changes in the following file patterns
|
||||
@@ -39,6 +37,14 @@ settings:
|
||||
# Multiple providers could be defined, select the one by name in 'settings.provider'
|
||||
# This way you could switch between different predefined providers easily
|
||||
providers:
|
||||
- name: ollama-local
|
||||
token: 'empty'
|
||||
chat-url: http://localhost:11555/api/chat
|
||||
models:
|
||||
- name: deepseek-r1
|
||||
alias: r1
|
||||
enabled: true
|
||||
description: 'DeepSeek R1 model running on Ollama'
|
||||
- name: 'DeepSeek'
|
||||
token: 'YOUR_DEEPSEEK_TOKEN' # Required, The API token for the provider
|
||||
base-url: 'https://api.deepseek.com'
|
||||
@@ -64,17 +70,6 @@ providers:
|
||||
alias: r1
|
||||
description: 'SiliconFlow DeepSeek R1 model'
|
||||
|
||||
|
||||
# Multiple local repositories could be defined, select the one by name in 'settings.default-local-repo'
|
||||
# You can also use `-r` or `--repo` to specify the local repository to review by name to override the default
|
||||
local-repos:
|
||||
- name: 'review'
|
||||
path: '/Users/hustcer/deepseek-review'
|
||||
- name: 'milestone'
|
||||
path: '/Users/hustcer/milestone-action'
|
||||
- name: 'setup-nu'
|
||||
path: '/Users/hustcer/setup-nu'
|
||||
|
||||
# Multiple Prompts could be defined, select the one by name in 'settings.user-prompt' or 'settings.system-prompt'
|
||||
prompts:
|
||||
user:
|
||||
@@ -87,6 +82,219 @@ prompts:
|
||||
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.
|
||||
|
||||
- name: frontend
|
||||
prompt: >
|
||||
As a senior Frontend engineer, perform comprehensive code review with focus on:
|
||||
|
||||
### 1. Core Requirements:
|
||||
- Validate ES specification compliance
|
||||
- Check component design patterns
|
||||
- Verify state management efficiency
|
||||
- Assess accessibility implementation
|
||||
|
||||
### 2. Security Analysis:
|
||||
- XSS prevention measures
|
||||
- CSRF protection implementation
|
||||
- Safe third-party dependency usage
|
||||
- Sensitive data handling practices
|
||||
|
||||
### 3. Performance Optimization:
|
||||
- Resource loading strategies
|
||||
- Rendering performance optimization
|
||||
- Memory leak prevention
|
||||
- Bundle size management
|
||||
|
||||
**Rules:**
|
||||
- Target React/Vue framework conventions
|
||||
- Highlight security vulnerabilities
|
||||
- Suggest performance metrics improvements
|
||||
- Provide code snippets for fixes
|
||||
- Use modern frontend terminology
|
||||
|
||||
**Required output structure:**
|
||||
#### Code Analysis
|
||||
- Key observations
|
||||
|
||||
#### Security Review
|
||||
- Vulnerability findings
|
||||
|
||||
#### Optimization Suggestions
|
||||
- Performance improvements
|
||||
|
||||
**Overall Quality:** Rating (1-5)
|
||||
|
||||
```yaml
|
||||
checklist:
|
||||
- Compatibility: ["Browser support", "Responsive design", "ES specification"]
|
||||
- Security: ["Input sanitization", "CORS configuration", "Cookie flags"]
|
||||
- Reliability: ["Error boundaries", "Loading states", "Fallback UI"]
|
||||
- Performance: ["Lazy loading", "Code splitting", "Rendering optimization"]
|
||||
|
||||
examples:
|
||||
- issue: "❗ Unsanitized HTML insertion in line 28 (XSS risk)"
|
||||
- issue: "⚠️ Missing `rel='noreferrer'` on external links in line 15"
|
||||
- suggestion: "Implement virtual scrolling for large datasets in TableComponent"
|
||||
- suggestion: "Convert CSS-in-JS to CSS Modules for better tree-shaking"
|
||||
|
||||
response_template: |
|
||||
#### Code Analysis
|
||||
- {{observations}}
|
||||
|
||||
{{#security_issues}}
|
||||
#### Security Review
|
||||
- {{security_issues}}
|
||||
{{/security_issues}}
|
||||
|
||||
{{#optimizations}}
|
||||
#### Optimization Suggestions
|
||||
- {{optimizations}}
|
||||
{{/optimizations}}
|
||||
|
||||
**Overall Quality:** {{rating}}
|
||||
```
|
||||
|
||||
- name: java
|
||||
prompt: >
|
||||
As a senior Java Backend engineer, perform comprehensive code review with focus on:
|
||||
|
||||
### 1. Core Requirements:
|
||||
- Validate Java coding standards compliance
|
||||
- Check enterprise design patterns implementation
|
||||
- Verify resource management efficiency
|
||||
- Assess concurrency control mechanisms
|
||||
|
||||
### 2. Security Analysis:
|
||||
- SQL/NoSQL injection prevention
|
||||
- Sensitive data encryption handling
|
||||
- Proper authentication/authorization
|
||||
- Secure session management
|
||||
|
||||
### 3. Performance Optimization:
|
||||
- Thread pool configuration analysis
|
||||
- Database connection management
|
||||
- Cache strategy evaluation
|
||||
- GC tuning opportunities
|
||||
|
||||
**Rules:**
|
||||
- Target Spring Boot/Jakarta EE frameworks
|
||||
- Highlight OWASP TOP 10 vulnerabilities
|
||||
- Suggest JVM optimization strategies
|
||||
- Provide code snippets for fixes
|
||||
- Use enterprise Java terminology
|
||||
|
||||
**Required output structure:**
|
||||
#### Code Analysis
|
||||
- Key observations
|
||||
|
||||
#### Security Review
|
||||
- Vulnerability findings
|
||||
|
||||
#### Optimization Suggestions
|
||||
- Performance improvements
|
||||
|
||||
**Overall Quality:** Rating (1-5)
|
||||
|
||||
```yaml
|
||||
checklist:
|
||||
- Compatibility: ["JDK version", "Framework version", "API contracts"]
|
||||
- Security: ["Input validation", "CSRF protection", "Security headers"]
|
||||
- Reliability: ["Exception handling", "Transaction management", "Circuit breakers"]
|
||||
- Performance: ["Connection pooling", "Query optimization", "Object reuse"]
|
||||
|
||||
examples:
|
||||
- issue: "❗ Unvalidated user input in DAO layer (SQL injection risk)[2,3](@ref)"
|
||||
- issue: "⚠️ Plaintext credentials storage in properties file[2](@ref)"
|
||||
- suggestion: "Replace synchronized blocks with ReentrantLock for better concurrency[3](@ref)"
|
||||
- suggestion: "Implement prepared statement caching in JDBC configuration[3](@ref)"
|
||||
|
||||
response_template: |
|
||||
#### Code Analysis
|
||||
- {{observations}}
|
||||
|
||||
{{#security_issues}}
|
||||
#### Security Review
|
||||
- {{security_issues}}
|
||||
{{/security_issues}}
|
||||
|
||||
{{#optimizations}}
|
||||
#### Optimization Suggestions
|
||||
- {{optimizations}}
|
||||
{{/optimizations}}
|
||||
|
||||
**Overall Quality:** {{rating}}
|
||||
```
|
||||
|
||||
- name: rust
|
||||
prompt: >
|
||||
As a senior Rust engineer, perform comprehensive code review with focus on:
|
||||
|
||||
### 1. Core Requirements:
|
||||
- Validate Rust coding standards compliance
|
||||
- Check memory safety guarantees
|
||||
- Verify concurrency model correctness
|
||||
- Assess error handling patterns
|
||||
|
||||
### 2. Security Analysis:
|
||||
- Unsafe code usage validation
|
||||
- Data race prevention measures
|
||||
- Input sanitization practices
|
||||
- Supply chain security checks
|
||||
|
||||
### 3. Performance Optimization:
|
||||
- Memory allocation patterns
|
||||
- Iterator vs loop efficiency
|
||||
- Parallel execution opportunities
|
||||
- Zero-cost abstraction utilization
|
||||
|
||||
**Rules:**
|
||||
- Target Rust 2021 edition features
|
||||
- Highlight memory safety violations
|
||||
- Suggest lifetime optimization strategies
|
||||
- Provide unsafe code alternatives
|
||||
- Use Rust ecosystem terminology
|
||||
|
||||
**Required output structure:**
|
||||
#### Code Analysis
|
||||
- Key observations
|
||||
|
||||
#### Security Review
|
||||
- Vulnerability findings
|
||||
|
||||
#### Optimization Suggestions
|
||||
- Performance improvements
|
||||
|
||||
**Overall Quality:** Rating (1-5)
|
||||
|
||||
```yaml
|
||||
checklist:
|
||||
- Compatibility: ["Edition compliance", "Crate versioning", "FFI safety"]
|
||||
- Security: ["Unsafe scoping", "Panic safety", "Trait bounds"]
|
||||
- Reliability: ["Error propagation", "Test coverage", "Documentation"]
|
||||
- Performance: ["Allocation tracking", "Concurrency patterns", "SIMD usage"]
|
||||
|
||||
examples:
|
||||
- issue: "❗ Unmarked unsafe block in line 75 (memory safety violation risk)[1](@ref)"
|
||||
- issue: "⚠️ Missing error handling for Result in line 42[1](@ref)"
|
||||
- suggestion: "Replace Box<dyn Trait> with impl Trait for better monomorphization[1](@ref)"
|
||||
- suggestion: "Use crossbeam-channel instead of std::sync::mpsc for improved throughput[3](@ref)"
|
||||
|
||||
response_template: |
|
||||
#### Code Analysis
|
||||
- {{observations}}
|
||||
|
||||
{{#security_issues}}
|
||||
#### Security Review
|
||||
- {{security_issues}}
|
||||
{{/security_issues}}
|
||||
|
||||
{{#optimizations}}
|
||||
#### Optimization Suggestions
|
||||
- {{optimizations}}
|
||||
{{/optimizations}}
|
||||
|
||||
**Overall Quality:** {{rating}}
|
||||
```
|
||||
|
||||
- name: strict-dev
|
||||
prompt: >
|
||||
Act as a senior engineer performing rigorous code review. Analyze the provided git diff output through
|
||||
|
||||
14
cr
14
cr
@@ -4,14 +4,14 @@
|
||||
# Description: A wrapper for nu/review.nu as the main entry point of the project.
|
||||
|
||||
use nu/config.nu *
|
||||
use nu/common.nu [hr-line, ECODE]
|
||||
use nu/common.nu [hr-line, check-nushell, ECODE]
|
||||
use nu/review.nu [deepseek-review]
|
||||
|
||||
# Use DeepSeek AI to review code changes locally or in GitHub Actions
|
||||
def main [
|
||||
token?: string, # Your DeepSeek API token, fallback to CHAT_TOKEN env var
|
||||
--debug(-d), # Debug mode
|
||||
--repo(-r): string, # GitHub repo name, e.g. hustcer/deepseek-review, or local repo path / alias
|
||||
--repo(-r): string, # GitHub repo name, e.g. hustcer/deepseek-review
|
||||
--pr-number(-n): string, # GitHub PR number
|
||||
--gh-token(-k): string, # Your GitHub token, fallback to GITHUB_TOKEN env var
|
||||
--diff-to(-t): string, # Diff to git REF
|
||||
@@ -20,15 +20,18 @@ def main [
|
||||
--max-length(-l): int, # Maximum length of the content for review, 0 means no limit.
|
||||
--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 # 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 `1.0`, Only for V3
|
||||
--temperature(-T): float, # Temperature for the model, between `0` and `2`, default value `1.0`
|
||||
--config(-C): string # Config file path, default to `config.yml`
|
||||
] {
|
||||
|
||||
config-check
|
||||
config-load --debug=$debug --repo=$repo --model=$model
|
||||
check-nushell
|
||||
config-check --config=$config
|
||||
config-load --debug=$debug --config=$config --model=$model
|
||||
(
|
||||
deepseek-review $token
|
||||
--repo=$repo
|
||||
@@ -37,6 +40,7 @@ def main [
|
||||
--exclude=$exclude
|
||||
--model=$env.CHAT_MODEL
|
||||
--base-url=$base_url
|
||||
--chat-url=$chat_url
|
||||
--gh-token=$gh_token
|
||||
--diff-to=$diff_to
|
||||
--diff-from=$diff_from
|
||||
|
||||
@@ -8,12 +8,15 @@ words:
|
||||
- MPFR
|
||||
- nuon
|
||||
- pwsh
|
||||
- JDBC
|
||||
- mpsc
|
||||
- nuons
|
||||
- ECODE
|
||||
- vyadh
|
||||
- nutest
|
||||
- endfor
|
||||
- dotenv
|
||||
- Ollama
|
||||
- hustcer
|
||||
- Nushell
|
||||
- creatio
|
||||
@@ -26,4 +29,9 @@ words:
|
||||
- Infinigence
|
||||
- SILICONFLOW
|
||||
- USERPROFILE
|
||||
- noreferrer
|
||||
- Unsanitized
|
||||
- Unvalidated
|
||||
- monomorphization
|
||||
ignorePaths:
|
||||
- config.yml
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "deepseek-review",
|
||||
"version": "1.12.0",
|
||||
"actionVer": "v1.12",
|
||||
"version": "1.15.0",
|
||||
"actionVer": "v1.15",
|
||||
"author": "hustcer",
|
||||
"license": "MIT",
|
||||
"github": "https://github.com/hustcer/deepseek-review",
|
||||
|
||||
29
nu/common.nu
29
nu/common.nu
@@ -4,6 +4,8 @@
|
||||
# Description: Common helpers for DeepSeek-Review
|
||||
#
|
||||
|
||||
use kv.nu ['kv set', 'kv get']
|
||||
|
||||
# Commonly used exit codes
|
||||
export const ECODE = {
|
||||
SUCCESS: 0,
|
||||
@@ -55,6 +57,27 @@ export def compare-ver [v1: string, v2: string] {
|
||||
0
|
||||
}
|
||||
|
||||
# Check nushell version and notify user to upgrade it if outdated
|
||||
# Check version once daily and cache the result
|
||||
export def check-nushell [--debug] {
|
||||
const _DATE_FMT = '%Y.%m.%d'
|
||||
const V_KEY = 'NU-VERSION-CHECK@DEEPSEEK-REVIEW'
|
||||
let version_cached = kv get -u $V_KEY
|
||||
let today = date now | format date $_DATE_FMT
|
||||
let check = if ($version_cached | is-empty) or $version_cached.date? != $today {
|
||||
let $check = try { ({ ...(version check), date: $today }) } catch { ({ current: true }) }
|
||||
if $debug { print 'Checking for the latest Nushell version...'; $check | print }
|
||||
kv set -u $V_KEY $check --return value
|
||||
} else {
|
||||
$version_cached
|
||||
}
|
||||
# If the current version is the latest after user upgrade, return
|
||||
if $check.current or (compare-ver $check.latest (version).version) == 0 { return }
|
||||
print $'(char nl) (ansi yr) WARNING: (ansi reset) Your Nushell is (ansi r)OUTDATED(ansi reset)'
|
||||
print $' ------------> Please upgrade Nushell to the latest version: (ansi g)($check.latest)(ansi reset) <------------'
|
||||
print -n (char nl)
|
||||
}
|
||||
|
||||
# Converts a .env file into a record
|
||||
# may be used like this: open .env | load-env
|
||||
# works with quoted and unquoted .env files
|
||||
@@ -143,3 +166,9 @@ export def has-ref [
|
||||
let parse = (do -i { git rev-parse --verify -q $ref } | complete)
|
||||
if ($parse.stdout | is-empty) { false } else { true }
|
||||
}
|
||||
|
||||
# Notify the user that the `CHAT_TOKEN` hasn't been configured
|
||||
export const NO_TOKEN_TIP = (
|
||||
"**Notice:** It looks like you're using [`hustcer/deepseek-review`](https://github.com/hustcer/deepseek-review), but the `CHAT_TOKEN` hasn't" +
|
||||
"been configured in your repo's Variables/Secrets. Please ensure this token is set for proper functionality. For step-by-step guidance, refer" +
|
||||
"to the **CHAT_TOKEN Config** section of [README](https://github.com/hustcer/deepseek-review/blob/main/README.md#code-review-with-github-action).")
|
||||
|
||||
18
nu/config.nu
18
nu/config.nu
@@ -91,9 +91,9 @@ def check-models [options: record] {
|
||||
}
|
||||
|
||||
# Check if the config.yml file exists and if it's valid
|
||||
export def config-check [] {
|
||||
file-exists $SETTING_FILE
|
||||
let options = open $SETTING_FILE
|
||||
export def config-check [--config: string = $SETTING_FILE] {
|
||||
file-exists $config
|
||||
let options = open $config
|
||||
check-prompts $options
|
||||
check-providers $options
|
||||
check-models $options
|
||||
@@ -117,22 +117,17 @@ def get-model-envs [settings: record, model?: string = ''] {
|
||||
| get -i 0.name
|
||||
| default $model
|
||||
|
||||
{ CHAT_TOKEN: $provider.token?, BASE_URL: $provider.base-url?, CHAT_MODEL: $model_name }
|
||||
{ CHAT_TOKEN: $provider.token?, BASE_URL: $provider.base-url?, CHAT_URL: $provider.chat-url?, CHAT_MODEL: $model_name }
|
||||
}
|
||||
|
||||
# Load the config.yml file to the environment
|
||||
export def --env config-load [
|
||||
--debug(-d), # Print the loaded environment variables
|
||||
--repo(-r): string, # Load the specified local repository by name
|
||||
--config(-C): string, # The config file path, default to `config.yml`
|
||||
--model(-m): string, # Load the specified model by name
|
||||
] {
|
||||
let all_settings = open $SETTING_FILE
|
||||
let all_settings = open ($config | default $SETTING_FILE)
|
||||
let settings = $all_settings | get settings? | default {}
|
||||
let local_repo = $all_settings.local-repos
|
||||
| default []
|
||||
| where name == ($repo | default $settings.default-local-repo? | default '')
|
||||
| get -i 0.path
|
||||
| default $repo
|
||||
|
||||
let user_prompt = $all_settings.prompts?.user?
|
||||
| default []
|
||||
@@ -155,7 +150,6 @@ export def --env config-load [
|
||||
GITHUB_TOKEN: $settings.github-token,
|
||||
EXCLUDE_PATTERNS: $settings.exclude-patterns,
|
||||
INCLUDE_PATTERNS: $settings.include-patterns,
|
||||
DEFAULT_LOCAL_REPO: $local_repo,
|
||||
DEFAULT_GITHUB_REPO: $settings.default-github-repo,
|
||||
}
|
||||
load-env $env_vars
|
||||
|
||||
161
nu/review.nu
161
nu/review.nu
@@ -27,7 +27,7 @@
|
||||
|
||||
use kv.nu *
|
||||
use common.nu [
|
||||
ECODE, hr-line, is-installed, windows?, mac?,
|
||||
ECODE, NO_TOKEN_TIP, hr-line, is-installed, windows?, mac?,
|
||||
compare-ver, compact-record, git-check, has-ref,
|
||||
]
|
||||
|
||||
@@ -63,6 +63,7 @@ export def --env deepseek-review [
|
||||
--max-length(-l): int, # Maximum length of the content for review, 0 means no limit.
|
||||
--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 # 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
|
||||
@@ -71,21 +72,18 @@ export def --env deepseek-review [
|
||||
]: nothing -> nothing {
|
||||
|
||||
$env.config.table.mode = 'psql'
|
||||
let local_repo = $env.PWD
|
||||
let is_action = ($env.GITHUB_ACTIONS? == 'true')
|
||||
let stream = if $is_action { false } else { true }
|
||||
let token = $token | default $env.CHAT_TOKEN?
|
||||
let repo = $repo | default $env.DEFAULT_GITHUB_REPO?
|
||||
let CHAT_HEADER = [Authorization $'Bearer ($token)']
|
||||
let local_repo = $env.DEFAULT_LOCAL_REPO? | default (pwd)
|
||||
let model = $model | default $env.CHAT_MODEL? | default $DEFAULT_OPTIONS.MODEL
|
||||
let base_url = $base_url | default $env.BASE_URL? | default $DEFAULT_OPTIONS.BASE_URL
|
||||
let url = $chat_url | default $env.CHAT_URL? | default $'($base_url)/chat/completions'
|
||||
let max_length = try { $max_length | default ($env.MAX_LENGTH? | default 0 | into int) } catch { 0 }
|
||||
let temperature = try { $temperature | default $env.TEMPERATURE? | default $DEFAULT_OPTIONS.TEMPERATURE | into float } catch { $DEFAULT_OPTIONS.TEMPERATURE }
|
||||
if ($temperature < 0) or ($temperature > 2) {
|
||||
print $'(ansi r)Invalid temperature value, should be in the range of 0 to 2.(ansi reset)'
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
let url = $'($base_url)/chat/completions'
|
||||
validate-temperature $temperature
|
||||
let setting = {
|
||||
repo: $repo,
|
||||
model: $model,
|
||||
@@ -102,10 +100,7 @@ export def --env deepseek-review [
|
||||
}
|
||||
$env.GH_TOKEN = $gh_token | default $env.GITHUB_TOKEN?
|
||||
|
||||
if ($token | is-empty) {
|
||||
print $'(ansi r)Please provide your DeepSeek API token by setting `CHAT_TOKEN` or passing it as an argument.(ansi reset)'
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
validate-token $token --pr-number $pr_number --repo $repo
|
||||
let hint = if not $is_action and ($pr_number | is-empty) {
|
||||
$'🚀 Initiate the code review by DeepSeek AI for local changes ...'
|
||||
} else {
|
||||
@@ -138,12 +133,12 @@ export def --env deepseek-review [
|
||||
]
|
||||
}
|
||||
if $debug { print $'(char nl)Code Changes:'; hr-line; print $content }
|
||||
print $'(char nl)Waiting for response from (ansi g)($base_url)(ansi reset) ...'
|
||||
print $'(char nl)Waiting for response from (ansi g)($url)(ansi reset) ...'
|
||||
if $stream { streaming-output $url $payload --headers $CHAT_HEADER --debug=$debug; return }
|
||||
|
||||
let response = http post -e -H $CHAT_HEADER -t application/json $url $payload
|
||||
if ($response | is-empty) {
|
||||
print $'(ansi r)Oops, No response returned from ($base_url) ...(ansi reset)'
|
||||
print $'(ansi r)Oops, No response returned from ($url) ...(ansi reset)'
|
||||
exit $ECODE.SERVER_ERROR
|
||||
}
|
||||
if $debug { print $'DeepSeek Model Response:'; hr-line; $response | table -e | print }
|
||||
@@ -152,7 +147,7 @@ export def --env deepseek-review [
|
||||
exit $ECODE.SERVER_ERROR
|
||||
}
|
||||
let reason = $response | get -i choices.0.message.reasoning_content
|
||||
let review = $response | get -i choices.0.message.content
|
||||
let review = $response | get -i choices.0.message.content | default ($response | get -i 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) ...'
|
||||
@@ -162,12 +157,49 @@ export def --env deepseek-review [
|
||||
if not $is_action {
|
||||
print $'Code Review Result:'; hr-line; print $result
|
||||
} else {
|
||||
let BASE_HEADER = [Authorization $'Bearer ($env.GH_TOKEN)' Accept application/vnd.github.v3+json ...$HTTP_HEADERS]
|
||||
http post -t application/json -H $BASE_HEADER $'($GITHUB_API_BASE)/repos/($repo)/issues/($pr_number)/comments' { body: $result }
|
||||
post-comments-to-pr $repo $pr_number $result
|
||||
print $'✅ Code review finished!PR (ansi g)#($pr_number)(ansi reset) review result was posted as a comment.'
|
||||
}
|
||||
print $'(char nl)Token Usage:'; hr-line
|
||||
$response.usage | table -e | print
|
||||
if ($response.usage? | is-not-empty) {
|
||||
print $'(char nl)Token Usage:'; hr-line
|
||||
$response.usage? | table -e | print
|
||||
}
|
||||
}
|
||||
|
||||
# Validate the DeepSeek API token
|
||||
def validate-token [token?: string, --pr-number: string, --repo: string] {
|
||||
if ($token | is-empty) {
|
||||
print $'(ansi r)Please provide your DeepSeek API token by setting `CHAT_TOKEN` or passing it as an argument.(ansi reset)'
|
||||
if ($pr_number | is-not-empty) { post-comments-to-pr $repo $pr_number $NO_TOKEN_TIP }
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
$token
|
||||
}
|
||||
|
||||
# Validate the temperature value
|
||||
def validate-temperature [temp: float] {
|
||||
if ($temp < 0) or ($temp > 2) {
|
||||
print $'(ansi r)Invalid temperature value, should be in the range of 0 to 2.(ansi reset)'
|
||||
exit $ECODE.INVALID_PARAMETER
|
||||
}
|
||||
$temp
|
||||
}
|
||||
|
||||
# Post review comments to GitHub PR
|
||||
def post-comments-to-pr [
|
||||
repo: string, # GitHub repository name, e.g. hustcer/deepseek-review
|
||||
pr_number: string, # GitHub PR number
|
||||
comments: string, # Comments content to post
|
||||
] {
|
||||
let comment_url = $'($GITHUB_API_BASE)/repos/($repo)/issues/($pr_number)/comments'
|
||||
let BASE_HEADER = [Authorization $'Bearer ($env.GH_TOKEN)' Accept application/vnd.github.v3+json ...$HTTP_HEADERS]
|
||||
try {
|
||||
http post -t application/json -H $BASE_HEADER $comment_url { body: $comments }
|
||||
} catch {|err|
|
||||
print $'(ansi r)Failed to post comments to PR: (ansi reset)'
|
||||
$err | table -e | print
|
||||
exit $ECODE.SERVER_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
# Output the streaming response of review result from DeepSeek API
|
||||
@@ -185,7 +217,7 @@ def streaming-output [
|
||||
let res = $in
|
||||
let type = $res | describe
|
||||
let record_error = $type =~ '^record'
|
||||
let other_error = $type =~ '^string' and $res !~ 'data: '
|
||||
let other_error = $type =~ '^string' and $res !~ 'data: ' and $res !~ 'done'
|
||||
if $record_error or $other_error {
|
||||
$res | table -e | print
|
||||
exit $ECODE.SERVER_ERROR
|
||||
@@ -195,10 +227,11 @@ def streaming-output [
|
||||
| each {|line|
|
||||
if $line == $RESPONSE_END { return }
|
||||
if ($line | is-empty) { return }
|
||||
let $last = $line | str substring 6.. | from json
|
||||
# DeepSeek Response vs Local Ollama Response
|
||||
let $last = if $line =~ '^data: ' { $line | str substring 6.. | from json } else { $line | from json }
|
||||
if $last == '-alive' { print $last; return }
|
||||
if $debug { $last | to json | kv set last-reply }
|
||||
$last | get -i choices.0.delta | if ($in | is-not-empty) {
|
||||
$last | get -i choices.0.delta | default ($last | get -i message) | if ($in | is-not-empty) {
|
||||
let delta = $in
|
||||
if ($delta.reasoning_content? | is-not-empty) { kv set reasoning ((kv get reasoning) + 1) }
|
||||
if (kv get reasoning) == 1 { print $'(char nl)Reasoning Details:'; hr-line }
|
||||
@@ -224,16 +257,9 @@ export def get-diff [
|
||||
--exclude: string, # Comma separated file patterns to exclude in the code review
|
||||
--patch-cmd: string, # The `git show` or `git diff` command to get the diff content
|
||||
] {
|
||||
let local_repo = $env.PWD
|
||||
let BASE_HEADER = [Authorization $'Bearer ($env.GH_TOKEN)' Accept application/vnd.github.v3+json]
|
||||
let DIFF_HEADER = [Authorization $'Bearer ($env.GH_TOKEN)' Accept application/vnd.github.v3.diff]
|
||||
let local_repo = $env.DEFAULT_LOCAL_REPO? | default (pwd)
|
||||
if ($pr_number | is-empty) {
|
||||
if not ($local_repo | path exists) {
|
||||
print $'(ansi r)The directory ($local_repo) does not exist.(ansi reset)'
|
||||
exit $ECODE.CONDITION_NOT_SATISFIED
|
||||
}
|
||||
cd $local_repo
|
||||
}
|
||||
mut content = if ($pr_number | is-not-empty) {
|
||||
if ($repo | is-empty) {
|
||||
print $'(ansi r)Please provide the GitHub repository name by `--repo` option.(ansi reset)'
|
||||
@@ -335,11 +361,36 @@ export def prepare-awk [] {
|
||||
# 2. Convert ? to . (optional, as needed)
|
||||
# 3. Convert / to \/
|
||||
def glob-to-regex [patterns: list<string>] {
|
||||
# Handle empty patterns list
|
||||
if ($patterns | length) == 0 { return '' }
|
||||
|
||||
# Define a mapping of characters to escape
|
||||
let regex_escapes = {
|
||||
# Escape special regex characters first
|
||||
"\\.": "\\\\.",
|
||||
"\\+": "\\\\+",
|
||||
"\\^": "\\\\^",
|
||||
"\\$": "\\\\$",
|
||||
"\\(": "\\\\(",
|
||||
"\\)": "\\\\)",
|
||||
"\\[": "\\\\[",
|
||||
"\\]": "\\\\]",
|
||||
"\\{": "\\\\{",
|
||||
"\\}": "\\\\}",
|
||||
"\\|": "\\\\|",
|
||||
# Then convert glob patterns to regex patterns
|
||||
"*": ".*",
|
||||
"?": ".",
|
||||
"/": "\\/",
|
||||
}
|
||||
|
||||
$patterns
|
||||
| each { |pat|
|
||||
$pat | str replace "*" ".*" | str replace "?" "." | str replace "/" "\\/"
|
||||
$regex_escapes | columns | reduce -f $pat { |k, acc|
|
||||
$acc | str replace -a $k ($regex_escapes | get $k)
|
||||
}
|
||||
}
|
||||
| str join "|"
|
||||
| str join '|'
|
||||
}
|
||||
|
||||
# Generate the awk include regex pattern string for the specified patterns
|
||||
@@ -359,57 +410,17 @@ export def generate-exclude-regex [patterns: list<string>] {
|
||||
# - git show
|
||||
# - git diff
|
||||
# - git show head~1
|
||||
# - git diff --since=2025-02-09 HEAD
|
||||
# - git diff 2393375 71f5a31
|
||||
# - git diff 2393375 71f5a31 nu/*
|
||||
# - git diff 2393375 71f5a31 :!nu/*
|
||||
export def is-safe-git [cmd: string] {
|
||||
# Normalize the command string by trimming and converting to lowercase
|
||||
let normalized_cmd = ($cmd | str trim | str downcase)
|
||||
|
||||
# More strict regex for git commands, allow:
|
||||
# 1. --since parameter with ISO date format
|
||||
# 2. File path patterns with or without colon (e.g. :!nu/*, nu/*)
|
||||
let allowed_regex = '^git\s+(show|diff)(?:\s+(?:--since=\d{4}-\d{2}-\d{2}|[a-zA-Z0-9_\-\.~/]+))*(?:\s+(?::[!]?)?[a-zA-Z0-9_\-\.\*\/]+)?$'
|
||||
# Define allowed command patterns with named capture groups for better validation
|
||||
let git_cmd_pattern = '^git\s+(show|diff)(?:\s+(?:[a-zA-Z0-9_\-\.~/]+)){0,3}(?:\s+(?::[!]?)?[a-zA-Z0-9_\-\.\*\/]+){0,2}$'
|
||||
|
||||
# Dangerous patterns to check (expanded list)
|
||||
let dangerous_patterns = [
|
||||
# Command chaining/injection
|
||||
';', '&&', '||', '|',
|
||||
# Shell expansion
|
||||
'?', '[', ']', '{', '}',
|
||||
# Command substitution
|
||||
'`', '$(',
|
||||
# IO redirection
|
||||
'>', '>>', '<', '<<',
|
||||
# Special characters
|
||||
'\n', '\r', '\t',
|
||||
# Path traversal
|
||||
'..',
|
||||
# Environment variables
|
||||
'$', '%',
|
||||
# Quotes that might be used for injection
|
||||
'"', "'"
|
||||
]
|
||||
|
||||
# First check: Command must match the allowed pattern
|
||||
if ($normalized_cmd | find -r $allowed_regex | is-empty) {
|
||||
print $'ERROR: Invalid git command format. (ansi r)Only simple `git show` or `git diff` commands are allowed(ansi reset).'
|
||||
return false
|
||||
}
|
||||
|
||||
# Second check: No dangerous patterns allowed
|
||||
for pattern in $dangerous_patterns {
|
||||
if ($cmd | str contains $pattern) {
|
||||
print $'(ansi r)ERROR: Dangerous pattern detected: `($pattern)`(ansi reset)'
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
# Third check: Command parts validation (increased limit to accommodate path patterns)
|
||||
let cmd_parts = $normalized_cmd | split row ' '
|
||||
if ($cmd_parts | length) > 6 {
|
||||
print $'ERROR: Command too complex. (ansi r)Only simple `git show` or `git diff` commands are allowed(ansi reset).'
|
||||
if ($normalized_cmd | find -r $git_cmd_pattern | is-empty) {
|
||||
print $'(ansi r)Invalid git command format. (ansi g)Only simple `git show` or `git diff` commands are allowed.(ansi reset)'
|
||||
return false
|
||||
}
|
||||
true
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
|
||||
use std/assert
|
||||
|
||||
use ../nu/common.nu [compare-ver, 'from env', is-installed, has-ref, git-check, compact-record]
|
||||
use ../nu/common.nu [
|
||||
compare-ver, 'from env', is-installed, has-ref,
|
||||
git-check, compact-record, is-repo, windows?, mac?,
|
||||
]
|
||||
|
||||
#[test]
|
||||
def 'compare-ver:v1.0.0 is greater than v0.999.0' [] {
|
||||
@@ -52,6 +55,11 @@ def 'has-ref:git repo should has HEAD ref' [] {
|
||||
assert equal (has-ref 0000) false
|
||||
}
|
||||
|
||||
#[test]
|
||||
def 'is-repo:current dir is a git repo' [] {
|
||||
assert equal (is-repo) true
|
||||
}
|
||||
|
||||
#[test]
|
||||
def 'git-check:current dir is a git repo' [] {
|
||||
assert equal (git-check (pwd) --check-repo=1) true
|
||||
@@ -62,3 +70,31 @@ def 'compact-record:should work as expected' [] {
|
||||
assert equal ({a: null, b: '', c: 'abc' } | compact-record) { c: 'abc' }
|
||||
assert equal ({a: null, b: 0, c: 1, e: { f: 'g' } } | compact-record) { b: 0, c: 1, e: { f: 'g' } }
|
||||
}
|
||||
|
||||
#[test]
|
||||
def 'OS check should work as expected' [] {
|
||||
# `$env.RUNNER_OS` Possible values are Linux, Windows, or macOS in GitHub Actions
|
||||
match $nu.os-info.name {
|
||||
'windows' => {
|
||||
assert equal (mac?) false
|
||||
assert equal (windows?) true
|
||||
if ($env.RUNNER_OS? | is-not-empty) {
|
||||
assert equal $env.RUNNER_OS Windows
|
||||
}
|
||||
}
|
||||
'macos' => {
|
||||
assert equal (mac?) true
|
||||
assert equal (windows?) false
|
||||
if ($env.RUNNER_OS? | is-not-empty) {
|
||||
assert equal $env.RUNNER_OS macOS
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
assert equal (mac?) false
|
||||
assert equal (windows?) false
|
||||
if ($env.RUNNER_OS? | is-not-empty) {
|
||||
assert equal $env.RUNNER_OS Linux
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,13 @@ def 'is-safe-git:should work as expected' [] {
|
||||
assert equal (is-safe-git 'git checkout') false
|
||||
assert equal (is-safe-git 'git show 0dd0eb5') true
|
||||
assert equal (is-safe-git 'git show HEAD') true
|
||||
assert equal (is-safe-git 'git show head~1') true
|
||||
assert equal (is-safe-git 'git diff HEAD~2') true
|
||||
assert equal (is-safe-git 'git diff head~3 main') true
|
||||
assert equal (is-safe-git 'git diff f536acc 0dd0eb5') true
|
||||
assert equal (is-safe-git 'git show 2393375 | less') false
|
||||
assert equal (is-safe-git 'git show 2393375>diff.patch') false
|
||||
assert equal (is-safe-git 'git show 2393375 o+e>diff.patch') false
|
||||
assert equal (is-safe-git 'git diff f536acc 0dd0eb5 nu/*') true
|
||||
assert equal (is-safe-git 'git diff f536acc 0dd0eb5 :!nu/*') true
|
||||
assert equal (is-safe-git 'git diff f536acc 0dd0eb5 :!nu/*; rm -rf abc') false
|
||||
|
||||
Reference in New Issue
Block a user