@woodpeck/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +205 -0
  2. package/bin/wood +9 -0
  3. package/install.js +117 -0
  4. package/package.json +50 -0
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # Woodpeck 🐦 / Wood 啄木鸟
2
+
3
+ 基于 Git diff 的智能代码审查 CLI 工具,使用 Rust 编写。
4
+
5
+ ## ✨ 特性
6
+
7
+ - 🔴 **严重级别**: unwrap()、unsafe 代码块、硬编码密钥等
8
+ - 🟡 **中等级别**: TODO/FIXME、未使用变量、资源泄露等
9
+ - 🟢 **初级别**: 魔法数字、长函数、代码风格等
10
+ - 📊 **多格式输出**: Table/JSON/Markdown/SARIF
11
+ - 🔧 **CI/CD 集成**: 支持失败阈值控制
12
+
13
+ ## 📦 安装
14
+
15
+ ### 方式 1: 直接下载二进制文件
16
+
17
+ #### macOS
18
+ ```bash
19
+ # Intel
20
+ curl -L -o wood.tar.gz https://github.com/yourusername/woodpeck/releases/latest/download/wood-macos-x64.tar.gz
21
+ tar xzf wood.tar.gz
22
+ sudo mv wood /usr/local/bin/
23
+
24
+ # Apple Silicon
25
+ curl -L -o wood.tar.gz https://github.com/yourusername/woodpeck/releases/latest/download/wood-macos-arm64.tar.gz
26
+ tar xzf wood.tar.gz
27
+ sudo mv wood /usr/local/bin/
28
+ ```
29
+
30
+ #### Linux
31
+ ```bash
32
+ curl -L -o wood.tar.gz https://github.com/yourusername/woodpeck/releases/latest/download/wood-linux-x64.tar.gz
33
+ tar xzf wood.tar.gz
34
+ sudo mv wood /usr/local/bin/
35
+ ```
36
+
37
+ #### Windows
38
+ 下载 [wood-windows-x64.exe](https://github.com/yourusername/woodpeck/releases) 并重命名为 `wood.exe`,添加到 PATH。
39
+
40
+ ### 方式 2: 通过 npm 安装
41
+ ```bash
42
+ npm install -g @woodpeck/cli
43
+ ```
44
+
45
+ ### 方式 3: 从源码编译
46
+ ```bash
47
+ git clone https://github.com/yourusername/woodpeck.git
48
+ cd woodpeck
49
+ cargo build --release
50
+ sudo cp target/release/woodpeck /usr/local/bin/wood
51
+ ```
52
+
53
+ ## 🚀 使用
54
+
55
+ ### 查看帮助
56
+ ```bash
57
+ wood -h
58
+ wood compare -h
59
+ ```
60
+
61
+ ### 基础分析
62
+ ```bash
63
+ # 对比两个分支
64
+ wood compare main feature-branch
65
+
66
+ # 指定仓库路径
67
+ wood compare main feature-branch --path=/path/to/repo
68
+
69
+ # 只显示严重问题
70
+ wood compare main feature-branch --severity=high
71
+ ```
72
+
73
+ ### 输出格式
74
+ ```bash
75
+ # JSON 格式
76
+ wood compare main feature-branch --format=json
77
+
78
+ # Markdown 格式(适合 PR 描述)
79
+ wood compare main feature-branch --format=markdown
80
+
81
+ # 导出到文件
82
+ wood compare main feature-branch --output=report.md
83
+ ```
84
+
85
+ ### CI/CD 集成
86
+ ```bash
87
+ # 如果有严重问题则 CI 失败
88
+ wood compare main feature-branch --fail-on=high:0
89
+
90
+ # 允许最多 5 个中等问题
91
+ wood compare main feature-branch --fail-on=medium:5
92
+ ```
93
+
94
+ ## 📊 输出示例
95
+
96
+ ```
97
+ Woodpeck Analysis Report
98
+ main → feature/test
99
+
100
+ +-----------+---------+------+---------------------+----------------------------------+
101
+ | Severity | File | Line | Rule | Description |
102
+ +=======================================================================================+
103
+ | 🔴 High | main.rs | 3 | RUST_UNWRAP_IN_PROD | Using unwrap() can cause panics |
104
+ |-----------+---------+------+---------------------+----------------------------------|
105
+ | 🟡 Medium | main.rs | 10 | RUST_TODO | TODO comment found |
106
+ |-----------+---------+------+---------------------+----------------------------------|
107
+ | 🟢 Low | main.rs | 13 | RUST_MAGIC_NUMBER | Unnamed numeric constant |
108
+ +-----------+---------+------+---------------------+----------------------------------+
109
+
110
+ Summary:
111
+ Total files: 1
112
+ Total issues: 3
113
+ 🔴 High: 1
114
+ 🟡 Medium: 1
115
+ 🟢 Low: 1
116
+ ```
117
+
118
+ ## ⚙️ 配置
119
+
120
+ 创建 `woodpeck.toml` 配置文件:
121
+
122
+ ```toml
123
+ # 默认只显示严重和中等问题
124
+ default_severity = "medium"
125
+
126
+ # 默认 JSON 格式
127
+ default_format = "json"
128
+
129
+ [output]
130
+ color = "auto"
131
+ show_summary = true
132
+
133
+ [rules.overrides.RUST_UNWRAP_IN_PROD]
134
+ enabled = true
135
+ severity = "high"
136
+ ```
137
+
138
+ ## 🔌 GitHub Actions 集成
139
+
140
+ ```yaml
141
+ name: Code Review
142
+
143
+ on: [pull_request]
144
+
145
+ jobs:
146
+ woodpeck:
147
+ runs-on: ubuntu-latest
148
+ steps:
149
+ - uses: actions/checkout@v3
150
+ with:
151
+ fetch-depth: 0
152
+
153
+ - name: Download Woodpeck
154
+ run: |
155
+ curl -L -o wood.tar.gz https://github.com/yourusername/woodpeck/releases/latest/download/wood-linux-x64.tar.gz
156
+ tar xzf wood.tar.gz
157
+ chmod +x wood
158
+ sudo mv wood /usr/local/bin/
159
+
160
+ - name: Run Woodpeck
161
+ run: wood compare origin/main HEAD --fail-on=high:0
162
+ ```
163
+
164
+ ## 🛠️ 开发
165
+
166
+ ### 构建
167
+ ```bash
168
+ cargo build --release
169
+ ```
170
+
171
+ ### 测试
172
+ ```bash
173
+ cargo test
174
+ ```
175
+
176
+ ### 运行
177
+ ```bash
178
+ cargo run -- compare main feature-branch
179
+ ```
180
+
181
+ ## 📋 支持的规则
182
+
183
+ | 规则 ID | 级别 | 描述 |
184
+ |---------|------|------|
185
+ | RUST_UNWRAP_IN_PROD | 🔴 High | 生产代码中使用 unwrap() |
186
+ | RUST_UNSAFE_BLOCK | 🔴 High | unsafe 代码块 |
187
+ | JS_DANGEROUS_EVAL | 🔴 High | 使用 eval() |
188
+ | RUST_TODO | 🟡 Medium | TODO/FIXME/XXX 注释 |
189
+ | RUST_UNUSED_VARIABLE | 🟡 Medium | 未使用的变量 |
190
+ | RUST_MAGIC_NUMBER | 🟢 Low | 魔法数字 |
191
+ | RUST_LONG_FUNCTION | 🟢 Low | 过长的函数 |
192
+
193
+ ## 📄 许可证
194
+
195
+ MIT
196
+
197
+ ## 🤝 贡献
198
+
199
+ 欢迎提交 Issue 和 PR!
200
+
201
+ ## 🙏 鸣谢
202
+
203
+ - [clap](https://github.com/clap-rs/clap) - CLI 框架
204
+ - [git2](https://github.com/rust-lang/git2-rs) - Git 操作
205
+ - [regex](https://github.com/rust-lang/regex) - 正则表达式
package/bin/wood ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ const path = require('path');
3
+ const { spawn } = require('child_process');
4
+
5
+ const binary = path.join(__dirname, process.platform === 'win32' ? 'wood.exe' : 'wood');
6
+ const args = process.argv.slice(2);
7
+
8
+ const child = spawn(binary, args, { stdio: 'inherit' });
9
+ child.on('exit', (code) => process.exit(code));
package/install.js ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const https = require('https');
7
+ const { platform, arch } = process;
8
+
9
+ const VERSION = require('./package.json').version;
10
+ const REPO = 'yourusername/woodpeck';
11
+
12
+ function getBinaryName() {
13
+ const platformMap = {
14
+ 'darwin': 'macos',
15
+ 'linux': 'linux',
16
+ 'win32': 'windows'
17
+ };
18
+
19
+ const archMap = {
20
+ 'x64': 'x64',
21
+ 'arm64': 'arm64'
22
+ };
23
+
24
+ const platformName = platformMap[platform];
25
+ const archName = archMap[arch] || 'x64';
26
+
27
+ if (!platformName) {
28
+ throw new Error(`不支持的平台: ${platform}`);
29
+ }
30
+
31
+ if (platform === 'win32') {
32
+ return `wood-${platformName}-${archName}.exe`;
33
+ }
34
+ return `wood-${platformName}-${archName}`;
35
+ }
36
+
37
+ function getDownloadUrl() {
38
+ const binaryName = getBinaryName();
39
+ return `https://github.com/${REPO}/releases/download/v${VERSION}/${binaryName}`;
40
+ }
41
+
42
+ function downloadFile(url, dest) {
43
+ return new Promise((resolve, reject) => {
44
+ const file = fs.createWriteStream(dest);
45
+ https.get(url, (response) => {
46
+ if (response.statusCode === 302 || response.statusCode === 301) {
47
+ downloadFile(response.headers.location, dest)
48
+ .then(resolve)
49
+ .catch(reject);
50
+ return;
51
+ }
52
+
53
+ if (response.statusCode !== 200) {
54
+ reject(new Error(`下载失败,状态码: ${response.statusCode}`));
55
+ return;
56
+ }
57
+
58
+ response.pipe(file);
59
+ file.on('finish', () => {
60
+ file.close();
61
+ resolve();
62
+ });
63
+ }).on('error', (err) => {
64
+ fs.unlink(dest, () => {});
65
+ reject(err);
66
+ });
67
+ });
68
+ }
69
+
70
+ async function install() {
71
+ try {
72
+ const binaryName = getBinaryName();
73
+ const binDir = path.join(__dirname, 'bin');
74
+ const binaryPath = path.join(binDir, platform === 'win32' ? 'wood.exe' : 'wood');
75
+
76
+ // 创建 bin 目录
77
+ if (!fs.existsSync(binDir)) {
78
+ fs.mkdirSync(binDir, { recursive: true });
79
+ }
80
+
81
+ // 如果本地已存在二进制文件,跳过下载
82
+ if (fs.existsSync(binaryPath)) {
83
+ console.log('✓ 二进制文件已存在,跳过下载');
84
+ return;
85
+ }
86
+
87
+ console.log(`正在下载 wood ${VERSION}...`);
88
+ console.log(`平台: ${platform} (${arch})`);
89
+ console.log(`目标: ${binaryName}`);
90
+
91
+ // 开发阶段:从本地复制
92
+ const localBinary = path.join(__dirname, 'target', 'release', 'wood');
93
+ if (fs.existsSync(localBinary)) {
94
+ console.log('使用本地构建的二进制文件...');
95
+ fs.copyFileSync(localBinary, binaryPath);
96
+ } else {
97
+ // 生产阶段:从 GitHub 下载
98
+ const url = getDownloadUrl();
99
+ console.log(`下载地址: ${url}`);
100
+ await downloadFile(url, binaryPath);
101
+ }
102
+
103
+ // 设置执行权限
104
+ if (platform !== 'win32') {
105
+ fs.chmodSync(binaryPath, 0o755);
106
+ }
107
+
108
+ console.log('✓ 安装完成!');
109
+ console.log(`运行: wood --help`);
110
+
111
+ } catch (error) {
112
+ console.error('安装失败:', error.message);
113
+ process.exit(1);
114
+ }
115
+ }
116
+
117
+ install();
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@woodpeck/cli",
3
+ "version": "0.1.0",
4
+ "description": "基于 Git diff 的代码审查工具 - 发现代码中的潜在问题",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "wood": "./bin/wood",
8
+ "woodpeck": "./bin/wood"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "node install.js",
12
+ "test": "echo \"Binary only package, no tests\""
13
+ },
14
+ "keywords": [
15
+ "code-review",
16
+ "git",
17
+ "static-analysis",
18
+ "rust",
19
+ "cli",
20
+ "code-quality"
21
+ ],
22
+ "author": "Woodpeck Team",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/jxhhdx/Woodpeck.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/jxhhdx/Woodpeck/issues"
30
+ },
31
+ "homepage": "https://github.com/jxhhdx/Woodpeck#readme",
32
+ "engines": {
33
+ "node": ">=14.0.0"
34
+ },
35
+ "os": [
36
+ "darwin",
37
+ "linux",
38
+ "win32"
39
+ ],
40
+ "cpu": [
41
+ "x64",
42
+ "arm64"
43
+ ],
44
+ "files": [
45
+ "bin/",
46
+ "install.js",
47
+ "README.md",
48
+ "LICENSE"
49
+ ]
50
+ }