gitlab-ai-review 1.0.0 → 1.0.3

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.
package/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # GitLab AI Review SDK
2
2
 
3
- GitLab AI Review SDK - 测试版本
3
+ GitLab AI Review SDK - 支持 CI/CD 自动配置和手动配置
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ 封装 GitLab API 客户端
8
+ - ✅ CI/CD 环境自动检测配置
9
+ - ✅ 支持手动传递配置
10
+ - ✅ 获取项目和 MR 信息
11
+ - ✅ 添加 MR 评论
4
12
 
5
13
  ## 安装
6
14
 
@@ -8,16 +16,163 @@ GitLab AI Review SDK - 测试版本
8
16
  npm install gitlab-ai-review
9
17
  ```
10
18
 
11
- ## 使用
19
+ ## 使用方式
20
+
21
+ ### 方式 1:CI/CD 自动配置(推荐)
22
+
23
+ 在 GitLab CI/CD 环境中,SDK 会自动检测环境变量:
12
24
 
13
25
  ```javascript
14
26
  import GitLabAIReview from 'gitlab-ai-review';
15
27
 
28
+ // 自动从环境变量读取配置
16
29
  const sdk = new GitLabAIReview();
17
- console.log(sdk.test());
30
+
31
+ // 获取 MR 信息
32
+ const mr = await sdk.getMergeRequest();
33
+ console.log('MR 标题:', mr.title);
34
+
35
+ // 添加评论
36
+ await sdk.addComment('✅ AI 代码审查完成!');
18
37
  ```
19
38
 
20
- ## 版本
39
+ **自动检测的环境变量:**
40
+ - `CI_JOB_TOKEN` 或 `GITLAB_TOKEN` - GitLab Token
41
+ - `CI_SERVER_URL` 或 `GITLAB_URL` - GitLab 地址
42
+ - `CI_PROJECT_PATH` 或 `PROJECT_ID` - 项目 ID
43
+ - `CI_MERGE_REQUEST_IID` 或 `MERGE_REQUEST_IID` - MR 编号
44
+
45
+ ### 方式 2:手动传递配置
46
+
47
+ ```javascript
48
+ import GitLabAIReview from 'gitlab-ai-review';
49
+
50
+ // 手动传递配置
51
+ const sdk = new GitLabAIReview({
52
+ token: 'your-gitlab-token',
53
+ url: 'https://gitlab.com',
54
+ projectId: 'group/project',
55
+ mergeRequestIid: 123,
56
+ });
57
+
58
+ // 获取项目信息
59
+ const project = await sdk.getProject();
60
+ console.log('项目名:', project.name);
61
+
62
+ // 获取 MR 信息
63
+ const mr = await sdk.getMergeRequest();
64
+ console.log('MR 标题:', mr.title);
65
+
66
+ // 添加评论
67
+ await sdk.addComment('✅ 代码审查通过!');
68
+ ```
69
+
70
+ ## API 文档
71
+
72
+ ### 构造函数
73
+
74
+ ```javascript
75
+ new GitLabAIReview(options)
76
+ ```
77
+
78
+ **参数:**
79
+ - `options.token` - GitLab Token(可选,CI/CD 中自动获取)
80
+ - `options.url` - GitLab 地址(可选,默认 `https://gitlab.com`)
81
+ - `options.projectId` - 项目 ID(可选,CI/CD 中自动获取)
82
+ - `options.mergeRequestIid` - MR 编号(可选,CI/CD 中自动获取)
83
+
84
+ ### 方法
85
+
86
+ #### `validate()`
87
+ 验证配置是否完整
88
+
89
+ ```javascript
90
+ sdk.validate(); // 返回 true 或抛出错误
91
+ ```
92
+
93
+ #### `getConfig()`
94
+ 获取当前配置
95
+
96
+ ```javascript
97
+ const config = sdk.getConfig();
98
+ console.log(config.gitlab.url);
99
+ console.log(config.project.projectId);
100
+ ```
101
+
102
+ #### `getProject()`
103
+ 获取项目信息
21
104
 
