koishi-plugin-githubsth 1.0.0 → 1.0.1-test1
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/lib/commands/admin.js +16 -3
- package/lib/commands/index.js +13 -0
- package/lib/commands/repo.d.ts +5 -0
- package/lib/commands/repo.js +23 -5
- package/lib/commands/subscribe.js +3 -0
- package/lib/config.js +1 -1
- package/lib/index.js +10 -6
- package/lib/locales/zh-CN.d.ts +3 -3
- package/lib/locales/zh-CN.js +4 -4
- package/lib/services/formatter.d.ts +2 -0
- package/lib/services/formatter.js +24 -0
- package/lib/services/notifier.js +24 -2
- package/package.json +4 -5
package/lib/commands/admin.js
CHANGED
|
@@ -3,13 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.apply = apply;
|
|
4
4
|
function apply(ctx) {
|
|
5
5
|
const logger = ctx.logger('githubsth');
|
|
6
|
+
// Allow . in repo name (e.g. koishi.js) but disallow / inside parts.
|
|
7
|
+
// owner: [\w-]+ (alphanumeric, underscore, dash)
|
|
8
|
+
// repo: [\w-\.]+ (alphanumeric, underscore, dash, dot)
|
|
9
|
+
const repoRegex = /^[\w-]+\/[\w-\.]+$/;
|
|
6
10
|
ctx.command('githubsth.trust', '管理信任仓库', { authority: 3 })
|
|
7
11
|
.alias('gh.trust');
|
|
8
12
|
ctx.command('githubsth.trust.add <repo>', '添加信任仓库')
|
|
9
13
|
.action(async ({ session }, repo) => {
|
|
10
14
|
if (!repo)
|
|
11
15
|
return '请指定仓库名称 (owner/repo)。';
|
|
16
|
+
if (!repoRegex.test(repo)) {
|
|
17
|
+
return '仓库名称格式不正确 (应为 owner/repo)。';
|
|
18
|
+
}
|
|
12
19
|
try {
|
|
20
|
+
logger.debug(`Adding trusted repo: ${repo}`);
|
|
21
|
+
// Check existence first to avoid UNIQUE constraint error log from driver
|
|
22
|
+
const existing = await ctx.database.get('github_trusted_repo', { repo });
|
|
23
|
+
if (existing.length > 0) {
|
|
24
|
+
return '该仓库已在信任列表中。';
|
|
25
|
+
}
|
|
13
26
|
await ctx.database.create('github_trusted_repo', {
|
|
14
27
|
repo,
|
|
15
28
|
enabled: true,
|
|
@@ -19,11 +32,11 @@ function apply(ctx) {
|
|
|
19
32
|
return `已添加信任仓库: ${repo}`;
|
|
20
33
|
}
|
|
21
34
|
catch (e) {
|
|
22
|
-
|
|
35
|
+
logger.warn('Failed to add trusted repo:', e);
|
|
36
|
+
if (e.code === 'SQLITE_CONSTRAINT') {
|
|
23
37
|
return '该仓库已在信任列表中。';
|
|
24
38
|
}
|
|
25
|
-
|
|
26
|
-
return '添加失败,请查看日志。';
|
|
39
|
+
return `添加失败: ${e.message}`;
|
|
27
40
|
}
|
|
28
41
|
});
|
|
29
42
|
ctx.command('githubsth.trust.remove <repo>', '移除信任仓库')
|
package/lib/commands/index.js
CHANGED
|
@@ -35,6 +35,19 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.apply = apply;
|
|
37
37
|
const repo = __importStar(require("./repo"));
|
|
38
|
+
const admin = __importStar(require("./admin"));
|
|
39
|
+
const subscribe = __importStar(require("./subscribe"));
|
|
38
40
|
function apply(ctx, config) {
|
|
41
|
+
console.log('Applying githubsth commands...');
|
|
42
|
+
// Register parent command to show help
|
|
43
|
+
ctx.command('githubsth', 'GitHub 推送通知')
|
|
44
|
+
.action(({ session }) => {
|
|
45
|
+
session?.execute('help githubsth');
|
|
46
|
+
});
|
|
39
47
|
ctx.plugin(repo, config);
|
|
48
|
+
console.log('githubsth.repo loaded');
|
|
49
|
+
ctx.plugin(admin, config);
|
|
50
|
+
console.log('githubsth.admin loaded');
|
|
51
|
+
ctx.plugin(subscribe, config);
|
|
52
|
+
console.log('githubsth.subscribe loaded');
|
|
40
53
|
}
|
package/lib/commands/repo.d.ts
CHANGED
package/lib/commands/repo.js
CHANGED
|
@@ -10,10 +10,28 @@ function apply(ctx, config) {
|
|
|
10
10
|
const fullRepo = name || (config.defaultOwner ? `${config.defaultOwner}/${config.defaultRepo}` : name);
|
|
11
11
|
if (!fullRepo)
|
|
12
12
|
return session?.text('.specify_repo');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
try {
|
|
14
|
+
let data;
|
|
15
|
+
if (ctx.github && typeof ctx.github.request === 'function') {
|
|
16
|
+
// If adapter provides a request method (hypothetical, based on common adapter patterns)
|
|
17
|
+
data = await ctx.github.request('GET /repos/:owner/:repo', {
|
|
18
|
+
owner: fullRepo.split('/')[0],
|
|
19
|
+
repo: fullRepo.split('/')[1]
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const headers = {
|
|
24
|
+
'User-Agent': 'Koishi-Plugin-GithubSth'
|
|
25
|
+
};
|
|
26
|
+
data = await ctx.http.get(`https://api.github.com/repos/${fullRepo}`, { headers });
|
|
27
|
+
}
|
|
28
|
+
return session?.text('.repo_info', [data.owner.login, data.name, data.description || '无描述', data.stargazers_count]);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
if (e.response?.status === 404) {
|
|
32
|
+
return session?.text('.not_found');
|
|
33
|
+
}
|
|
34
|
+
return session?.text('.error', [e.message]);
|
|
35
|
+
}
|
|
18
36
|
});
|
|
19
37
|
}
|
|
@@ -3,11 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.apply = apply;
|
|
4
4
|
function apply(ctx) {
|
|
5
5
|
const logger = ctx.logger('githubsth');
|
|
6
|
+
const repoRegex = /^[\w-]+\/[\w-\.]+$/;
|
|
6
7
|
ctx.command('githubsth.subscribe <repo> [events:text]', '订阅 GitHub 仓库')
|
|
7
8
|
.alias('gh.sub')
|
|
8
9
|
.action(async ({ session }, repo, eventsStr) => {
|
|
9
10
|
if (!repo)
|
|
10
11
|
return '请指定仓库名称 (owner/repo)。';
|
|
12
|
+
if (!repoRegex.test(repo))
|
|
13
|
+
return '仓库名称格式不正确 (应为 owner/repo)。';
|
|
11
14
|
if (!session?.channelId)
|
|
12
15
|
return '请在群组中使用此命令。';
|
|
13
16
|
// Check trusted repo
|
package/lib/config.js
CHANGED
|
@@ -10,6 +10,6 @@ exports.Config = koishi_1.Schema.object({
|
|
|
10
10
|
repo: koishi_1.Schema.string().required(),
|
|
11
11
|
channelId: koishi_1.Schema.string().required(),
|
|
12
12
|
platform: koishi_1.Schema.string(),
|
|
13
|
-
events: koishi_1.Schema.array(koishi_1.Schema.string()).default(['push', 'issues', 'pull_request']),
|
|
13
|
+
events: koishi_1.Schema.array(koishi_1.Schema.string()).default(['push', 'issues', 'pull_request', 'issue_comment', 'pull_request_review']),
|
|
14
14
|
})).hidden().description('已废弃,请使用数据库管理订阅'),
|
|
15
15
|
});
|
package/lib/index.js
CHANGED
|
@@ -42,8 +42,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
42
42
|
exports.inject = exports.name = void 0;
|
|
43
43
|
exports.apply = apply;
|
|
44
44
|
const commands = __importStar(require("./commands"));
|
|
45
|
-
const admin = __importStar(require("./commands/admin"));
|
|
46
|
-
const subscribe = __importStar(require("./commands/subscribe"));
|
|
47
45
|
const database = __importStar(require("./database"));
|
|
48
46
|
const zh_CN_1 = __importDefault(require("./locales/zh-CN"));
|
|
49
47
|
const notifier_1 = require("./services/notifier");
|
|
@@ -51,7 +49,7 @@ const formatter_1 = require("./services/formatter");
|
|
|
51
49
|
exports.name = 'githubsth';
|
|
52
50
|
exports.inject = {
|
|
53
51
|
required: ['database'],
|
|
54
|
-
optional: ['github']
|
|
52
|
+
optional: ['github'],
|
|
55
53
|
};
|
|
56
54
|
__exportStar(require("./config"), exports);
|
|
57
55
|
function apply(ctx, config) {
|
|
@@ -63,7 +61,13 @@ function apply(ctx, config) {
|
|
|
63
61
|
ctx.plugin(formatter_1.Formatter);
|
|
64
62
|
ctx.plugin(notifier_1.Notifier, config);
|
|
65
63
|
// 注册命令
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
// admin and subscribe are already loaded in commands/index.ts, remove duplicate loading here
|
|
65
|
+
try {
|
|
66
|
+
ctx.plugin(commands, config);
|
|
67
|
+
// 加载成功日志
|
|
68
|
+
console.log('githubsth plugin loaded');
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
console.error('githubsth plugin failed to load:', e);
|
|
72
|
+
}
|
|
69
73
|
}
|
package/lib/locales/zh-CN.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ declare const _default: {
|
|
|
2
2
|
commands: {
|
|
3
3
|
githubsth: {
|
|
4
4
|
description: string;
|
|
5
|
+
};
|
|
6
|
+
'githubsth.repo': {
|
|
7
|
+
description: string;
|
|
5
8
|
messages: {
|
|
6
9
|
repo_info: string;
|
|
7
10
|
error: string;
|
|
@@ -9,9 +12,6 @@ declare const _default: {
|
|
|
9
12
|
not_found: string;
|
|
10
13
|
};
|
|
11
14
|
};
|
|
12
|
-
'githubsth.repo': {
|
|
13
|
-
description: string;
|
|
14
|
-
};
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
17
|
export default _default;
|
package/lib/locales/zh-CN.js
CHANGED
|
@@ -3,16 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.default = {
|
|
4
4
|
commands: {
|
|
5
5
|
githubsth: {
|
|
6
|
-
description: 'GitHub 交互插件'
|
|
6
|
+
description: 'GitHub 交互插件'
|
|
7
|
+
},
|
|
8
|
+
'githubsth.repo': {
|
|
9
|
+
description: '获取仓库信息',
|
|
7
10
|
messages: {
|
|
8
11
|
repo_info: '仓库: {0}/{1}\n描述: {2}\nStars: {3}',
|
|
9
12
|
error: '获取信息失败: {0}',
|
|
10
13
|
specify_repo: '请指定仓库名称。',
|
|
11
14
|
not_found: '未找到仓库或无权限访问。'
|
|
12
15
|
}
|
|
13
|
-
},
|
|
14
|
-
'githubsth.repo': {
|
|
15
|
-
description: '获取仓库信息'
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
};
|
|
@@ -14,4 +14,6 @@ export declare class Formatter extends Service {
|
|
|
14
14
|
formatRelease(payload: any): h | null;
|
|
15
15
|
formatDiscussion(payload: any): h;
|
|
16
16
|
formatWorkflowRun(payload: any): h | null;
|
|
17
|
+
formatIssueComment(payload: any): h | null;
|
|
18
|
+
formatPullRequestReview(payload: any): h | null;
|
|
17
19
|
}
|
|
@@ -90,5 +90,29 @@ class Formatter extends koishi_1.Service {
|
|
|
90
90
|
(0, koishi_1.h)('text', { content: `链接: ${workflow_run.html_url}` })
|
|
91
91
|
]);
|
|
92
92
|
}
|
|
93
|
+
formatIssueComment(payload) {
|
|
94
|
+
const { action, issue, comment, repository, sender } = payload;
|
|
95
|
+
if (action !== 'created')
|
|
96
|
+
return null;
|
|
97
|
+
return (0, koishi_1.h)('message', [
|
|
98
|
+
(0, koishi_1.h)('text', { content: `[GitHub] ${repository.full_name} Issue 收到新评论\n` }),
|
|
99
|
+
(0, koishi_1.h)('text', { content: `标题: #${issue.number} ${issue.title}\n` }),
|
|
100
|
+
(0, koishi_1.h)('text', { content: `评论人: ${sender.login}\n` }),
|
|
101
|
+
(0, koishi_1.h)('text', { content: `内容: ${comment.body.substring(0, 100)}${comment.body.length > 100 ? '...' : ''}\n` }),
|
|
102
|
+
(0, koishi_1.h)('text', { content: `链接: ${comment.html_url}` })
|
|
103
|
+
]);
|
|
104
|
+
}
|
|
105
|
+
formatPullRequestReview(payload) {
|
|
106
|
+
const { action, pull_request, review, repository, sender } = payload;
|
|
107
|
+
if (action !== 'submitted')
|
|
108
|
+
return null;
|
|
109
|
+
return (0, koishi_1.h)('message', [
|
|
110
|
+
(0, koishi_1.h)('text', { content: `[GitHub] ${repository.full_name} PR 收到 Review\n` }),
|
|
111
|
+
(0, koishi_1.h)('text', { content: `标题: #${pull_request.number} ${pull_request.title}\n` }),
|
|
112
|
+
(0, koishi_1.h)('text', { content: `Reviewer: ${sender.login}\n` }),
|
|
113
|
+
(0, koishi_1.h)('text', { content: `状态: ${review.state}\n` }),
|
|
114
|
+
(0, koishi_1.h)('text', { content: `链接: ${review.html_url}` })
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
93
117
|
}
|
|
94
118
|
exports.Formatter = Formatter;
|
package/lib/services/notifier.js
CHANGED
|
@@ -18,6 +18,8 @@ class Notifier extends koishi_1.Service {
|
|
|
18
18
|
this.ctx.on('github/release', (payload) => this.handleEvent('release', payload));
|
|
19
19
|
this.ctx.on('github/discussion', (payload) => this.handleEvent('discussion', payload));
|
|
20
20
|
this.ctx.on('github/workflow_run', (payload) => this.handleEvent('workflow_run', payload));
|
|
21
|
+
this.ctx.on('github/issue_comment', (payload) => this.handleEvent('issue_comment', payload));
|
|
22
|
+
this.ctx.on('github/pull_request_review', (payload) => this.handleEvent('pull_request_review', payload));
|
|
21
23
|
}
|
|
22
24
|
async handleEvent(event, payload) {
|
|
23
25
|
const repoName = payload.repository?.full_name;
|
|
@@ -43,8 +45,15 @@ class Notifier extends koishi_1.Service {
|
|
|
43
45
|
return false;
|
|
44
46
|
return true;
|
|
45
47
|
});
|
|
46
|
-
if (matchedRules.length === 0)
|
|
48
|
+
if (matchedRules.length === 0) {
|
|
49
|
+
if (this.config.debug) {
|
|
50
|
+
this.ctx.logger('notifier').debug(`No matching rules for ${repoName} (event: ${event})`);
|
|
51
|
+
}
|
|
47
52
|
return;
|
|
53
|
+
}
|
|
54
|
+
if (this.config.debug) {
|
|
55
|
+
this.ctx.logger('notifier').debug(`Found ${matchedRules.length} matching rules for ${repoName}`);
|
|
56
|
+
}
|
|
48
57
|
let message = null;
|
|
49
58
|
// Ensure formatter is loaded
|
|
50
59
|
if (!this.ctx.formatter) {
|
|
@@ -76,10 +85,23 @@ class Notifier extends koishi_1.Service {
|
|
|
76
85
|
case 'workflow_run':
|
|
77
86
|
message = this.ctx.formatter.formatWorkflowRun(payload);
|
|
78
87
|
break;
|
|
88
|
+
case 'issue_comment':
|
|
89
|
+
message = this.ctx.formatter.formatIssueComment(payload);
|
|
90
|
+
break;
|
|
91
|
+
case 'pull_request_review':
|
|
92
|
+
message = this.ctx.formatter.formatPullRequestReview(payload);
|
|
93
|
+
break;
|
|
79
94
|
}
|
|
80
|
-
if (!message)
|
|
95
|
+
if (!message) {
|
|
96
|
+
if (this.config.debug) {
|
|
97
|
+
this.ctx.logger('notifier').debug(`Formatter returned null for event ${event}`);
|
|
98
|
+
}
|
|
81
99
|
return;
|
|
100
|
+
}
|
|
82
101
|
for (const rule of matchedRules) {
|
|
102
|
+
if (this.config.debug) {
|
|
103
|
+
this.ctx.logger('notifier').debug(`Sending message to channel ${rule.channelId} (platform: ${rule.platform || 'any'})`);
|
|
104
|
+
}
|
|
83
105
|
await this.sendMessage(rule, message);
|
|
84
106
|
}
|
|
85
107
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-githubsth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-test1",
|
|
4
4
|
"description": "Github Subscriptions Notifications, push notifications for GitHub subscriptions For koishi",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -39,11 +39,10 @@
|
|
|
39
39
|
},
|
|
40
40
|
"service": {
|
|
41
41
|
"required": [
|
|
42
|
-
"database"
|
|
43
|
-
],
|
|
44
|
-
"optional": [
|
|
42
|
+
"database",
|
|
45
43
|
"github"
|
|
46
|
-
]
|
|
44
|
+
],
|
|
45
|
+
"optional": []
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
}
|