22
- 1.0.0 - 初始测试版本
105
+ ```javascript
106
+ const project = await sdk.getProject();
107
+ console.log(project.name);
108
+ console.log(project.description);
109
+ ```
110
+
111
+ #### `getMergeRequest()`
112
+ 获取 MR 信息
113
+
114
+ ```javascript
115
+ const mr = await sdk.getMergeRequest();
116
+ console.log(mr.title);
117
+ console.log(mr.author.name);
118
+ ```
119
+
120
+ #### `getMergeRequestChanges()`
121
+ 获取 MR 的代码变更
122
+
123
+ ```javascript
124
+ const changes = await sdk.getMergeRequestChanges();
125
+ changes.forEach(change => {
126
+ console.log('文件:', change.new_path);
127
+ console.log('Diff:', change.diff);
128
+ });
129
+ ```
130
+
131
+ #### `addComment(body)`
132
+ 在 MR 上添加评论
133
+
134
+ ```javascript
135
+ await sdk.addComment('✅ 代码审查通过!');
136
+ ```
137
+
138
+ ## 在 GitLab CI/CD 中使用
139
+
140
+ `.gitlab-ci.yml` 示例:
141
+
142
+ ```yaml
143
+ stages:
144
+ - review
145
+
146
+ ai-review:
147
+ stage: review
148
+ image: node:18
149
+ only:
150
+ - merge_requests
151
+ script:
152
+ - npm install gitlab-ai-review
153
+ - node review.js
154
+ ```
155
+
156
+ `review.js` 示例:
157
+
158
+ ```javascript
159
+ import GitLabAIReview from 'gitlab-ai-review';
160
+
161
+ const sdk = new GitLabAIReview();
162
+
163
+ // 获取 MR 信息
164
+ const mr = await sdk.getMergeRequest();
165
+ console.log('正在审查 MR:', mr.title);
166
+
167
+ // 获取代码变更
168
+ const changes = await sdk.getMergeRequestChanges();
169
+ console.log(`共有 ${changes.length} 个文件变更`);
170
+
171
+ // 添加评论
172
+ await sdk.addComment('🤖 AI 代码审查已完成!');
173
+ ```
174
+
175
+ ## 版本
23
176
 
177
+ - 1.0.1 - 添加 GitLab 客户端封装和自动配置
178
+ - 1.0.0 - 初始测试版本
package/index.js CHANGED
@@ -1,12 +1,115 @@
1
1
  /**
2
2
  * GitLab AI Review SDK
3
- * 测试版本 - 最小化实现
3
+ * 支持 CI/CD 自动配置和手动配置
4
4
  */
5
5
 
6
+ import { getConfig, validateConfig } from './lib/config.js';
7
+ import { GitLabClient } from './lib/gitlab-client.js';
8
+
9
+ /**
10
+ * GitLab AI Review SDK 主类
11
+ */
6
12
  export class GitLabAIReview {
7
- constructor() {
13
+ constructor(options = {}) {
8
14
  this.name = 'GitLab AI Review SDK';
9
15
  this.version = '1.0.0';
16
+
17
+ // 如果传入了配置,使用手动配置;否则使用自动检测
18
+ if (options.token || options.gitlab) {
19
+ // 手动配置模式
20
+ this.config = {
21
+ gitlab: {
22
+ token: options.token || options.gitlab?.token,
23
+ url: options.url || options.gitlab?.url || 'https://gitlab.com',
24
+ },
25
+ project: {
26
+ projectId: options.projectId || options.project?.projectId,
27
+ mergeRequestIid: options.mergeRequestIid || options.project?.mergeRequestIid,
28
+ },
29
+ };
30
+ } else {
31
+ // 自动检测模式(CI/CD)
32
+ this.config = getConfig();
33
+ }
34
+
35
+ // 创建 GitLab 客户端
36
+ this.gitlabClient = new GitLabClient({
37
+ token: this.config.gitlab.token,
38
+ host: this.config.gitlab.url,
39
+ });
40
+ }
41
+
42
+ /**
43
+ * 验证配置
44
+ */
45
+ validate() {
46
+ return validateConfig(this.config);
47
+ }
48
+
49
+ /**
50
+ * 获取当前配置
51
+ */
52
+ getConfig() {
53
+ return this.config;
54
+ }
55
+
56
+ /**
57
+ * 获取项目信息
58
+ */
59
+ async getProject() {
60
+ if (!this.config.project.projectId) {
61
+ throw new Error('未配置项目 ID');
62
+ }
63
+ return this.gitlabClient.getProject(this.config.project.projectId);
64
+ }
65
+
66
+ /**
67
+ * 获取 MR 信息
68
+ */
69
+ async getMergeRequest() {
70
+ if (!this.config.project.projectId) {
71
+ throw new Error('未配置项目 ID');
72
+ }
73
+ if (!this.config.project.mergeRequestIid) {
74
+ throw new Error('未配置 MR IID');
75
+ }
76
+ return this.gitlabClient.getMergeRequest(
77
+ this.config.project.projectId,
78
+ this.config.project.mergeRequestIid
79
+ );
80
+ }
81
+
82
+ /**
83
+ * 获取 MR 的代码变更
84
+ */
85
+ async getMergeRequestChanges() {
86
+ if (!this.config.project.projectId) {
87
+ throw new Error('未配置项目 ID');
88
+ }
89
+ if (!this.config.project.mergeRequestIid) {
90
+ throw new Error('未配置 MR IID');
91
+ }
92
+ return this.gitlabClient.getMergeRequestChanges(
93
+ this.config.project.projectId,
94
+ this.config.project.mergeRequestIid
95
+ );
96
+ }
97
+
98
+ /**
99
+ * 在 MR 上添加评论
100
+ */
101
+ async addComment(body) {
102
+ if (!this.config.project.projectId) {
103
+ throw new Error('未配置项目 ID');
104
+ }
105
+ if (!this.config.project.mergeRequestIid) {
106
+ throw new Error('未配置 MR IID');
107
+ }
108
+ return this.gitlabClient.createMergeRequestNote(
109
+ this.config.project.projectId,
110
+ this.config.project.mergeRequestIid,
111
+ body
112
+ );
10
113
  }
11
114
 
12
115
  /**
@@ -17,6 +120,9 @@ export class GitLabAIReview {
17
120
  }
18
121
  }
19
122
 
123
+ // 导出工具函数
124
+ export { getConfig, validateConfig } from './lib/config.js';
125
+ export { GitLabClient } from './lib/gitlab-client.js';
126
+
20
127
  // 默认导出
21
128
  export default GitLabAIReview;
22
-
package/lib/config.js ADDED
@@ -0,0 +1,150 @@
1
+ /**
2
+ * 配置模块 - 自动检测 CI/CD 环境变量
3
+ * 参考 review-bot/config.js 的实现
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+
9
+ /**
10
+ * 读取项目根目录下的 AI Review Guard 配置文件
11
+ */
12
+ function readAIReviewGuardConfig() {
13
+ const configFiles = ['.aireviewguard', 'aireviewguard', '.aireviewguard.json', 'reviewguard.md', '.reviewguard.md'];
14
+
15
+ for (const filename of configFiles) {
16
+ try {
17
+ const configPath = path.join(process.cwd(), filename);
18
+ if (fs.existsSync(configPath)) {
19
+ const content = fs.readFileSync(configPath, 'utf-8');
20
+
21
+ // 如果是 Markdown 文件,返回原始内容
22
+ if (filename.endsWith('.md')) {
23
+ return {
24
+ type: 'markdown',
25
+ filename,
26
+ content,
27
+ };
28
+ }
29
+
30
+ // 尝试解析 JSON,如果失败则返回纯文本
31
+ try {
32
+ return {
33
+ type: 'json',
34
+ filename,
35
+ ...JSON.parse(content),
36
+ };
37
+ } catch {
38
+ return {
39
+ type: 'text',
40
+ filename,
41
+ content,
42
+ };
43
+ }
44
+ }
45
+ } catch (error) {
46
+ // 忽略读取错误,继续尝试下一个文件
47
+ }
48
+ }
49
+
50
+ return null;
51
+ }
52
+
53
+ /**
54
+ * 获取 GitLab 配置(支持自动检测 CI 环境)
55
+ */
56
+ export function getGitLabConfig() {
57
+ // Token 优先级:GITLAB_TOKEN > CI_JOB_TOKEN
58
+ const token = process.env.GITLAB_TOKEN ||
59
+ process.env.CI_JOB_TOKEN ||
60
+ '';
61
+
62
+ // GitLab URL 优先级:GITLAB_URL > CI_SERVER_URL > 默认值
63
+ let url = process.env.GITLAB_URL;
64
+ if (!url && process.env.CI_SERVER_URL) {
65
+ url = process.env.CI_SERVER_URL;
66
+ } else if (!url && process.env.CI_API_V4_URL) {
67
+ // 从 API URL 推导(移除 /api/v4)
68
+ url = process.env.CI_API_V4_URL.replace(/\/api\/v4\/?$/, '');
69
+ } else if (!url) {
70
+ url = 'https://gitlab.com';
71
+ }
72
+
73
+ return { token, url };
74
+ }
75
+
76
+ /**
77
+ * 获取 AI 配置(ARK API Key)
78
+ */
79
+ export function getAIConfig() {
80
+ // 从环境变量读取 ARK_API_KEY
81
+ const arkApiKey = process.env.ARK_API_KEY || '';
82
+
83
+ // 从配置文件读取其他配置
84
+ const guardConfig = readAIReviewGuardConfig();
85
+
86
+ return {
87
+ arkApiKey,
88
+ guardConfig,
89
+ };
90
+ }
91
+
92
+ /**
93
+ * 获取项目配置(支持自动检测 CI 环境)
94
+ */
95
+ export function getProjectConfig() {
96
+ // 项目 ID:PROJECT_ID > CI_PROJECT_ID > CI_PROJECT_PATH
97
+ let projectId = process.env.PROJECT_ID || process.env.CI_PROJECT_ID;
98
+
99
+ if (!projectId && process.env.CI_PROJECT_NAMESPACE && process.env.CI_PROJECT_NAME) {
100
+ projectId = `${process.env.CI_PROJECT_NAMESPACE}/${process.env.CI_PROJECT_NAME}`;
101
+ }
102
+
103
+ if (!projectId && process.env.CI_PROJECT_PATH) {
104
+ projectId = process.env.CI_PROJECT_PATH;
105
+ }
106
+
107
+ // MR IID:MERGE_REQUEST_IID > CI_MERGE_REQUEST_IID
108
+ const mergeRequestIid = process.env.MERGE_REQUEST_IID ||
109
+ process.env.CI_MERGE_REQUEST_IID ||
110
+ '';
111
+
112
+ return { projectId, mergeRequestIid };
113
+ }
114
+
115
+ /**
116
+ * 获取完整配置
117
+ */
118
+ export function getConfig() {
119
+ const gitlab = getGitLabConfig();
120
+ const project = getProjectConfig();
121
+ const ai = getAIConfig();
122
+
123
+ return {
124
+ gitlab,
125
+ project,
126
+ ai,
127
+ };
128
+ }
129
+
130
+ /**
131
+ * 验证配置
132
+ */
133
+ export function validateConfig(config) {
134
+ const errors = [];
135
+
136
+ if (!config.gitlab.token) {
137
+ errors.push('缺少 GitLab Token');
138
+ }
139
+
140
+ if (!config.project.projectId) {
141
+ errors.push('缺少项目 ID');
142
+ }
143
+
144
+ if (errors.length > 0) {
145
+ throw new Error('配置验证失败: ' + errors.join(', '));
146
+ }
147
+
148
+ return true;
149
+ }
150
+
@@ -0,0 +1,87 @@
1
+ /**
2
+ * GitLab API 客户端封装
3
+ * 简化版,仅包含基础功能
4
+ */
5
+
6
+ export class GitLabClient {
7
+ constructor(options = {}) {
8
+ this.token = options.token;
9
+ this.host = options.host || 'https://gitlab.com';
10
+ this.apiUrl = `${this.host}/api/v4`;
11
+ }
12
+
13
+ /**
14
+ * 发送 API 请求
15
+ */
16
+ async request(endpoint, options = {}) {
17
+ const url = `${this.apiUrl}${endpoint}`;
18
+ const headers = {
19
+ 'PRIVATE-TOKEN': this.token,
20
+ 'Content-Type': 'application/json',
21
+ ...options.headers,
22
+ };
23
+
24
+ const response = await fetch(url, {
25
+ ...options,
26
+ headers,
27
+ });
28
+
29
+ if (!response.ok) {
30
+ throw new Error(`GitLab API 请求失败: ${response.status} ${response.statusText}`);
31
+ }
32
+
33
+ return response.json();
34
+ }
35
+
36
+ /**
37
+ * 获取项目信息
38
+ */
39
+ async getProject(projectId) {
40
+ return this.request(`/projects/${encodeURIComponent(projectId)}`);
41
+ }
42
+
43
+ /**
44
+ * 获取 Merge Request 信息
45
+ */
46
+ async getMergeRequest(projectId, mergeRequestIid) {
47
+ return this.request(`/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}`);
48
+ }
49
+
50
+ /**
51
+ * 获取 MR 的代码变更
52
+ */
53
+ async getMergeRequestChanges(projectId, mergeRequestIid) {
54
+ const mr = await this.request(`/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/changes`);
55
+ return mr.changes || [];
56
+ }
57
+
58
+ /**
59
+ * 在 MR 上创建评论
60
+ */
61
+ async createMergeRequestNote(projectId, mergeRequestIid, body) {
62
+ return this.request(
63
+ `/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/notes`,
64
+ {
65
+ method: 'POST',
66
+ body: JSON.stringify({ body }),
67
+ }
68
+ );
69
+ }
70
+
71
+ /**
72
+ * 在 MR 上创建讨论(行内评论)
73
+ */
74
+ async createMergeRequestDiscussion(projectId, mergeRequestIid, body, position) {
75
+ return this.request(
76
+ `/projects/${encodeURIComponent(projectId)}/merge_requests/${mergeRequestIid}/discussions`,
77
+ {
78
+ method: 'POST',
79
+ body: JSON.stringify({
80
+ body,
81
+ position,
82
+ }),
83
+ }
84
+ );
85
+ }
86
+ }
87
+
package/package.json CHANGED
@@ -1,18 +1,25 @@
1
1
  {
2
2
  "name": "gitlab-ai-review",
3
- "version": "1.0.0",
4
- "description": "GitLab AI Review SDK - 测试版本",
3
+ "version": "1.0.3",
4
+ "description": "GitLab AI Review SDK - 支持 CI/CD 自动配置和 ARK API",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
+ "scripts": {
8
+ "test": "node test-info.js",
9
+ "test:info": "node test-info.js"
10
+ },
7
11
  "files": [
8
12
  "index.js",
13
+ "lib/",
14
+ "test-info.js",
9
15
  "README.md"
10
16
  ],
11
17
  "keywords": [
12
18
  "gitlab",
13
19
  "ai",
14
20
  "review",
15
- "sdk"
21
+ "sdk",
22
+ "ci-cd"
16
23
  ],
17
24
  "author": "",
18
25
  "license": "MIT",
@@ -20,4 +27,3 @@
20
27
  "node": ">=18.0.0"
21
28
  }
22
29
  }
23
-
package/test-info.js ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 测试脚本:输出项目 URL 和最新 MR 编号
4
+ * 用于验证 gitlab-ai-review SDK 在 CI/CD 中的配置
5
+ */
6
+
7
+ import { GitLabAIReview } from './index.js';
8
+
9
+ async function testInfo() {
10
+ try {
11
+ console.log('🔍 正在测试 gitlab-ai-review SDK...\n');
12
+
13
+ // 创建 SDK 实例(自动从环境变量读取配置)
14
+ const sdk = new GitLabAIReview();
15
+
16
+ // 获取配置信息
17
+ const config = sdk.getConfig();
18
+
19
+ console.log('📋 配置信息:');
20
+ console.log('━'.repeat(50));
21
+ console.log(`GitLab URL: ${config.gitlab.url}`);
22
+ console.log(`项目 ID: ${config.project.projectId || '(未设置)'}`);
23
+ console.log(`MR IID: ${config.project.mergeRequestIid || '(未设置)'}`);
24
+ console.log(`Token: ${config.gitlab.token ? '✓ 已配置' : '✗ 未配置'}`);
25
+ console.log('━'.repeat(50));
26
+ console.log();
27
+
28
+ // 验证配置
29
+ try {
30
+ sdk.validate();
31
+ console.log('✅ 配置验证通过\n');
32
+ } catch (error) {
33
+ console.error('❌ 配置验证失败:', error.message);
34
+ console.log('\n💡 提示: 在 CI/CD 中,GitLab 会自动提供以下环境变量:');
35
+ console.log(' - CI_JOB_TOKEN (GitLab Token)');
36
+ console.log(' - CI_SERVER_URL (GitLab 地址)');
37
+ console.log(' - CI_PROJECT_PATH (项目路径)');
38
+ console.log(' - CI_MERGE_REQUEST_IID (MR 编号)\n');
39
+ process.exit(1);
40
+ }
41
+
42
+ // 获取项目信息
43
+ console.log('📦 正在获取项目信息...');
44
+ const project = await sdk.getProject();
45
+ console.log(`项目名称: ${project.name}`);
46
+ console.log(`项目描述: ${project.description || '(无)'}`);
47
+ console.log(`项目 URL: ${project.web_url}`);
48
+ console.log(`命名空间: ${project.namespace.full_path}`);
49
+ console.log(`默认分支: ${project.default_branch}`);
50
+ console.log();
51
+
52
+ // 获取 MR 信息
53
+ if (config.project.mergeRequestIid) {
54
+ console.log('🔀 正在获取 MR 信息...');
55
+ const mr = await sdk.getMergeRequest();
56
+ console.log(`MR 标题: ${mr.title}`);
57
+ console.log(`MR 编号: #${mr.iid}`);
58
+ console.log(`MR URL: ${mr.web_url}`);
59
+ console.log(`作者: ${mr.author.name} (@${mr.author.username})`);
60
+ console.log(`源分支: ${mr.source_branch}`);
61
+ console.log(`目标分支: ${mr.target_branch}`);
62
+ console.log(`状态: ${mr.state}`);
63
+ console.log(`创建时间: ${mr.created_at}`);
64
+ console.log();
65
+
66
+ // 获取代码变更
67
+ console.log('📝 正在获取代码变更...');
68
+ const changes = await sdk.getMergeRequestChanges();
69
+ console.log(`共有 ${changes.length} 个文件变更:`);
70
+ changes.forEach((change, index) => {
71
+ console.log(` ${index + 1}. ${change.new_path}`);
72
+ });
73
+ console.log();
74
+ } else {
75
+ console.log('⚠️ 未检测到 MR 环境(非 MR Pipeline)\n');
76
+ }
77
+
78
+ console.log('━'.repeat(50));
79
+ console.log('✅ 测试完成!gitlab-ai-review SDK 工作正常!');
80
+ console.log('━'.repeat(50));
81
+
82
+ } catch (error) {
83
+ console.error('\n❌ 测试失败:', error.message);
84
+ console.error('\n详细错误:', error);
85
+ process.exit(1);
86
+ }
87
+ }
88
+
89
+ // 运行测试
90
+ testInfo();
91
+