diff --git a/.github/wechat.png b/.github/wechat.png
deleted file mode 100644
index a92bd138cc..0000000000
Binary files a/.github/wechat.png and /dev/null differ
diff --git a/.gitignore b/.gitignore
index 3dbe0d016b..4514a66f85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,10 +3,10 @@ temp
/addons
/atri
+/coverage
/docs
/shiki
-/coverage
-/plugins
+/test
todo.md
yarn.lock
diff --git a/.mocharc.js b/.mocharc.js
index f8674754a7..7ebf613555 100644
--- a/.mocharc.js
+++ b/.mocharc.js
@@ -6,6 +6,7 @@ module.exports = {
'packages/koishi-utils/tests/*.spec.ts',
'packages/koishi-test-utils/tests/*.spec.ts',
'packages/plugin-eval/tests/*.spec.ts',
+ 'packages/plugin-github/tests/*.spec.ts',
'packages/plugin-teach/tests/*.spec.ts',
],
require: [
diff --git a/README.md b/README.md
index 3ee4da6c69..ea4c94ed0d 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,9 @@ Koishi 是一个在 [Node.js](https://nodejs.org/) 环境下运行的机器人
这个项目的名字和图标来源于东方 Project 中的角色古明地恋 (Komeiji Koishi)。
-![demo](./.github/demo.png)
+
+
+
## 安装
@@ -56,10 +58,12 @@ koishi run
[CQHTTP (OneBot)](https://github.com/howmanybots/onebot) 协议支持,可与下列实现该协议的框架完美对接:
-- [richardchien/coolq-http-api](https://github.com/richardchien/coolq-http-api)
+- [richardchien/coolq-http-api](https://github.com/richardchien/coolq-http-api)(可配合 [iTXTech/mirai-native](https://github.com/iTXTech/mirai-native) 使用)
- [Mrs4s/go-cqhttp](https://github.com/Mrs4s/go-cqhttp)
- [yyuueexxiinngg/cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai)
+请注意:尽管 Koishi 使用的协议是 [MIT](https://choosealicense.com/licenses/mit/),但上面陈述的三种途径的相关框架都使用了基于 [AGPL 3.0](https://choosealicense.com/licenses/agpl-3.0/) 的协议。因此如果你使用 koishi-adapter-cqhttp 运行你的机器人,你将可能受到 AGPL 3.0 协议的限制,**必须将你的代码开源并保持同协议**。Koishi 及其作者对使用上述框架或违反上述限制的行为所可能造成的法律后果概不负责。
+
## 数据库支持
### [koishi-plugin-mongo](./packages/plugin-mongo) [![npm](https://img.shields.io/npm/v/koishi-plugin-mongo?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-mongo)
@@ -85,7 +89,7 @@ koishi-plugin-common 包含了一些常用功能,它们在你使用 koishi 库
- 输出聊天记录到控制台
- 欢迎入群,复读,处理申请,频率限制,自定义回复……
-### [koishi-plugin-eval](https://koishi.js.org/plugins/eval.html) [![npm](https://img.shields.io/npm/v/koishi-plugin-eval/next?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-eval)
+### [koishi-plugin-eval](https://koishi.js.org/plugins/eval.html) [![npm](https://img.shields.io/npm/v/koishi-plugin-eval?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-eval)
koishi-plugin-eval 允许用户直接使用机器人执行脚本。它利用了 Node.js 的 [vm](https://nodejs.org/api/vm.html) 和 [worker_threads](https://nodejs.org/api/worker_threads.html) 模块,在保护执行安全的前提下能够获得较快的响应速度。同时,插件还提供了一些内置的 API 供用户调用,结合教学功能可以在客户端实现复杂的行为。
@@ -99,20 +103,26 @@ koishi-plugin-eval-addons 在前一个插件的基础上,允许用户编写自
### [koishi-plugin-monitor](./packages/plugin-monitor) [![npm](https://img.shields.io/npm/v/koishi-plugin-monitor/next?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-monitor)
-### [koishi-plugin-puppeteer](./packages/plugin-puppeteer) [![npm](https://img.shields.io/npm/v/koishi-plugin-puppeteer?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-puppeteer)
+### [koishi-plugin-puppeteer](https://koishi.js.org/plugins/puppeteer.html) [![npm](https://img.shields.io/npm/v/koishi-plugin-puppeteer?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-puppeteer)
-### [koishi-plugin-recorder](./packages/plugin-recorder) [![npm](https://img.shields.io/npm/v/koishi-plugin-recorder/next?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-recorder)
+koishi-plugin-puppeteer 本身提供了网页截图(shot)指令和 TeX 渲染指令(tex),同时也封装了一系列与网页进行交互的接口。利用这些接口我们可以开发更多以渲染图片为基础的插件,如 koishi-plugin-chess 等。
### [koishi-plugin-rss](./packages/plugin-rss) [![npm](https://img.shields.io/npm/v/koishi-plugin-rss?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-rss)
+koishi-plugin-rss 提供了 [RSS](https://en.wikipedia.org/wiki/RSS) 支持,允许不同的群订阅不同的 RSS 信息源并实时进行通知。
+
### [koishi-plugin-schedule](./packages/plugin-schedule) [![npm](https://img.shields.io/npm/v/koishi-plugin-schedule?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-schedule)
+koishi-plugin-schedule 允许用户设置定时任务并执行。这些计划任务会被存储在数据库中,即使重启机器人也能继续工作。
+
### [koishi-plugin-status](./packages/plugin-status) [![npm](https://img.shields.io/npm/v/koishi-plugin-status/next?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-status)
### [koishi-plugin-teach](./packages/plugin-teach) [![npm](https://img.shields.io/npm/v/koishi-plugin-teach?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-teach)
### [koishi-plugin-tools](./packages/plugin-tools) [![npm](https://img.shields.io/npm/v/koishi-plugin-tools?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-tools)
-## 支持作者
+## 协议
+
+[MIT](./LICENSE)
-
+Copyright © 2019-present, Shigma
diff --git a/build/bump.ts b/build/bump.ts
index 2bec33f835..8bed6e66a7 100644
--- a/build/bump.ts
+++ b/build/bump.ts
@@ -109,7 +109,7 @@ function bumpPkg(source: Package, flag: BumpType, only = false) {
const { name } = source
if (target.name === name) return
Object.entries({ devDependencies, peerDependencies, dependencies, optionalDependencies })
- .filter(([_, dependencies = {}]) => dependencies[name])
+ .filter(([, dependencies = {}]) => dependencies[name])
.forEach(([type]) => {
target.meta[type][name] = '^' + newVersion
target.dirty = true
@@ -150,4 +150,13 @@ const flag = options.major ? 'major' : options.minor ? 'minor' : options.patch ?
}
return pkg.save()
}))
+
+ const ecosystem: Record> = {}
+ for (const path in packages) {
+ if (!path.startsWith('packages/') || path.startsWith('packages/koishi')) continue
+ const { name, version, description } = packages[path].meta
+ ecosystem[name] = { version, description }
+ }
+
+ await writeJson(resolve(__dirname, '../packages/koishi/ecosystem.json'), ecosystem, { spaces: 2 })
})()
diff --git a/build/utils.ts b/build/utils.ts
index e11227986b..14f88a9a39 100644
--- a/build/utils.ts
+++ b/build/utils.ts
@@ -17,6 +17,7 @@ export type DependencyType = 'dependencies' | 'devDependencies' | 'peerDependenc
export interface PackageJson extends Partial>> {
name?: string
+ description?: string
private?: boolean
version?: string
}
@@ -36,7 +37,7 @@ export function spawnSync(command: string, silent?: boolean) {
export function spawnAsync(command: string) {
const args = command.split(/\s+/)
const child = spawn(args[0], args.slice(1), { stdio: 'inherit' })
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
child.on('close', resolve)
})
}
diff --git a/package.json b/package.json
index 745b6cbcd5..647d1a2aa1 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
"workspaces": [
"atri",
"addons",
+ "test",
"shiki",
"shiki/core",
"shiki/cosmos",
diff --git a/packages/adapter-cqhttp/package.json b/packages/adapter-cqhttp/package.json
index acbd65c0cb..08f33b16f6 100644
--- a/packages/adapter-cqhttp/package.json
+++ b/packages/adapter-cqhttp/package.json
@@ -31,7 +31,7 @@
"koishi"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"devDependencies": {
"@types/ms": "^0.7.31",
@@ -43,6 +43,6 @@
"axios": "^0.20.0",
"ms": "^2.1.2",
"ws": "^7.3.1",
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/koishi-core/package.json b/packages/koishi-core/package.json
index 7ca86fdfac..ec5d743e3b 100644
--- a/packages/koishi-core/package.json
+++ b/packages/koishi-core/package.json
@@ -1,7 +1,7 @@
{
"name": "koishi-core",
"description": "Core features for Koishi",
- "version": "2.0.2",
+ "version": "2.1.0",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"engines": {
@@ -44,7 +44,7 @@
"koa": "^2.13.0",
"koa-bodyparser": "^4.3.0",
"koa-router": "^9.4.0",
- "koishi-utils": "^3.1.2",
+ "koishi-utils": "^3.1.3",
"leven": "^3.1.0",
"lru-cache": "^6.0.0"
}
diff --git a/packages/koishi-core/src/app.ts b/packages/koishi-core/src/app.ts
index 1cb51f8404..af7300ed38 100644
--- a/packages/koishi-core/src/app.ts
+++ b/packages/koishi-core/src/app.ts
@@ -46,8 +46,8 @@ export class App extends Context {
_commands: Command[]
_commandMap: Record
_hooks: Record any][]>
- _userCache: LruCache>>
- _groupCache: LruCache>>
+ _userCache: LruCache, Promise>>
+ _groupCache: LruCache, Promise>>
private _nameRE: RegExp
private _prefixRE: RegExp
diff --git a/packages/koishi-core/tests/command.spec.ts b/packages/koishi-core/tests/command.spec.ts
index 74ed02db3b..0c738dc504 100644
--- a/packages/koishi-core/tests/command.spec.ts
+++ b/packages/koishi-core/tests/command.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+
import { App } from 'koishi-test-utils'
import { spyOn } from 'jest-mock'
import { Logger, noop } from 'koishi-utils'
diff --git a/packages/koishi-core/tests/help.spec.ts b/packages/koishi-core/tests/help.spec.ts
index 6b3ca58db3..46ad68b941 100644
--- a/packages/koishi-core/tests/help.spec.ts
+++ b/packages/koishi-core/tests/help.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+
import { memory, App } from 'koishi-test-utils'
import { Time } from 'koishi-utils'
import { Message } from 'koishi-core'
diff --git a/packages/koishi-core/tests/server.spec.ts b/packages/koishi-core/tests/server.spec.ts
index 1277255ab2..fe23ce3ea1 100644
--- a/packages/koishi-core/tests/server.spec.ts
+++ b/packages/koishi-core/tests/server.spec.ts
@@ -1,7 +1,8 @@
import { App, BASE_SELF_ID, memory } from 'koishi-test-utils'
-import { App as RealApp, Group, Session } from 'koishi-core'
+import { App as RealApp, extendDatabase, Group, Session } from 'koishi-core'
import { expect } from 'chai'
import { fn, spyOn } from 'jest-mock'
+import { Logger } from 'koishi-utils'
describe('Server API', () => {
describe('Adaptation API', () => {
@@ -96,4 +97,31 @@ describe('Server API', () => {
expect(sendGroupMsg.mock.calls).to.deep.equal([[123, 'foo'], [456, 'foo']])
})
})
+
+ describe('Database API', () => {
+ const app = new App()
+ const warn = spyOn(new Logger('app'), 'warn')
+
+ it('override database', () => {
+ warn.mockClear()
+ app.database = {} as any
+ expect(warn.mock.calls).to.have.length(0)
+ app.database = {} as any
+ expect(warn.mock.calls).to.have.length(1)
+ })
+
+ it('extend database', () => {
+ const callback = fn()
+ const id = 'this-module-does-not-exist'
+ extendDatabase(id, callback)
+ expect(callback.mock.calls).to.have.length(0)
+ class CustomDatabase {}
+ const module = require.cache[require.resolve('koishi-core/src/database.ts')]
+ const mockedRequire = spyOn(module, 'require')
+ mockedRequire.mockReturnValue({ default: CustomDatabase })
+ extendDatabase(id, callback)
+ expect(callback.mock.calls).to.deep.equal([[CustomDatabase]])
+ mockedRequire.mockRestore()
+ })
+ })
})
diff --git a/packages/koishi-test-utils/package.json b/packages/koishi-test-utils/package.json
index 63173017cc..49214cc7a7 100644
--- a/packages/koishi-test-utils/package.json
+++ b/packages/koishi-test-utils/package.json
@@ -40,8 +40,8 @@
"dependencies": {
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
- "koishi-core": "^2.0.2",
- "koishi-utils": "^3.1.2"
+ "koishi-core": "^2.1.0",
+ "koishi-utils": "^3.1.3"
},
"devDependencies": {
"@types/chai": "^4.2.12",
diff --git a/packages/koishi-utils/package.json b/packages/koishi-utils/package.json
index 9e5700e185..06e3325ae0 100644
--- a/packages/koishi-utils/package.json
+++ b/packages/koishi-utils/package.json
@@ -1,7 +1,7 @@
{
"name": "koishi-utils",
"description": "Utilities for Koishi",
- "version": "3.1.2",
+ "version": "3.1.3",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
diff --git a/packages/koishi-utils/src/logger.ts b/packages/koishi-utils/src/logger.ts
index 2b270eb811..90563b2d27 100644
--- a/packages/koishi-utils/src/logger.ts
+++ b/packages/koishi-utils/src/logger.ts
@@ -14,6 +14,10 @@ const instances: Record = {}
type LogFunction = (format: any, ...param: any[]) => void
+type LogType = 'success' | 'error' | 'info' | 'warn' | 'debug'
+
+export interface Logger extends Record {}
+
export class Logger {
static readonly SUCCESS = 1
static readonly ERROR = 1
@@ -44,12 +48,6 @@ export class Logger {
private code: number
private displayName: string
- public success: LogFunction
- public error: LogFunction
- public info: LogFunction
- public warn: LogFunction
- public debug: LogFunction
-
constructor(private name: string, private showDiff = false) {
if (name in instances) return instances[name]
let hash = 0
@@ -71,7 +69,7 @@ export class Logger {
return Logger.color(this.code, value, decoration)
}
- private createMethod(name: string, prefix: string, minLevel: number) {
+ private createMethod(name: LogType, prefix: string, minLevel: number) {
this[name] = (...args: [any, ...any[]]) => {
if (this.level < minLevel) return
process.stderr.write(prefix + this.displayName + this.format(...args) + '\n')
diff --git a/packages/koishi/ecosystem.json b/packages/koishi/ecosystem.json
new file mode 100644
index 0000000000..02c045b4cd
--- /dev/null
+++ b/packages/koishi/ecosystem.json
@@ -0,0 +1,64 @@
+{
+ "koishi-adapter-cqhttp": {
+ "version": "1.0.1",
+ "description": "CQHTTP adapter for Koishi"
+ },
+ "koishi-plugin-chess": {
+ "version": "2.0.0-beta.10",
+ "description": "Chess Plugin for Koishi"
+ },
+ "koishi-plugin-common": {
+ "version": "3.0.0-beta.15",
+ "description": "Common plugins for Koishi"
+ },
+ "koishi-plugin-eval": {
+ "version": "2.0.0",
+ "description": "Execute JavaScript in Koishi"
+ },
+ "koishi-plugin-eval-addons": {
+ "version": "1.0.0-beta.10",
+ "description": "Execute JavaScript in Koishi"
+ },
+ "koishi-plugin-github": {
+ "version": "2.0.0-beta.10",
+ "description": "GitHub webhook plugin for Koishi"
+ },
+ "koishi-plugin-image-search": {
+ "version": "2.0.0",
+ "description": "Image searching plugin for Koishi"
+ },
+ "koishi-plugin-mongo": {
+ "version": "1.0.2",
+ "description": "MongoDB support for Koishi"
+ },
+ "koishi-plugin-monitor": {
+ "version": "1.0.0-beta.14"
+ },
+ "koishi-plugin-mysql": {
+ "version": "2.0.0",
+ "description": "MySQL support for Koishi"
+ },
+ "koishi-plugin-puppeteer": {
+ "version": "1.0.0",
+ "description": "Take Screenshots in Koishi"
+ },
+ "koishi-plugin-rss": {
+ "version": "1.0.0",
+ "description": "Subscribe RSS Url for Koishi"
+ },
+ "koishi-plugin-schedule": {
+ "version": "2.0.1",
+ "description": "Schedule plugin for Koishi"
+ },
+ "koishi-plugin-status": {
+ "version": "2.0.0-beta.13",
+ "description": "Show Status of Koishi"
+ },
+ "koishi-plugin-teach": {
+ "version": "1.0.2",
+ "description": "Teach plugin for Koishi"
+ },
+ "koishi-plugin-tools": {
+ "version": "1.0.0"
+ }
+}
diff --git a/packages/koishi/package.json b/packages/koishi/package.json
index 05da115ad0..3946353c7b 100644
--- a/packages/koishi/package.json
+++ b/packages/koishi/package.json
@@ -1,14 +1,15 @@
{
"name": "koishi",
"description": "A QQ bot framework based on CQHTTP",
- "version": "2.0.2",
+ "version": "2.1.0",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"engines": {
"node": ">=12.0.0"
},
"files": [
- "dist"
+ "dist",
+ "ecosystem.json"
],
"bin": "dist/cli.js",
"author": "Shigma <1700011071@pku.edu.cn>",
@@ -34,21 +35,14 @@
"koishi"
],
"devDependencies": {
- "@types/js-yaml": "^3.12.5",
"@types/prompts": "^2.0.8"
},
"dependencies": {
"cac": "^6.6.1",
"kleur": "^4.1.1",
- "koishi-core": "^2.0.2",
"koishi-adapter-cqhttp": "^1.0.1",
+ "koishi-core": "^2.1.0",
"koishi-plugin-common": "^3.0.0-beta.15",
- "koishi-plugin-mysql": "^2.0.0",
- "koishi-plugin-mongo": "^1.0.1",
- "koishi-plugin-schedule": "^2.0.1",
- "koishi-plugin-status": "^2.0.0-beta.13",
- "koishi-plugin-teach": "^1.0.2",
- "koishi-utils": "^3.1.2",
"prompts": "^2.3.2"
}
}
diff --git a/packages/koishi/src/init.ts b/packages/koishi/src/init.ts
index 3a6c5d5206..08a7583850 100644
--- a/packages/koishi/src/init.ts
+++ b/packages/koishi/src/init.ts
@@ -1,78 +1,261 @@
-import { existsSync, writeFileSync, mkdirSync } from 'fs'
+import { promises as fs, existsSync } from 'fs'
import { yellow, red, green } from 'kleur'
import { resolve, extname, dirname } from 'path'
import { AppConfig } from './worker'
-import prompts from 'prompts'
import { CAC } from 'cac'
+import prompts, { Choice, PrevCaller, PromptObject } from 'prompts'
+import * as mysql from 'koishi-plugin-mysql/dist/database'
+import * as mongo from 'koishi-plugin-mongo/dist/database'
-async function createConfig() {
+function conditional(type: T, key: string, ...values: string[]): PrevCaller {
+ return (prev, data, prompt) => {
+ if (!values.includes(data[key])) return null
+ return typeof type === 'function' ? (type as PrevCaller)(prev, data, prompt) : type
+ }
+}
+
+const serverQuestions: PromptObject[] = [{
+ name: 'type',
+ type: 'select',
+ message: 'Server Type',
+ choices: [
+ { title: 'HTTP', value: 'cqhttp:http' },
+ { title: 'WebSocket', value: 'cqhttp:ws' },
+ { title: 'WebSocket Reverse', value: 'cqhttp:ws-reverse' },
+ ],
+}, {
+ name: 'port',
+ type: conditional('number', 'type', 'cqhttp:http', 'cqhttp:ws-reverse'),
+ message: 'Koishi Port',
+ initial: 8080,
+}, {
+ name: 'path',
+ type: conditional('text', 'type', 'cqhttp:http', 'cqhttp:ws-reverse'),
+ message: 'Koishi Path',
+ initial: '/',
+}, {
+ name: 'server',
+ type: conditional('text', 'type', 'cqhttp:http'),
+ message: 'HTTP Server',
+ initial: 'http://localhost:5700',
+}, {
+ name: 'server',
+ type: conditional('text', 'type', 'cqhttp:ws'),
+ message: 'WebSocket Server',
+ initial: 'ws://localhost:6700',
+}, {
+ name: 'selfId',
+ type: 'number',
+ message: 'Your Bot\'s QQ Number',
+}, {
+ name: 'secret',
+ type: 'text',
+ message: 'Secret for Koishi Server',
+}, {
+ name: 'token',
+ type: 'text',
+ message: 'Token for CQHTTP Server',
+}, {
+ name: 'database',
+ type: 'select',
+ message: 'Database Type',
+ choices: [
+ { title: 'None', value: null },
+ { title: 'MySQL', value: 'mysql' },
+ { title: 'MongoDB', value: 'mongo' },
+ ],
+}]
+
+const mysqlQuestions: PromptObject[] = [{
+ name: 'host',
+ type: 'text',
+ message: 'MySQL / Host',
+ initial: '127.0.0.1',
+}, {
+ name: 'port',
+ type: 'number',
+ message: 'MySQL / Port',
+ initial: '3306',
+}, {
+ name: 'user',
+ type: 'text',
+ message: 'MySQL / Username',
+ initial: 'root',
+}, {
+ name: 'password',
+ type: 'text',
+ message: 'MySQL / Password',
+}, {
+ name: 'database',
+ type: 'text',
+ message: 'MySQL / Database',
+ initial: 'koishi',
+}]
+
+const mongoQuestions: PromptObject[] = [{
+ name: 'host',
+ type: 'text',
+ message: 'MongoDB / Host',
+ initial: '127.0.0.1',
+}, {
+ name: 'port',
+ type: 'number',
+ message: 'MongoDB / Port',
+ initial: '27017',
+}, {
+ name: 'username',
+ type: 'text',
+ message: 'MongoDB / Username',
+ initial: 'root',
+}, {
+ name: 'password',
+ type: 'text',
+ message: 'MongoDB / Password',
+}, {
+ name: 'name',
+ type: 'text',
+ message: 'MongoDB / Database',
+ initial: 'koishi',
+}]
+
+const dbQuestionMap = {
+ mysql: mysqlQuestions,
+ mongo: mongoQuestions,
+}
+
+async function question(questions: PromptObject[]) {
let succeed = true
- const data = await prompts([{
- name: 'type',
- type: 'select',
- message: 'Connection Type',
- choices: [
- { title: 'HTTP', value: 'cqhttp:http' },
- { title: 'WebSocket', value: 'cqhttp:ws' },
- ],
- }, {
- name: 'port',
- type: (_, data) => data.type === 'cqhttp:http' ? 'number' : null,
- message: 'Koishi Port',
- initial: 8080,
- }, {
- name: 'server',
- type: (_, data) => data.type === 'cqhttp:http' ? 'text' : null,
- message: 'HTTP Server',
- initial: 'http://localhost:5700',
- }, {
- name: 'server',
- type: (_, data) => data.type === 'cqhttp:ws' ? 'text' : null,
- message: 'WebSocket Server',
- initial: 'ws://localhost:6700',
- }, {
- name: 'selfId',
- type: 'number',
- message: 'Your Bot\'s QQ Number',
- }, {
- name: 'secret',
- type: 'text',
- message: 'Secret for Koishi Server',
- }, {
- name: 'token',
- type: 'text',
- message: 'Token for CoolQ Server',
- }], {
+ const data = await prompts(questions, {
onCancel: () => succeed = false,
})
- if (!succeed) return
- const config = {} as AppConfig
- for (const key in data) {
- if (data[key]) config[key] = data[key]
+ if (!succeed) throw new Error('interrupted')
+ return data
+}
+
+type DependencyType = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies'
+
+interface Package extends Partial>> {
+ version: string
+ description?: string
+}
+
+const ecosystem: Record = require('../ecosystem')
+const builtinPackages = ['koishi-plugin-common']
+
+async function createConfig() {
+ const data = await question(serverQuestions)
+ const { database } = data
+ const config = { ...data, database: undefined, plugins: [] } as AppConfig
+
+ // database
+ if (database) {
+ config.plugins.push([database, await question(dbQuestionMap[database])])
}
- config.plugins = ['common', 'schedule']
+
+ // official plugins
+ const choices: Choice[] = Object.entries(ecosystem).map(([title, meta]) => {
+ if (!title.startsWith('koishi-plugin-')) return
+ const value = title.slice(14)
+ if (value in dbQuestionMap) return
+ const { description } = meta
+ const selected = builtinPackages.includes(title)
+ return { title, value, description, selected }
+ }).filter(Boolean)
+
+ const { plugins } = await prompts({
+ type: 'multiselect',
+ name: 'plugins',
+ message: 'Choose Official Plugins',
+ choices,
+ })
+
+ config.plugins.push(...plugins.map(name => [name]))
+
return config
}
+const workingDirectory = process.cwd()
const supportedTypes = ['js', 'ts', 'json'] as const
-type ConfigFileType = typeof supportedTypes[number]
+type SourceType = typeof supportedTypes[number]
-export default function (cli: CAC) {
- const error = red('error')
- const success = green('success')
+const error = red('error')
+const success = green('success')
+
+async function updateMeta(config: AppConfig) {
+ const path = resolve(workingDirectory, 'package.json')
+ const meta: Package = JSON.parse(await fs.readFile(path, 'utf8'))
+ let modified = false
+ if (!meta.dependencies) meta.dependencies = {}
+ for (const [name] of config.plugins as string[]) {
+ const fullname = 'koishi-plugin-' + name
+ if (!meta.dependencies[fullname]) {
+ modified = true
+ meta.dependencies[fullname] = '^' + ecosystem[fullname].version
+ }
+ }
+ if (!modified) return
+ await fs.writeFile(path, JSON.stringify(meta, null, 2))
+ console.log(`${success} package.json was updated`)
+}
+
+type Serializable = string | number | Serializable[] | { [key: string]: Serializable }
+function joinLines(lines: string[], type: SourceType, indent: string) {
+ return `\n ${indent}${lines.join(',\n ' + indent)}${type === 'json' ? '' : ','}\n${indent}`
+}
+
+function codegen(value: Serializable, type: SourceType, indent = '', path = '/') {
+ if (value === null) return 'null'
+ switch (typeof value) {
+ case 'number': case 'boolean': return '' + value
+ case 'string': return type === 'json' || value.includes("'") && !value.includes('"')
+ ? `"${value.replace(/"/g, '\\"')}"`
+ : `'${value.replace(/'/g, "\\'")}'`
+ case 'undefined': return undefined
+ }
+
+ if (Array.isArray(value)) {
+ return path === '/plugins/0/'
+ ? `[${value.map(value => codegen(value, type, indent, path + '0/')).join(', ')}]`
+ : `[${joinLines(value.map(value => codegen(value, type, ' ' + indent, path + '0/')), type, indent)}]`
+ }
+
+ return `{${joinLines(Object.entries(value).filter(([, value]) => value !== undefined).map(([key, value]) => {
+ const keyString = type === 'json' ? `"${key}"` : key
+ const valueString = codegen(value, type, ' ' + indent, path + key + '/')
+ return keyString + ': ' + valueString
+ }), type, indent)}}`
+}
+
+async function writeConfig(config: any, path: string, type: SourceType) {
+ // generate output
+ let output = codegen(config, type) + '\n'
+ if (type === 'js') {
+ output = 'module.exports = ' + output
+ } else if (type === 'ts') {
+ output = 'export = ' + output
+ }
+
+ // write to file
+ const folder = dirname(path)
+ await fs.mkdir(folder, { recursive: true })
+ await fs.writeFile(path, output)
+ console.log(`${success} created config file: ${path}`)
+}
+
+export default function (cli: CAC) {
cli.command('init [file]', 'initialize a koishi configuration file')
.option('-f, --forced', 'overwrite config file if it exists')
- .action(async (file, options) => {
+ .action(async (file = 'koishi.config.js', options) => {
// resolve file path
- const path = resolve(process.cwd(), String(file || 'koishi.config.js'))
+ const path = resolve(workingDirectory, file)
if (!options.forced && existsSync(path)) {
console.warn(`${error} ${options.output} already exists. If you want to overwrite the current file, use ${yellow('koishi init -f')}`)
process.exit(1)
}
// parse extension
- const extension = extname(path).slice(1) as ConfigFileType
+ const extension = extname(path).slice(1) as SourceType
if (!extension) {
console.warn(`${error} configuration file should have an extension, received "${file}"`)
process.exit(1)
@@ -82,28 +265,13 @@ export default function (cli: CAC) {
}
// create configurations
- const config = await createConfig()
+ const config = await createConfig().catch(() => {})
if (!config) {
console.warn(`${error} initialization was canceled`)
process.exit(0)
}
- // generate output
- let output = JSON.stringify(config, null, 2)
- if (extension !== 'json') {
- output = output.replace(/^(\s+)"([\w$]+)":/mg, '$1$2:')
- if (extension === 'js') {
- output = 'module.exports = ' + output
- } else if (extension === 'ts') {
- output = 'export = ' + output
- }
- }
-
- // write to file
- const folder = dirname(path)
- if (!existsSync(folder)) mkdirSync(folder, { recursive: true })
- writeFileSync(path, output)
- console.warn(`${success} created config file: ${path}`)
+ await Promise.all([updateMeta(config), writeConfig(config, path, extension)])
process.exit(0)
})
}
diff --git a/packages/koishi/src/run.ts b/packages/koishi/src/run.ts
index 66812ecf1f..0e307c71ca 100644
--- a/packages/koishi/src/run.ts
+++ b/packages/koishi/src/run.ts
@@ -26,6 +26,13 @@ process.on('SIGINT', () => {
}
})
+interface Message {
+ type: 'start' | 'exit'
+ payload: any
+}
+
+let payload: any
+
function createWorker(options: WorkerOptions) {
child = fork(resolve(__dirname, 'worker'), [], {
execArgv: options['--'],
@@ -33,9 +40,14 @@ function createWorker(options: WorkerOptions) {
let started = false
- child.on('message', (data) => {
- if (data === 'start') {
+ child.on('message', (message: Message) => {
+ if (message.type === 'start') {
started = true
+ if (payload) {
+ child.send({ type: 'send', payload })
+ }
+ } else if (message.type === 'exit') {
+ payload = message.payload
}
})
diff --git a/packages/koishi/src/worker.ts b/packages/koishi/src/worker.ts
index 6fe3061c78..fe56ad8f7d 100644
--- a/packages/koishi/src/worker.ts
+++ b/packages/koishi/src/worker.ts
@@ -1,6 +1,6 @@
import { App, AppOptions, Context, Plugin } from 'koishi-core'
import { resolve, dirname } from 'path'
-import { Logger } from 'koishi-utils'
+import { Logger, noop } from 'koishi-utils'
import { performance } from 'perf_hooks'
import { yellow } from 'kleur'
import 'koishi-adapter-cqhttp'
@@ -105,14 +105,38 @@ if (config.logLevel && !process.env.KOISHI_LOG_LEVEL) {
Logger.baseLevel = config.logLevel
}
+interface Message {
+ type: 'send'
+ payload: any
+}
+
+process.on('message', (data: Message) => {
+ if (data.type === 'send') {
+ const { groupId, userId, selfId, message } = data.payload
+ const bot = app.bots[selfId]
+ if (groupId) {
+ bot.sendGroupMsg(groupId, message)
+ } else {
+ bot.sendPrivateMsg(userId, message)
+ }
+ }
+})
+
const app = new App(config)
app.command('exit', '停止机器人运行', { authority: 4 })
.option('restart', '-r 重新启动')
.shortcut('关机', { prefix: true })
.shortcut('重启', { prefix: true, options: { restart: true } })
- .action(({ options }) => {
- process.exit(options.restart ? 514 : 0)
+ .action(async ({ options, session }) => {
+ const { groupId, userId, selfId } = session
+ if (!options.restart) {
+ await session.$send('正在关机……').catch(noop)
+ process.exit()
+ }
+ process.send({ type: 'exit', payload: { groupId, userId, selfId, message: '已成功重启。' } })
+ await session.$send(`正在重启……`).catch(noop)
+ process.exit(514)
})
if (Array.isArray(config.plugins)) {
@@ -131,5 +155,5 @@ app.start().then(() => {
const time = Math.max(0, performance.now() - +process.env.KOISHI_START_TIME).toFixed()
logger.success(`bot started successfully in ${time} ms.`)
- process.send('start')
+ process.send({ type: 'start' })
}, handleException)
diff --git a/packages/plugin-chess/package.json b/packages/plugin-chess/package.json
index 250b4def53..138cff3b2d 100644
--- a/packages/plugin-chess/package.json
+++ b/packages/plugin-chess/package.json
@@ -33,10 +33,10 @@
"game"
],
"peerDependencies": {
- "koishi-core": "^2.0.2",
+ "koishi-core": "^2.1.0",
"koishi-plugin-puppeteer": "^1.0.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-common/package.json b/packages/plugin-common/package.json
index e5a3a12a8f..00a293c261 100644
--- a/packages/plugin-common/package.json
+++ b/packages/plugin-common/package.json
@@ -31,12 +31,12 @@
"plugin"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"devDependencies": {
"koishi-test-utils": "^4.0.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-eval-addons/package.json b/packages/plugin-eval-addons/package.json
index 79cba96065..9d5e728a14 100644
--- a/packages/plugin-eval-addons/package.json
+++ b/packages/plugin-eval-addons/package.json
@@ -1,6 +1,6 @@
{
"name": "koishi-plugin-eval-addons",
- "version": "1.0.0-beta.8",
+ "version": "1.0.0-beta.10",
"description": "Execute JavaScript in Koishi",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
@@ -36,13 +36,13 @@
"code"
],
"peerDependencies": {
- "koishi-core": "^2.0.2",
+ "koishi-core": "^2.1.0",
"koishi-plugin-eval": "^2.0.0"
},
"dependencies": {
"js-yaml": "^3.14.0",
"json5": "^2.1.3",
- "koishi-utils": "^3.1.2",
+ "koishi-utils": "^3.1.3",
"simple-git": "^2.20.1",
"typescript": "^4.0.2"
},
diff --git a/packages/plugin-eval-addons/src/index.ts b/packages/plugin-eval-addons/src/index.ts
index 655e8825c7..e30d667597 100644
--- a/packages/plugin-eval-addons/src/index.ts
+++ b/packages/plugin-eval-addons/src/index.ts
@@ -5,18 +5,19 @@ import { safeLoad } from 'js-yaml'
import { promises as fs } from 'fs'
import { attachTraps, FieldOptions } from 'koishi-plugin-eval'
import Git, { CheckRepoActions } from 'simple-git'
+import { AddonWorkerConfig } from './worker'
const logger = new Logger('addon')
-type AddonConfig = Config
+export interface Config extends AddonMainConfig, AddonWorkerConfig {}
-export interface Config {
+export interface AddonMainConfig {
gitRemote?: string
exclude?: RegExp
}
declare module 'koishi-plugin-eval/dist/main' {
- interface MainConfig extends AddonConfig {}
+ interface MainConfig extends AddonMainConfig {}
}
interface OptionManifest extends OptionConfig {
diff --git a/packages/plugin-eval-addons/src/worker.ts b/packages/plugin-eval-addons/src/worker.ts
index 74437becca..d2d7012c55 100644
--- a/packages/plugin-eval-addons/src/worker.ts
+++ b/packages/plugin-eval-addons/src/worker.ts
@@ -1,5 +1,5 @@
import { config, context, internal, WorkerAPI, Context, response, mapDirectory, formatError } from 'koishi-plugin-eval/dist/worker'
-import { promises, readFileSync } from 'fs'
+import { promises as fs, readFileSync } from 'fs'
import { resolve, posix, dirname } from 'path'
import { Logger, Time, CQCode, Random } from 'koishi-utils'
import json5 from 'json5'
@@ -9,10 +9,12 @@ const logger = new Logger('addon')
const { SourceTextModule, SyntheticModule } = require('vm')
+export interface AddonWorkerConfig {
+ moduleRoot?: string
+}
+
declare module 'koishi-plugin-eval/dist/worker' {
- interface WorkerConfig {
- moduleRoot?: string
- }
+ interface WorkerConfig extends AddonWorkerConfig {}
interface WorkerData {
addonNames: string[]
@@ -120,7 +122,7 @@ async function loadSource(path: string) {
for (const postfix of suffixes) {
try {
const target = path + postfix
- return [await promises.readFile(resolve(config.moduleRoot, target), 'utf8'), target]
+ return [await fs.readFile(resolve(config.moduleRoot, target), 'utf8'), target]
} catch {}
}
throw new Error(`cannot load source file "${path}"`)
@@ -142,7 +144,10 @@ async function createModule(path: string) {
await module.evaluate()
if (!path.includes('/')) {
- internal.setGlobal(path, module.namespace)
+ const namespace = internal.decontextify(module.namespace)
+ if (Object.keys(namespace).length) {
+ internal.setGlobal(path, namespace)
+ }
}
return module
}
@@ -158,5 +163,5 @@ export async function evaluate(path: string) {
export default Promise.all(config.addonNames.map(evaluate)).then(() => {
response.commands = Object.keys(commandMap)
mapDirectory('koishi/utils/', require.resolve('koishi-utils'))
- internal.setGlobal('utils', modules['koishi/utils.ts'].namespace)
+ internal.setGlobal('utils', internal.decontextify(modules['koishi/utils.ts'].namespace))
})
diff --git a/packages/plugin-eval/package.json b/packages/plugin-eval/package.json
index a92f6f3429..38307bdb52 100644
--- a/packages/plugin-eval/package.json
+++ b/packages/plugin-eval/package.json
@@ -37,12 +37,12 @@
"code"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"devDependencies": {
"koishi-test-utils": "^4.0.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-github/package.json b/packages/plugin-github/package.json
index dbd6f16aec..bd4511b603 100644
--- a/packages/plugin-github/package.json
+++ b/packages/plugin-github/package.json
@@ -1,7 +1,7 @@
{
"name": "koishi-plugin-github",
"description": "GitHub webhook plugin for Koishi",
- "version": "2.0.0-beta.9",
+ "version": "2.0.0-beta.10",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
@@ -36,12 +36,12 @@
"koishi-test-utils": "^4.0.0"
},
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
"@octokit/rest": "^18.0.4",
"@octokit/webhooks": "^7.11.2",
"axios": "^0.20.0",
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-github/src/events.ts b/packages/plugin-github/src/events.ts
new file mode 100644
index 0000000000..de00ad0248
--- /dev/null
+++ b/packages/plugin-github/src/events.ts
@@ -0,0 +1,209 @@
+/* eslint-disable camelcase */
+
+import { EventNames, EventPayloads, Webhooks } from '@octokit/webhooks'
+import { GetWebhookPayloadTypeFromEvent } from '@octokit/webhooks/dist-types/generated/get-webhook-payload-type-from-event'
+import { Octokit } from '@octokit/rest'
+import { Context, Middleware, Session } from 'koishi-core'
+import { defineProperty } from 'koishi-utils'
+import { Config } from '.'
+
+type Payload = GetWebhookPayloadTypeFromEvent['payload']
+type Repository = EventPayloads.PayloadRepository
+type Issue =
+ | EventPayloads.WebhookPayloadIssuesIssue
+ | EventPayloads.WebhookPayloadPullRequestPullRequest
+ | EventPayloads.WebhookPayloadPullRequestReviewPullRequest
+type ReviewComment = EventPayloads.WebhookPayloadPullRequestReviewCommentComment
+
+export default function apply(ctx: Context, config: Config) {
+ const github = new Octokit({
+ request: {
+ agent: config.agent,
+ timeout: config.requestTimeout,
+ },
+ })
+
+ const webhooks = new Webhooks({
+ ...config,
+ path: config.webhook,
+ })
+
+ defineProperty(ctx.app, 'githubWebhooks', webhooks)
+
+ const interactions: Record = {}
+
+ ctx.router.post(config.webhook, (ctx, next) => {
+ // workaround @octokit/webhooks for koa
+ ctx.req['body'] = ctx.request.body
+ return webhooks.middleware(ctx.req, ctx.res, next)
+ })
+
+ ctx.on('before-attach-user', (session, fields) => {
+ if (interactions[session.$reply]) {
+ fields.add('githubToken')
+ }
+ })
+
+ ctx.middleware((session, next) => {
+ const middleware = interactions[session.$reply]
+ return middleware ? middleware(session, next) : next()
+ })
+
+ function registerHandler(event: T, handler: (payload: Payload) => [string, Middleware?]) {
+ webhooks.on(event, async (callback) => {
+ const { repository } = callback.payload
+ const groupIds = config.repos[repository.full_name]
+ if (!groupIds) return
+
+ const result = handler(callback.payload)
+ if (!result) return
+
+ const [message, middleware] = result
+ const messageIds = await ctx.broadcast(groupIds, message)
+ if (!middleware) return
+
+ for (const id of messageIds) {
+ interactions[id] = middleware
+ }
+ setTimeout(() => {
+ for (const id of messageIds) {
+ delete interactions[id]
+ }
+ }, config.replyTimeout)
+ })
+ }
+
+ function formatMarkdown(source: string) {
+ return source
+ .replace(/^```(.*)$/gm, '')
+ .replace(/\n\s*\n/g, '\n')
+ }
+
+ registerHandler('commit_comment.created', ({ repository, comment }) => {
+ const { user, html_url, commit_id, body } = comment
+ return [[
+ `[GitHub] ${user.login} commented on commit ${repository.full_name}@${commit_id.slice(0, 6)}`,
+ `URL: ${html_url}`,
+ formatMarkdown(body),
+ ].join('\n')]
+ })
+
+ registerHandler('fork', ({ repository, sender, forkee }) => {
+ const { full_name, forks_count } = repository
+ return [`[GitHub] ${sender.login} forked ${full_name} to ${forkee.full_name} (total ${forks_count} forks)`]
+ })
+
+ const checkToken: Middleware = async (session: Session<'githubToken'>, next) => {
+ if (!session.$user.githubToken) {
+ await session.$send('如果想使用此功能,请对机器人进行授权,输入你的 GitHub 用户名。')
+ const name = await session.$prompt().catch()
+ if (!name) return
+ return session.$execute({ command: 'github', args: [name] })
+ }
+ return next()
+ }
+
+ const createIssueComment = (repo: Repository, issue: Issue): Middleware => async (session, next) => {
+ const body = session.$parsed
+ if (!body) return next()
+ return checkToken(session, async () => {
+ await github.issues.createComment({
+ owner: repo.owner.login,
+ repo: repo.name,
+ issue_number: issue.number,
+ body,
+ headers: {
+ Authorization: `token ${session.$user['githubToken']}`,
+ },
+ })
+ })
+ }
+
+ const createReviewCommentReply = (repo: Repository, issue: Issue, comment: ReviewComment): Middleware => async (session, next) => {
+ const body = session.$parsed
+ if (!body) return next()
+ return checkToken(session, async () => {
+ await github.pulls.createReplyForReviewComment({
+ owner: repo.owner.login,
+ repo: repo.name,
+ pull_number: issue.number,
+ comment_id: comment.id,
+ body,
+ headers: {
+ Authorization: `token ${session.$user['githubToken']}`,
+ },
+ })
+ })
+ }
+
+ registerHandler('issues.opened', ({ repository, issue }) => {
+ const { user, html_url, title, body, number } = issue
+ return [[
+ `[GitHub] ${user.login} opened an issue ${repository.full_name}#${number}`,
+ `URL: ${html_url}`,
+ `Title: ${title}`,
+ formatMarkdown(body),
+ ].join('\n'), createIssueComment(repository, issue)]
+ })
+
+ registerHandler('issue_comment.created', ({ comment, issue, repository }) => {
+ const { user, html_url, body } = comment
+ const type = issue['pull_request'] ? 'pull request' : 'issue'
+ return [[
+ `[GitHub] ${user.login} commented on ${type} ${repository.full_name}#${issue.number}`,
+ `URL: ${html_url}`,
+ formatMarkdown(body),
+ ].join('\n'), createIssueComment(repository, issue)]
+ })
+
+ registerHandler('pull_request.opened', ({ repository, pull_request }) => {
+ const { user, html_url, base, head, body, number } = pull_request
+ return [[
+ `[GitHub] ${user.login} opened a pull request ${repository.full_name}#${number} (${base.label} <- ${head.label})`,
+ `URL: ${html_url}`,
+ formatMarkdown(body),
+ ].join('\n'), createIssueComment(repository, pull_request)]
+ })
+
+ registerHandler('pull_request_review.submitted', ({ repository, review, pull_request }) => {
+ if (!review.body) return
+ const { user, html_url, body } = review
+ return [[
+ `[GitHub] ${user.login} reviewed pull request ${repository.full_name}#${pull_request.number}`,
+ `URL: ${html_url}`,
+ // @ts-ignore
+ formatMarkdown(body),
+ ].join('\n'), createIssueComment(repository, pull_request)]
+ })
+
+ registerHandler('pull_request_review_comment.created', ({ repository, comment, pull_request }) => {
+ const { user, path, html_url, body } = comment
+ return [[
+ `[GitHub] ${user.login} commented on pull request review ${repository.full_name}#${pull_request.number}`,
+ `Path: ${path}`,
+ `URL: ${html_url}`,
+ formatMarkdown(body),
+ ].join('\n'), createReviewCommentReply(repository, pull_request, comment)]
+ })
+
+ registerHandler('push', ({ compare, pusher, commits, repository, ref, after }) => {
+ // do not show pull request merge
+ if (/^0+$/.test(after)) return
+
+ // use short form for tag releases
+ if (ref.startsWith('refs/tags')) {
+ return [`[GitHub] ${pusher.name} published tag ${repository.full_name}@${ref.slice(10)}`]
+ }
+
+ return [[
+ `[GitHub] ${pusher.name} pushed to ${repository.full_name}:${ref.replace(/^refs\/heads\//, '')}`,
+ `Compare: ${compare}`,
+ ...commits.map(c => `[${c.id.slice(0, 6)}] ${formatMarkdown(c.message)}`),
+ ].join('\n')]
+ })
+
+ registerHandler('star.created', ({ repository, sender }) => {
+ const { full_name, stargazers_count } = repository
+ return [`[GitHub] ${sender.login} starred ${full_name} (total ${stargazers_count} stargazers)`]
+ })
+}
diff --git a/packages/plugin-github/src/index.ts b/packages/plugin-github/src/index.ts
index 0c354952dd..30486d2031 100644
--- a/packages/plugin-github/src/index.ts
+++ b/packages/plugin-github/src/index.ts
@@ -1,20 +1,18 @@
/* eslint-disable camelcase */
-import { Context, Middleware, User } from 'koishi-core'
+import { Context, User } from 'koishi-core'
import { Logger, Time } from 'koishi-utils'
-import { Octokit } from '@octokit/rest'
-import { Webhooks, EventNames, EventPayloads } from '@octokit/webhooks'
-import { GetWebhookPayloadTypeFromEvent } from '@octokit/webhooks/dist-types/generated/get-webhook-payload-type-from-event'
+import { Webhooks } from '@octokit/webhooks'
import { Agent } from 'http'
import { encode } from 'querystring'
import axios from 'axios'
+import events from './events'
-type Payload = GetWebhookPayloadTypeFromEvent['payload']
-type Repository = EventPayloads.PayloadRepository
-type Issue = EventPayloads.WebhookPayloadIssuesIssue
- | EventPayloads.WebhookPayloadPullRequestPullRequest
- | EventPayloads.WebhookPayloadPullRequestReviewPullRequest
-type ReviewComment = EventPayloads.WebhookPayloadPullRequestReviewCommentComment
+declare module 'koishi-core/dist/app' {
+ interface App {
+ githubWebhooks?: Webhooks
+ }
+}
declare module 'koishi-core/dist/database' {
interface User {
@@ -56,27 +54,17 @@ const defaultOptions: Config = {
repos: {},
}
-export const name = 'github-webhook'
+export const name = 'github'
export function apply(ctx: Context, config: Config = {}) {
if (!ctx.router) throw new Error('ctx.router is not defined')
config = { ...defaultOptions, ...config }
- const webhook = new Webhooks(config)
- const github = new Octokit({
- request: {
- agent: config.agent,
- timeout: config.requestTimeout,
- },
- })
+ ctx.plugin(events, config)
- const { router, database } = ctx
+ const { database } = ctx
- router.post(config.webhook, (ctx, next) => {
- return webhook.middleware(ctx.req, ctx.res, next)
- })
-
- router.get(config.authorize, async (ctx) => {
+ ctx.router.get(config.authorize, async (ctx) => {
const targetId = parseInt(ctx.query.state)
if (Number.isNaN(targetId)) throw new Error('Invalid targetId')
const { code, state } = ctx.query
@@ -111,154 +99,4 @@ export function apply(ctx: Context, config: Config = {}) {
})
return '请点击下面的链接继续操作:\n' + url
})
-
- const interactions: Record = {}
-
- ctx.middleware((session, next) => {
- const middleware = interactions[session.$reply]
- return middleware ? middleware(session, next) : next()
- })
-
- function registerHandler(event: T, handler: (payload: Payload) => [string, Middleware?]) {
- webhook.on(event, async (callback) => {
- const { repository } = callback.payload
- const groupIds = config.repos[repository.full_name]
- if (!groupIds) return
-
- const result = handler(callback.payload)
- if (!result) return
-
- const [message, middleware] = result
- const messageIds = await ctx.broadcast(groupIds, message)
- if (!middleware) return
-
- for (const id of messageIds) {
- interactions[id] = middleware
- }
- setTimeout(() => {
- for (const id of messageIds) {
- delete interactions[id]
- }
- }, config.replyTimeout)
- })
- }
-
- function formatMarkdown(source: string) {
- return source
- .replace(/^```(.*)$/gm, '')
- .replace(/\n\s*\n/g, '\n')
- }
-
- registerHandler('commit_comment.created', ({ repository, comment }) => {
- return [[
- `[GitHub] ${comment.user.login} commented on commit ${repository.full_name}@${comment.commit_id.slice(0, 6)}`,
- `URL: ${comment.html_url}`,
- formatMarkdown(comment.body),
- ].join('\n')]
- })
-
- const checkToken: Middleware = async (session, next) => {
- const user = await session.$observeUser(['githubToken'])
- if (!user.githubToken) {
- await session.$send('如果想使用此功能,请对机器人进行授权,输入你的 GitHub 用户名。')
- const name = await session.$prompt().catch()
- if (!name) return
- return session.$execute({ command: 'github', args: [name] })
- }
- return next()
- }
-
- const createIssueComment = (repo: Repository, issue: Issue): Middleware => async (session, next) => {
- const body = session.$parsed
- if (!body) return next()
- return checkToken(session, async () => {
- await github.issues.createComment({
- owner: repo.owner.login,
- repo: repo.name,
- issue_number: issue.number,
- body,
- headers: {
- Authorization: `token ${session.$user['githubToken']}`,
- },
- })
- })
- }
-
- const createReviewCommentReply = (repo: Repository, issue: Issue, comment: ReviewComment): Middleware => async (session, next) => {
- const body = session.$parsed
- if (!body) return next()
- return checkToken(session, async () => {
- await github.pulls.createReplyForReviewComment({
- owner: repo.owner.login,
- repo: repo.name,
- pull_number: issue.number,
- comment_id: comment.id,
- body,
- headers: {
- Authorization: `token ${session.$user['githubToken']}`,
- },
- })
- })
- }
-
- registerHandler('issues.opened', ({ repository, issue }) => {
- return [[
- `[GitHub] ${issue.user.login} opened an issue ${repository.full_name}#${issue.number}`,
- `URL: ${issue.html_url}`,
- `Title: ${issue.title}`,
- formatMarkdown(issue.body),
- ].join('\n'), createIssueComment(repository, issue)]
- })
-
- registerHandler('issue_comment.created', ({ comment, issue, repository }) => {
- const type = issue['pull_request'] ? 'pull request' : 'issue'
- return [[
- `[GitHub] ${comment.user.login} commented on ${type} ${repository.full_name}#${issue.number}`,
- `URL: ${comment.html_url}`,
- formatMarkdown(comment.body),
- ].join('\n'), createIssueComment(repository, issue)]
- })
-
- registerHandler('pull_request.opened', ({ repository, pull_request }) => {
- return [[
- `[GitHub] ${pull_request.user.login} opened a pull request ${repository.full_name}#${pull_request.number} (${pull_request.base.label} <- ${pull_request.head.label})`,
- `URL: ${pull_request.html_url}`,
- formatMarkdown(pull_request.body),
- ].join('\n'), createIssueComment(repository, pull_request)]
- })
-
- registerHandler('pull_request_review.submitted', ({ repository, review, pull_request }) => {
- if (!review.body) return
- return [[
- `[GitHub] ${review.user.login} reviewed pull request ${repository.full_name}#${pull_request.number}`,
- `URL: ${review.html_url}`,
- // @ts-ignore
- formatMarkdown(review.body),
- ].join('\n'), createIssueComment(repository, pull_request)]
- })
-
- registerHandler('pull_request_review_comment.created', ({ repository, comment, pull_request }) => {
- return [[
- `[GitHub] ${comment.user.login} commented on pull request review ${repository.full_name}#${pull_request.number}`,
- `Path: ${comment.path}`,
- `URL: ${comment.html_url}`,
- formatMarkdown(comment.body),
- ].join('\n'), createReviewCommentReply(repository, pull_request, comment)]
- })
-
- registerHandler('push', ({ compare, pusher, commits, repository, ref, after }) => {
- // do not show pull request merge
- if (/^0+$/.test(after)) return
-
- // use short form for tag releases
- if (ref.startsWith('refs/tags')) {
- return [`[GitHub] ${pusher.name} published tag ${repository.full_name}@${ref.slice(10)}`]
- }
-
- return [[
- `[GitHub] ${pusher.name} pushed to ${repository.full_name}:${ref}`,
- `Compare: ${compare}`,
- ...commits.map(c => `[${c.id.slice(0, 6)}] ${formatMarkdown(c.message)}`),
- ].join('\n')]
- })
}
diff --git a/packages/plugin-github/tests/__snapshots__/index.spec.ts.snap b/packages/plugin-github/tests/__snapshots__/index.spec.ts.snap
deleted file mode 100644
index 72e82b8f86..0000000000
--- a/packages/plugin-github/tests/__snapshots__/index.spec.ts.snap
+++ /dev/null
@@ -1,141 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`check_run.completed: check_run.completed 1`] = `undefined`;
-
-exports[`chect_suite.completed: chect_suite.completed 1`] = `undefined`;
-
-exports[`commit_comment.created: commit_comment.created 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Commit Comment (koishijs/koishi)
-User: Shigma
-URL: https://github.com/koishijs/koishi/commit/bff469eabe14d42683a4f7c3ccb659daec5e1c00#commitcomment-36878220
-This will introduce a failure in test.",
- },
-]
-`;
-
-exports[`issue_comment.created.1: issue_comment.created.1 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Issue Comment (koishijs/koishi#19)
-User: simon300000
-URL: https://github.com/koishijs/koishi/issues/19#issuecomment-576277946
-Mich würde auch interessieren, was ist „CoolQ“?",
- },
-]
-`;
-
-exports[`issue_comment.created.2: issue_comment.created.2 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Pull Request Comment (koishijs/koishi#20)
-User: Kouchya
-URL: https://github.com/koishijs/koishi/pull/20#issuecomment-576291300
-C'est important!",
- },
-]
-`;
-
-exports[`issues.assigned: issues.assigned 1`] = `undefined`;
-
-exports[`issues.closed: issues.closed 1`] = `undefined`;
-
-exports[`issues.labeled: issues.labeled 1`] = `undefined`;
-
-exports[`issues.opened: issues.opened 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Issue Opened (koishijs/koishi#19)
-Title: Wie kann man um das Koishi zu installieren?
-User: simon300000
-URL: https://github.com/koishijs/koishi/issues/19
-Ich verstecke Englisch und Chinesisch nicht! Gab es Personen, die mir helfen kann?",
- },
-]
-`;
-
-exports[`pull_request.opened: pull_request.opened 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Pull Request Opened (koishijs/koishi#364852707)
-koishijs:develop <- koishijs:experimental
-User: simon300000
-URL: https://github.com/koishijs/koishi/pull/20
-Das ist wichtig!",
- },
-]
-`;
-
-exports[`pull_request_review.submitted.1: pull_request_review.submitted.1 1`] = `undefined`;
-
-exports[`pull_request_review.submitted.2: pull_request_review.submitted.2 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Pull Request Review (koishijs/koishi#364852707)
-User: Kouchya
-URL: https://github.com/koishijs/koishi/pull/20#pullrequestreview-345349537
-LGTM",
- },
-]
-`;
-
-exports[`pull_request_review_comment.created: pull_request_review_comment.created 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Pull Request Review Comment (koishijs/koishi#364852707)
-Path: packages/test-utils/src/mocks.ts
-User: Shigma
-URL: https://github.com/koishijs/koishi/pull/20#discussion_r368570320
-Naming is so hard......",
- },
-]
-`;
-
-exports[`push.commit: push.commit 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] Push (koishijs/koishi)
-Ref: refs/heads/develop
-User: Shigma
-Compare: https://github.com/koishijs/koishi/compare/976c6e8f09a4...3ae7e7044d06
-chore: adjust
-fix(core): create major context at demand",
- },
-]
-`;
-
-exports[`push.tag: push.tag 1`] = `
-Array [
- "send_group_msg",
- Object {
- "auto_escape": false,
- "group_id": 123,
- "message": "[GitHub] koishijs/koishi published tag 1.5.0",
- },
-]
-`;
diff --git a/packages/plugin-github/tests/__fixtures__/check_run.completed.json b/packages/plugin-github/tests/fixtures/check_run.completed.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/check_run.completed.json
rename to packages/plugin-github/tests/fixtures/check_run.completed.json
diff --git a/packages/plugin-github/tests/__fixtures__/chect_suite.completed.json b/packages/plugin-github/tests/fixtures/chect_suite.completed.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/chect_suite.completed.json
rename to packages/plugin-github/tests/fixtures/chect_suite.completed.json
diff --git a/packages/plugin-github/tests/__fixtures__/commit_comment.created.json b/packages/plugin-github/tests/fixtures/commit_comment.created.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/commit_comment.created.json
rename to packages/plugin-github/tests/fixtures/commit_comment.created.json
diff --git a/packages/plugin-github/tests/fixtures/fork.json b/packages/plugin-github/tests/fixtures/fork.json
new file mode 100644
index 0000000000..5aba27cde2
--- /dev/null
+++ b/packages/plugin-github/tests/fixtures/fork.json
@@ -0,0 +1,237 @@
+{
+ "forkee": {
+ "id": 290096040,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyOTAwOTYwNDA=",
+ "name": "koishi",
+ "full_name": "jjyyxx/koishi",
+ "private": false,
+ "owner": {
+ "login": "jjyyxx",
+ "id": 13808089,
+ "node_id": "MDQ6VXNlcjEzODA4MDg5",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13808089?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/jjyyxx",
+ "html_url": "https://github.com/jjyyxx",
+ "followers_url": "https://api.github.com/users/jjyyxx/followers",
+ "following_url": "https://api.github.com/users/jjyyxx/following{/other_user}",
+ "gists_url": "https://api.github.com/users/jjyyxx/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/jjyyxx/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/jjyyxx/subscriptions",
+ "organizations_url": "https://api.github.com/users/jjyyxx/orgs",
+ "repos_url": "https://api.github.com/users/jjyyxx/repos",
+ "events_url": "https://api.github.com/users/jjyyxx/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/jjyyxx/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/jjyyxx/koishi",
+ "description": "QQ bot out of the box",
+ "fork": true,
+ "url": "https://api.github.com/repos/jjyyxx/koishi",
+ "forks_url": "https://api.github.com/repos/jjyyxx/koishi/forks",
+ "keys_url": "https://api.github.com/repos/jjyyxx/koishi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/jjyyxx/koishi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/jjyyxx/koishi/teams",
+ "hooks_url": "https://api.github.com/repos/jjyyxx/koishi/hooks",
+ "issue_events_url": "https://api.github.com/repos/jjyyxx/koishi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/jjyyxx/koishi/events",
+ "assignees_url": "https://api.github.com/repos/jjyyxx/koishi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/jjyyxx/koishi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/jjyyxx/koishi/tags",
+ "blobs_url": "https://api.github.com/repos/jjyyxx/koishi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/jjyyxx/koishi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/jjyyxx/koishi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/jjyyxx/koishi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/jjyyxx/koishi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/jjyyxx/koishi/languages",
+ "stargazers_url": "https://api.github.com/repos/jjyyxx/koishi/stargazers",
+ "contributors_url": "https://api.github.com/repos/jjyyxx/koishi/contributors",
+ "subscribers_url": "https://api.github.com/repos/jjyyxx/koishi/subscribers",
+ "subscription_url": "https://api.github.com/repos/jjyyxx/koishi/subscription",
+ "commits_url": "https://api.github.com/repos/jjyyxx/koishi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/jjyyxx/koishi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/jjyyxx/koishi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/jjyyxx/koishi/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/jjyyxx/koishi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/jjyyxx/koishi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/jjyyxx/koishi/merges",
+ "archive_url": "https://api.github.com/repos/jjyyxx/koishi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/jjyyxx/koishi/downloads",
+ "issues_url": "https://api.github.com/repos/jjyyxx/koishi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/jjyyxx/koishi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/jjyyxx/koishi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/jjyyxx/koishi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/jjyyxx/koishi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/jjyyxx/koishi/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/jjyyxx/koishi/deployments",
+ "created_at": "2020-08-25T02:51:14Z",
+ "updated_at": "2020-08-24T19:15:52Z",
+ "pushed_at": "2020-08-24T18:51:18Z",
+ "git_url": "git://github.com/jjyyxx/koishi.git",
+ "ssh_url": "git@github.com:jjyyxx/koishi.git",
+ "clone_url": "https://github.com/jjyyxx/koishi.git",
+ "svn_url": "https://github.com/jjyyxx/koishi",
+ "homepage": "https://koishi.js.org",
+ "size": 2438,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": false,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": false,
+ "has_pages": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 0,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "public": true
+ },
+ "repository": {
+ "id": 225572038,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyMjU1NzIwMzg=",
+ "name": "koishi",
+ "full_name": "koishijs/koishi",
+ "private": false,
+ "owner": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/koishijs",
+ "html_url": "https://github.com/koishijs",
+ "followers_url": "https://api.github.com/users/koishijs/followers",
+ "following_url": "https://api.github.com/users/koishijs/following{/other_user}",
+ "gists_url": "https://api.github.com/users/koishijs/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/koishijs/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/koishijs/subscriptions",
+ "organizations_url": "https://api.github.com/users/koishijs/orgs",
+ "repos_url": "https://api.github.com/users/koishijs/repos",
+ "events_url": "https://api.github.com/users/koishijs/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/koishijs/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/koishijs/koishi",
+ "description": "QQ bot out of the box",
+ "fork": false,
+ "url": "https://api.github.com/repos/koishijs/koishi",
+ "forks_url": "https://api.github.com/repos/koishijs/koishi/forks",
+ "keys_url": "https://api.github.com/repos/koishijs/koishi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/koishijs/koishi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/koishijs/koishi/teams",
+ "hooks_url": "https://api.github.com/repos/koishijs/koishi/hooks",
+ "issue_events_url": "https://api.github.com/repos/koishijs/koishi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/koishijs/koishi/events",
+ "assignees_url": "https://api.github.com/repos/koishijs/koishi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/koishijs/koishi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/koishijs/koishi/tags",
+ "blobs_url": "https://api.github.com/repos/koishijs/koishi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/koishijs/koishi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/koishijs/koishi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/koishijs/koishi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/koishijs/koishi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/koishijs/koishi/languages",
+ "stargazers_url": "https://api.github.com/repos/koishijs/koishi/stargazers",
+ "contributors_url": "https://api.github.com/repos/koishijs/koishi/contributors",
+ "subscribers_url": "https://api.github.com/repos/koishijs/koishi/subscribers",
+ "subscription_url": "https://api.github.com/repos/koishijs/koishi/subscription",
+ "commits_url": "https://api.github.com/repos/koishijs/koishi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/koishijs/koishi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/koishijs/koishi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/koishijs/koishi/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/koishijs/koishi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/koishijs/koishi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/koishijs/koishi/merges",
+ "archive_url": "https://api.github.com/repos/koishijs/koishi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/koishijs/koishi/downloads",
+ "issues_url": "https://api.github.com/repos/koishijs/koishi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/koishijs/koishi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/koishijs/koishi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/koishijs/koishi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/koishijs/koishi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/koishijs/koishi/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/koishijs/koishi/deployments",
+ "created_at": "2019-12-03T08:47:29Z",
+ "updated_at": "2020-08-24T19:15:52Z",
+ "pushed_at": "2020-08-24T18:51:18Z",
+ "git_url": "git://github.com/koishijs/koishi.git",
+ "ssh_url": "git@github.com:koishijs/koishi.git",
+ "clone_url": "https://github.com/koishijs/koishi.git",
+ "svn_url": "https://github.com/koishijs/koishi",
+ "homepage": "https://koishi.js.org",
+ "size": 2438,
+ "stargazers_count": 186,
+ "watchers_count": 186,
+ "language": "TypeScript",
+ "has_issues": true,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": false,
+ "has_pages": false,
+ "forks_count": 12,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 2,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 12,
+ "open_issues": 2,
+ "watchers": 186,
+ "default_branch": "master"
+ },
+ "organization": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "url": "https://api.github.com/orgs/koishijs",
+ "repos_url": "https://api.github.com/orgs/koishijs/repos",
+ "events_url": "https://api.github.com/orgs/koishijs/events",
+ "hooks_url": "https://api.github.com/orgs/koishijs/hooks",
+ "issues_url": "https://api.github.com/orgs/koishijs/issues",
+ "members_url": "https://api.github.com/orgs/koishijs/members{/member}",
+ "public_members_url": "https://api.github.com/orgs/koishijs/public_members{/member}",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "description": ""
+ },
+ "sender": {
+ "login": "jjyyxx",
+ "id": 13808089,
+ "node_id": "MDQ6VXNlcjEzODA4MDg5",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13808089?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/jjyyxx",
+ "html_url": "https://github.com/jjyyxx",
+ "followers_url": "https://api.github.com/users/jjyyxx/followers",
+ "following_url": "https://api.github.com/users/jjyyxx/following{/other_user}",
+ "gists_url": "https://api.github.com/users/jjyyxx/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/jjyyxx/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/jjyyxx/subscriptions",
+ "organizations_url": "https://api.github.com/users/jjyyxx/orgs",
+ "repos_url": "https://api.github.com/users/jjyyxx/repos",
+ "events_url": "https://api.github.com/users/jjyyxx/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/jjyyxx/received_events",
+ "type": "User",
+ "site_admin": false
+ }
+}
\ No newline at end of file
diff --git a/packages/plugin-github/tests/__fixtures__/issue_comment.created.1.json b/packages/plugin-github/tests/fixtures/issue_comment.created.1.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/issue_comment.created.1.json
rename to packages/plugin-github/tests/fixtures/issue_comment.created.1.json
diff --git a/packages/plugin-github/tests/__fixtures__/issue_comment.created.2.json b/packages/plugin-github/tests/fixtures/issue_comment.created.2.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/issue_comment.created.2.json
rename to packages/plugin-github/tests/fixtures/issue_comment.created.2.json
diff --git a/packages/plugin-github/tests/__fixtures__/issues.assigned.json b/packages/plugin-github/tests/fixtures/issues.assigned.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/issues.assigned.json
rename to packages/plugin-github/tests/fixtures/issues.assigned.json
diff --git a/packages/plugin-github/tests/__fixtures__/issues.closed.json b/packages/plugin-github/tests/fixtures/issues.closed.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/issues.closed.json
rename to packages/plugin-github/tests/fixtures/issues.closed.json
diff --git a/packages/plugin-github/tests/__fixtures__/issues.labeled.json b/packages/plugin-github/tests/fixtures/issues.labeled.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/issues.labeled.json
rename to packages/plugin-github/tests/fixtures/issues.labeled.json
diff --git a/packages/plugin-github/tests/__fixtures__/issues.opened.json b/packages/plugin-github/tests/fixtures/issues.opened.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/issues.opened.json
rename to packages/plugin-github/tests/fixtures/issues.opened.json
diff --git a/packages/plugin-github/tests/__fixtures__/pull_request.opened.json b/packages/plugin-github/tests/fixtures/pull_request.opened.1.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/pull_request.opened.json
rename to packages/plugin-github/tests/fixtures/pull_request.opened.1.json
diff --git a/packages/plugin-github/tests/fixtures/pull_request.opened.2.json b/packages/plugin-github/tests/fixtures/pull_request.opened.2.json
new file mode 100644
index 0000000000..3ca357be35
--- /dev/null
+++ b/packages/plugin-github/tests/fixtures/pull_request.opened.2.json
@@ -0,0 +1,495 @@
+{
+ "action": "opened",
+ "number": 90,
+ "pull_request": {
+ "url": "https://api.github.com/repos/koishijs/koishi/pulls/90",
+ "id": 472904293,
+ "node_id": "MDExOlB1bGxSZXF1ZXN0NDcyOTA0Mjkz",
+ "html_url": "https://github.com/koishijs/koishi/pull/90",
+ "diff_url": "https://github.com/koishijs/koishi/pull/90.diff",
+ "patch_url": "https://github.com/koishijs/koishi/pull/90.patch",
+ "issue_url": "https://api.github.com/repos/koishijs/koishi/issues/90",
+ "number": 90,
+ "state": "open",
+ "locked": false,
+ "title": "test: fix path mapping",
+ "user": {
+ "login": "jjyyxx",
+ "id": 13808089,
+ "node_id": "MDQ6VXNlcjEzODA4MDg5",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13808089?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/jjyyxx",
+ "html_url": "https://github.com/jjyyxx",
+ "followers_url": "https://api.github.com/users/jjyyxx/followers",
+ "following_url": "https://api.github.com/users/jjyyxx/following{/other_user}",
+ "gists_url": "https://api.github.com/users/jjyyxx/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/jjyyxx/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/jjyyxx/subscriptions",
+ "organizations_url": "https://api.github.com/users/jjyyxx/orgs",
+ "repos_url": "https://api.github.com/users/jjyyxx/repos",
+ "events_url": "https://api.github.com/users/jjyyxx/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/jjyyxx/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "body": "According to `tsconfig-paths` documentation ...",
+ "created_at": "2020-08-25T02:57:41Z",
+ "updated_at": "2020-08-25T02:57:41Z",
+ "closed_at": null,
+ "merged_at": null,
+ "merge_commit_sha": null,
+ "assignee": null,
+ "assignees": [
+
+ ],
+ "requested_reviewers": [
+
+ ],
+ "requested_teams": [
+
+ ],
+ "labels": [
+
+ ],
+ "milestone": null,
+ "draft": false,
+ "commits_url": "https://api.github.com/repos/koishijs/koishi/pulls/90/commits",
+ "review_comments_url": "https://api.github.com/repos/koishijs/koishi/pulls/90/comments",
+ "review_comment_url": "https://api.github.com/repos/koishijs/koishi/pulls/comments{/number}",
+ "comments_url": "https://api.github.com/repos/koishijs/koishi/issues/90/comments",
+ "statuses_url": "https://api.github.com/repos/koishijs/koishi/statuses/b1ea76d2dfc43e4ba5852b52e1eeb03beeb36541",
+ "head": {
+ "label": "jjyyxx:mapping",
+ "ref": "mapping",
+ "sha": "b1ea76d2dfc43e4ba5852b52e1eeb03beeb36541",
+ "user": {
+ "login": "jjyyxx",
+ "id": 13808089,
+ "node_id": "MDQ6VXNlcjEzODA4MDg5",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13808089?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/jjyyxx",
+ "html_url": "https://github.com/jjyyxx",
+ "followers_url": "https://api.github.com/users/jjyyxx/followers",
+ "following_url": "https://api.github.com/users/jjyyxx/following{/other_user}",
+ "gists_url": "https://api.github.com/users/jjyyxx/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/jjyyxx/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/jjyyxx/subscriptions",
+ "organizations_url": "https://api.github.com/users/jjyyxx/orgs",
+ "repos_url": "https://api.github.com/users/jjyyxx/repos",
+ "events_url": "https://api.github.com/users/jjyyxx/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/jjyyxx/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "repo": {
+ "id": 290096040,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyOTAwOTYwNDA=",
+ "name": "koishi",
+ "full_name": "jjyyxx/koishi",
+ "private": false,
+ "owner": {
+ "login": "jjyyxx",
+ "id": 13808089,
+ "node_id": "MDQ6VXNlcjEzODA4MDg5",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13808089?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/jjyyxx",
+ "html_url": "https://github.com/jjyyxx",
+ "followers_url": "https://api.github.com/users/jjyyxx/followers",
+ "following_url": "https://api.github.com/users/jjyyxx/following{/other_user}",
+ "gists_url": "https://api.github.com/users/jjyyxx/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/jjyyxx/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/jjyyxx/subscriptions",
+ "organizations_url": "https://api.github.com/users/jjyyxx/orgs",
+ "repos_url": "https://api.github.com/users/jjyyxx/repos",
+ "events_url": "https://api.github.com/users/jjyyxx/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/jjyyxx/received_events",
+ "type": "User",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/jjyyxx/koishi",
+ "description": "QQ bot out of the box",
+ "fork": true,
+ "url": "https://api.github.com/repos/jjyyxx/koishi",
+ "forks_url": "https://api.github.com/repos/jjyyxx/koishi/forks",
+ "keys_url": "https://api.github.com/repos/jjyyxx/koishi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/jjyyxx/koishi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/jjyyxx/koishi/teams",
+ "hooks_url": "https://api.github.com/repos/jjyyxx/koishi/hooks",
+ "issue_events_url": "https://api.github.com/repos/jjyyxx/koishi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/jjyyxx/koishi/events",
+ "assignees_url": "https://api.github.com/repos/jjyyxx/koishi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/jjyyxx/koishi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/jjyyxx/koishi/tags",
+ "blobs_url": "https://api.github.com/repos/jjyyxx/koishi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/jjyyxx/koishi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/jjyyxx/koishi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/jjyyxx/koishi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/jjyyxx/koishi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/jjyyxx/koishi/languages",
+ "stargazers_url": "https://api.github.com/repos/jjyyxx/koishi/stargazers",
+ "contributors_url": "https://api.github.com/repos/jjyyxx/koishi/contributors",
+ "subscribers_url": "https://api.github.com/repos/jjyyxx/koishi/subscribers",
+ "subscription_url": "https://api.github.com/repos/jjyyxx/koishi/subscription",
+ "commits_url": "https://api.github.com/repos/jjyyxx/koishi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/jjyyxx/koishi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/jjyyxx/koishi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/jjyyxx/koishi/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/jjyyxx/koishi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/jjyyxx/koishi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/jjyyxx/koishi/merges",
+ "archive_url": "https://api.github.com/repos/jjyyxx/koishi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/jjyyxx/koishi/downloads",
+ "issues_url": "https://api.github.com/repos/jjyyxx/koishi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/jjyyxx/koishi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/jjyyxx/koishi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/jjyyxx/koishi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/jjyyxx/koishi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/jjyyxx/koishi/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/jjyyxx/koishi/deployments",
+ "created_at": "2020-08-25T02:51:14Z",
+ "updated_at": "2020-08-25T02:51:16Z",
+ "pushed_at": "2020-08-25T02:52:54Z",
+ "git_url": "git://github.com/jjyyxx/koishi.git",
+ "ssh_url": "git@github.com:jjyyxx/koishi.git",
+ "clone_url": "https://github.com/jjyyxx/koishi.git",
+ "svn_url": "https://github.com/jjyyxx/koishi",
+ "homepage": "https://koishi.js.org",
+ "size": 2438,
+ "stargazers_count": 0,
+ "watchers_count": 0,
+ "language": null,
+ "has_issues": false,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": false,
+ "has_pages": false,
+ "forks_count": 0,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 0,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 0,
+ "open_issues": 0,
+ "watchers": 0,
+ "default_branch": "master",
+ "allow_squash_merge": true,
+ "allow_merge_commit": true,
+ "allow_rebase_merge": true,
+ "delete_branch_on_merge": false
+ }
+ },
+ "base": {
+ "label": "koishijs:mapping",
+ "ref": "mapping",
+ "sha": "d951031c5cc53b9705ba20d23a528a8109e17332",
+ "user": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/koishijs",
+ "html_url": "https://github.com/koishijs",
+ "followers_url": "https://api.github.com/users/koishijs/followers",
+ "following_url": "https://api.github.com/users/koishijs/following{/other_user}",
+ "gists_url": "https://api.github.com/users/koishijs/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/koishijs/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/koishijs/subscriptions",
+ "organizations_url": "https://api.github.com/users/koishijs/orgs",
+ "repos_url": "https://api.github.com/users/koishijs/repos",
+ "events_url": "https://api.github.com/users/koishijs/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/koishijs/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "repo": {
+ "id": 225572038,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyMjU1NzIwMzg=",
+ "name": "koishi",
+ "full_name": "koishijs/koishi",
+ "private": false,
+ "owner": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/koishijs",
+ "html_url": "https://github.com/koishijs",
+ "followers_url": "https://api.github.com/users/koishijs/followers",
+ "following_url": "https://api.github.com/users/koishijs/following{/other_user}",
+ "gists_url": "https://api.github.com/users/koishijs/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/koishijs/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/koishijs/subscriptions",
+ "organizations_url": "https://api.github.com/users/koishijs/orgs",
+ "repos_url": "https://api.github.com/users/koishijs/repos",
+ "events_url": "https://api.github.com/users/koishijs/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/koishijs/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/koishijs/koishi",
+ "description": "QQ bot out of the box",
+ "fork": false,
+ "url": "https://api.github.com/repos/koishijs/koishi",
+ "forks_url": "https://api.github.com/repos/koishijs/koishi/forks",
+ "keys_url": "https://api.github.com/repos/koishijs/koishi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/koishijs/koishi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/koishijs/koishi/teams",
+ "hooks_url": "https://api.github.com/repos/koishijs/koishi/hooks",
+ "issue_events_url": "https://api.github.com/repos/koishijs/koishi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/koishijs/koishi/events",
+ "assignees_url": "https://api.github.com/repos/koishijs/koishi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/koishijs/koishi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/koishijs/koishi/tags",
+ "blobs_url": "https://api.github.com/repos/koishijs/koishi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/koishijs/koishi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/koishijs/koishi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/koishijs/koishi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/koishijs/koishi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/koishijs/koishi/languages",
+ "stargazers_url": "https://api.github.com/repos/koishijs/koishi/stargazers",
+ "contributors_url": "https://api.github.com/repos/koishijs/koishi/contributors",
+ "subscribers_url": "https://api.github.com/repos/koishijs/koishi/subscribers",
+ "subscription_url": "https://api.github.com/repos/koishijs/koishi/subscription",
+ "commits_url": "https://api.github.com/repos/koishijs/koishi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/koishijs/koishi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/koishijs/koishi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/koishijs/koishi/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/koishijs/koishi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/koishijs/koishi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/koishijs/koishi/merges",
+ "archive_url": "https://api.github.com/repos/koishijs/koishi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/koishijs/koishi/downloads",
+ "issues_url": "https://api.github.com/repos/koishijs/koishi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/koishijs/koishi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/koishijs/koishi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/koishijs/koishi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/koishijs/koishi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/koishijs/koishi/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/koishijs/koishi/deployments",
+ "created_at": "2019-12-03T08:47:29Z",
+ "updated_at": "2020-08-24T19:15:52Z",
+ "pushed_at": "2020-08-24T18:51:18Z",
+ "git_url": "git://github.com/koishijs/koishi.git",
+ "ssh_url": "git@github.com:koishijs/koishi.git",
+ "clone_url": "https://github.com/koishijs/koishi.git",
+ "svn_url": "https://github.com/koishijs/koishi",
+ "homepage": "https://koishi.js.org",
+ "size": 2438,
+ "stargazers_count": 186,
+ "watchers_count": 186,
+ "language": "TypeScript",
+ "has_issues": true,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": false,
+ "has_pages": false,
+ "forks_count": 12,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 3,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 12,
+ "open_issues": 3,
+ "watchers": 186,
+ "default_branch": "master",
+ "allow_squash_merge": true,
+ "allow_merge_commit": true,
+ "allow_rebase_merge": true,
+ "delete_branch_on_merge": false
+ }
+ },
+ "_links": {
+ "self": {
+ "href": "https://api.github.com/repos/koishijs/koishi/pulls/90"
+ },
+ "html": {
+ "href": "https://github.com/koishijs/koishi/pull/90"
+ },
+ "issue": {
+ "href": "https://api.github.com/repos/koishijs/koishi/issues/90"
+ },
+ "comments": {
+ "href": "https://api.github.com/repos/koishijs/koishi/issues/90/comments"
+ },
+ "review_comments": {
+ "href": "https://api.github.com/repos/koishijs/koishi/pulls/90/comments"
+ },
+ "review_comment": {
+ "href": "https://api.github.com/repos/koishijs/koishi/pulls/comments{/number}"
+ },
+ "commits": {
+ "href": "https://api.github.com/repos/koishijs/koishi/pulls/90/commits"
+ },
+ "statuses": {
+ "href": "https://api.github.com/repos/koishijs/koishi/statuses/b1ea76d2dfc43e4ba5852b52e1eeb03beeb36541"
+ }
+ },
+ "author_association": "NONE",
+ "active_lock_reason": null,
+ "merged": false,
+ "mergeable": null,
+ "rebaseable": null,
+ "mergeable_state": "unknown",
+ "merged_by": null,
+ "comments": 0,
+ "review_comments": 0,
+ "maintainer_can_modify": true,
+ "commits": 1,
+ "additions": 6,
+ "deletions": 1,
+ "changed_files": 3
+ },
+ "repository": {
+ "id": 225572038,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyMjU1NzIwMzg=",
+ "name": "koishi",
+ "full_name": "koishijs/koishi",
+ "private": false,
+ "owner": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/koishijs",
+ "html_url": "https://github.com/koishijs",
+ "followers_url": "https://api.github.com/users/koishijs/followers",
+ "following_url": "https://api.github.com/users/koishijs/following{/other_user}",
+ "gists_url": "https://api.github.com/users/koishijs/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/koishijs/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/koishijs/subscriptions",
+ "organizations_url": "https://api.github.com/users/koishijs/orgs",
+ "repos_url": "https://api.github.com/users/koishijs/repos",
+ "events_url": "https://api.github.com/users/koishijs/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/koishijs/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/koishijs/koishi",
+ "description": "QQ bot out of the box",
+ "fork": false,
+ "url": "https://api.github.com/repos/koishijs/koishi",
+ "forks_url": "https://api.github.com/repos/koishijs/koishi/forks",
+ "keys_url": "https://api.github.com/repos/koishijs/koishi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/koishijs/koishi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/koishijs/koishi/teams",
+ "hooks_url": "https://api.github.com/repos/koishijs/koishi/hooks",
+ "issue_events_url": "https://api.github.com/repos/koishijs/koishi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/koishijs/koishi/events",
+ "assignees_url": "https://api.github.com/repos/koishijs/koishi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/koishijs/koishi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/koishijs/koishi/tags",
+ "blobs_url": "https://api.github.com/repos/koishijs/koishi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/koishijs/koishi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/koishijs/koishi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/koishijs/koishi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/koishijs/koishi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/koishijs/koishi/languages",
+ "stargazers_url": "https://api.github.com/repos/koishijs/koishi/stargazers",
+ "contributors_url": "https://api.github.com/repos/koishijs/koishi/contributors",
+ "subscribers_url": "https://api.github.com/repos/koishijs/koishi/subscribers",
+ "subscription_url": "https://api.github.com/repos/koishijs/koishi/subscription",
+ "commits_url": "https://api.github.com/repos/koishijs/koishi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/koishijs/koishi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/koishijs/koishi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/koishijs/koishi/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/koishijs/koishi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/koishijs/koishi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/koishijs/koishi/merges",
+ "archive_url": "https://api.github.com/repos/koishijs/koishi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/koishijs/koishi/downloads",
+ "issues_url": "https://api.github.com/repos/koishijs/koishi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/koishijs/koishi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/koishijs/koishi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/koishijs/koishi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/koishijs/koishi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/koishijs/koishi/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/koishijs/koishi/deployments",
+ "created_at": "2019-12-03T08:47:29Z",
+ "updated_at": "2020-08-24T19:15:52Z",
+ "pushed_at": "2020-08-24T18:51:18Z",
+ "git_url": "git://github.com/koishijs/koishi.git",
+ "ssh_url": "git@github.com:koishijs/koishi.git",
+ "clone_url": "https://github.com/koishijs/koishi.git",
+ "svn_url": "https://github.com/koishijs/koishi",
+ "homepage": "https://koishi.js.org",
+ "size": 2438,
+ "stargazers_count": 186,
+ "watchers_count": 186,
+ "language": "TypeScript",
+ "has_issues": true,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": false,
+ "has_pages": false,
+ "forks_count": 12,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 3,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 12,
+ "open_issues": 3,
+ "watchers": 186,
+ "default_branch": "master"
+ },
+ "organization": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "url": "https://api.github.com/orgs/koishijs",
+ "repos_url": "https://api.github.com/orgs/koishijs/repos",
+ "events_url": "https://api.github.com/orgs/koishijs/events",
+ "hooks_url": "https://api.github.com/orgs/koishijs/hooks",
+ "issues_url": "https://api.github.com/orgs/koishijs/issues",
+ "members_url": "https://api.github.com/orgs/koishijs/members{/member}",
+ "public_members_url": "https://api.github.com/orgs/koishijs/public_members{/member}",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "description": ""
+ },
+ "sender": {
+ "login": "jjyyxx",
+ "id": 13808089,
+ "node_id": "MDQ6VXNlcjEzODA4MDg5",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13808089?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/jjyyxx",
+ "html_url": "https://github.com/jjyyxx",
+ "followers_url": "https://api.github.com/users/jjyyxx/followers",
+ "following_url": "https://api.github.com/users/jjyyxx/following{/other_user}",
+ "gists_url": "https://api.github.com/users/jjyyxx/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/jjyyxx/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/jjyyxx/subscriptions",
+ "organizations_url": "https://api.github.com/users/jjyyxx/orgs",
+ "repos_url": "https://api.github.com/users/jjyyxx/repos",
+ "events_url": "https://api.github.com/users/jjyyxx/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/jjyyxx/received_events",
+ "type": "User",
+ "site_admin": false
+ }
+}
\ No newline at end of file
diff --git a/packages/plugin-github/tests/__fixtures__/pull_request_review.submitted.1.json b/packages/plugin-github/tests/fixtures/pull_request_review.submitted.1.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/pull_request_review.submitted.1.json
rename to packages/plugin-github/tests/fixtures/pull_request_review.submitted.1.json
diff --git a/packages/plugin-github/tests/__fixtures__/pull_request_review.submitted.2.json b/packages/plugin-github/tests/fixtures/pull_request_review.submitted.2.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/pull_request_review.submitted.2.json
rename to packages/plugin-github/tests/fixtures/pull_request_review.submitted.2.json
diff --git a/packages/plugin-github/tests/__fixtures__/pull_request_review_comment.created.json b/packages/plugin-github/tests/fixtures/pull_request_review_comment.created.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/pull_request_review_comment.created.json
rename to packages/plugin-github/tests/fixtures/pull_request_review_comment.created.json
diff --git a/packages/plugin-github/tests/__fixtures__/push.commit.json b/packages/plugin-github/tests/fixtures/push.commit.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/push.commit.json
rename to packages/plugin-github/tests/fixtures/push.commit.json
diff --git a/packages/plugin-github/tests/__fixtures__/push.delete.json b/packages/plugin-github/tests/fixtures/push.delete.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/push.delete.json
rename to packages/plugin-github/tests/fixtures/push.delete.json
diff --git a/packages/plugin-github/tests/__fixtures__/push.tag.json b/packages/plugin-github/tests/fixtures/push.tag.json
similarity index 100%
rename from packages/plugin-github/tests/__fixtures__/push.tag.json
rename to packages/plugin-github/tests/fixtures/push.tag.json
diff --git a/packages/plugin-github/tests/fixtures/star.created.json b/packages/plugin-github/tests/fixtures/star.created.json
new file mode 100644
index 0000000000..e2a5ab582e
--- /dev/null
+++ b/packages/plugin-github/tests/fixtures/star.created.json
@@ -0,0 +1,138 @@
+{
+ "action": "created",
+ "starred_at": "2020-08-27T10:21:02Z",
+ "repository": {
+ "id": 225572038,
+ "node_id": "MDEwOlJlcG9zaXRvcnkyMjU1NzIwMzg=",
+ "name": "koishi",
+ "full_name": "koishijs/koishi",
+ "private": false,
+ "owner": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/koishijs",
+ "html_url": "https://github.com/koishijs",
+ "followers_url": "https://api.github.com/users/koishijs/followers",
+ "following_url": "https://api.github.com/users/koishijs/following{/other_user}",
+ "gists_url": "https://api.github.com/users/koishijs/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/koishijs/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/koishijs/subscriptions",
+ "organizations_url": "https://api.github.com/users/koishijs/orgs",
+ "repos_url": "https://api.github.com/users/koishijs/repos",
+ "events_url": "https://api.github.com/users/koishijs/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/koishijs/received_events",
+ "type": "Organization",
+ "site_admin": false
+ },
+ "html_url": "https://github.com/koishijs/koishi",
+ "description": "QQ bot out of the box",
+ "fork": false,
+ "url": "https://api.github.com/repos/koishijs/koishi",
+ "forks_url": "https://api.github.com/repos/koishijs/koishi/forks",
+ "keys_url": "https://api.github.com/repos/koishijs/koishi/keys{/key_id}",
+ "collaborators_url": "https://api.github.com/repos/koishijs/koishi/collaborators{/collaborator}",
+ "teams_url": "https://api.github.com/repos/koishijs/koishi/teams",
+ "hooks_url": "https://api.github.com/repos/koishijs/koishi/hooks",
+ "issue_events_url": "https://api.github.com/repos/koishijs/koishi/issues/events{/number}",
+ "events_url": "https://api.github.com/repos/koishijs/koishi/events",
+ "assignees_url": "https://api.github.com/repos/koishijs/koishi/assignees{/user}",
+ "branches_url": "https://api.github.com/repos/koishijs/koishi/branches{/branch}",
+ "tags_url": "https://api.github.com/repos/koishijs/koishi/tags",
+ "blobs_url": "https://api.github.com/repos/koishijs/koishi/git/blobs{/sha}",
+ "git_tags_url": "https://api.github.com/repos/koishijs/koishi/git/tags{/sha}",
+ "git_refs_url": "https://api.github.com/repos/koishijs/koishi/git/refs{/sha}",
+ "trees_url": "https://api.github.com/repos/koishijs/koishi/git/trees{/sha}",
+ "statuses_url": "https://api.github.com/repos/koishijs/koishi/statuses/{sha}",
+ "languages_url": "https://api.github.com/repos/koishijs/koishi/languages",
+ "stargazers_url": "https://api.github.com/repos/koishijs/koishi/stargazers",
+ "contributors_url": "https://api.github.com/repos/koishijs/koishi/contributors",
+ "subscribers_url": "https://api.github.com/repos/koishijs/koishi/subscribers",
+ "subscription_url": "https://api.github.com/repos/koishijs/koishi/subscription",
+ "commits_url": "https://api.github.com/repos/koishijs/koishi/commits{/sha}",
+ "git_commits_url": "https://api.github.com/repos/koishijs/koishi/git/commits{/sha}",
+ "comments_url": "https://api.github.com/repos/koishijs/koishi/comments{/number}",
+ "issue_comment_url": "https://api.github.com/repos/koishijs/koishi/issues/comments{/number}",
+ "contents_url": "https://api.github.com/repos/koishijs/koishi/contents/{+path}",
+ "compare_url": "https://api.github.com/repos/koishijs/koishi/compare/{base}...{head}",
+ "merges_url": "https://api.github.com/repos/koishijs/koishi/merges",
+ "archive_url": "https://api.github.com/repos/koishijs/koishi/{archive_format}{/ref}",
+ "downloads_url": "https://api.github.com/repos/koishijs/koishi/downloads",
+ "issues_url": "https://api.github.com/repos/koishijs/koishi/issues{/number}",
+ "pulls_url": "https://api.github.com/repos/koishijs/koishi/pulls{/number}",
+ "milestones_url": "https://api.github.com/repos/koishijs/koishi/milestones{/number}",
+ "notifications_url": "https://api.github.com/repos/koishijs/koishi/notifications{?since,all,participating}",
+ "labels_url": "https://api.github.com/repos/koishijs/koishi/labels{/name}",
+ "releases_url": "https://api.github.com/repos/koishijs/koishi/releases{/id}",
+ "deployments_url": "https://api.github.com/repos/koishijs/koishi/deployments",
+ "created_at": "2019-12-03T08:47:29Z",
+ "updated_at": "2020-08-27T10:21:02Z",
+ "pushed_at": "2020-08-27T08:52:42Z",
+ "git_url": "git://github.com/koishijs/koishi.git",
+ "ssh_url": "git@github.com:koishijs/koishi.git",
+ "clone_url": "https://github.com/koishijs/koishi.git",
+ "svn_url": "https://github.com/koishijs/koishi",
+ "homepage": "https://koishi.js.org",
+ "size": 2777,
+ "stargazers_count": 189,
+ "watchers_count": 189,
+ "language": "TypeScript",
+ "has_issues": true,
+ "has_projects": true,
+ "has_downloads": true,
+ "has_wiki": false,
+ "has_pages": false,
+ "forks_count": 13,
+ "mirror_url": null,
+ "archived": false,
+ "disabled": false,
+ "open_issues_count": 5,
+ "license": {
+ "key": "mit",
+ "name": "MIT License",
+ "spdx_id": "MIT",
+ "url": "https://api.github.com/licenses/mit",
+ "node_id": "MDc6TGljZW5zZTEz"
+ },
+ "forks": 13,
+ "open_issues": 5,
+ "watchers": 189,
+ "default_branch": "master"
+ },
+ "organization": {
+ "login": "koishijs",
+ "id": 58179220,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjU4MTc5MjIw",
+ "url": "https://api.github.com/orgs/koishijs",
+ "repos_url": "https://api.github.com/orgs/koishijs/repos",
+ "events_url": "https://api.github.com/orgs/koishijs/events",
+ "hooks_url": "https://api.github.com/orgs/koishijs/hooks",
+ "issues_url": "https://api.github.com/orgs/koishijs/issues",
+ "members_url": "https://api.github.com/orgs/koishijs/members{/member}",
+ "public_members_url": "https://api.github.com/orgs/koishijs/public_members{/member}",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/58179220?v=4",
+ "description": ""
+ },
+ "sender": {
+ "login": "275761919",
+ "id": 14012127,
+ "node_id": "MDQ6VXNlcjE0MDEyMTI3",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/14012127?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/275761919",
+ "html_url": "https://github.com/275761919",
+ "followers_url": "https://api.github.com/users/275761919/followers",
+ "following_url": "https://api.github.com/users/275761919/following{/other_user}",
+ "gists_url": "https://api.github.com/users/275761919/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/275761919/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/275761919/subscriptions",
+ "organizations_url": "https://api.github.com/users/275761919/orgs",
+ "repos_url": "https://api.github.com/users/275761919/repos",
+ "events_url": "https://api.github.com/users/275761919/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/275761919/received_events",
+ "type": "User",
+ "site_admin": false
+ }
+}
\ No newline at end of file
diff --git a/packages/plugin-github/tests/index.snap.js b/packages/plugin-github/tests/index.snap.js
new file mode 100644
index 0000000000..5f210bad61
--- /dev/null
+++ b/packages/plugin-github/tests/index.snap.js
@@ -0,0 +1,56 @@
+module.exports[`commit_comment.created`] = `
+[GitHub] Shigma commented on commit koishijs/koishi@bff469
+URL: https://github.com/koishijs/koishi/commit/bff469eabe14d42683a4f7c3ccb659daec5e1c00#commitcomment-36878220
+This will introduce a failure in test.`
+
+module.exports[`fork`] = `
+[GitHub] jjyyxx forked koishijs/koishi to jjyyxx/koishi (total 12 forks)`
+
+module.exports[`issue_comment.created.1`] = `
+[GitHub] simon300000 commented on issue koishijs/koishi#19
+URL: https://github.com/koishijs/koishi/issues/19#issuecomment-576277946
+Mich würde auch interessieren, was ist „CoolQ“?`
+
+module.exports[`issue_comment.created.2`] = `
+[GitHub] Kouchya commented on pull request koishijs/koishi#20
+URL: https://github.com/koishijs/koishi/pull/20#issuecomment-576291300
+C'est important!`
+
+module.exports[`issues.opened`] = `
+[GitHub] simon300000 opened an issue koishijs/koishi#19
+URL: https://github.com/koishijs/koishi/issues/19
+Title: Wie kann man um das Koishi zu installieren?
+Ich verstecke Englisch und Chinesisch nicht! Gab es Personen, die mir helfen kann?`
+
+module.exports[`pull_request.opened.1`] = `
+[GitHub] simon300000 opened a pull request koishijs/koishi#20 (koishijs:develop <- koishijs:experimental)
+URL: https://github.com/koishijs/koishi/pull/20
+Das ist wichtig!`
+
+module.exports[`pull_request.opened.2`] = `
+[GitHub] jjyyxx opened a pull request koishijs/koishi#90 (koishijs:mapping <- jjyyxx:mapping)
+URL: https://github.com/koishijs/koishi/pull/90
+According to \`tsconfig-paths\` documentation ...`
+
+module.exports[`pull_request_review.submitted.2`] = `
+[GitHub] Kouchya reviewed pull request koishijs/koishi#20
+URL: https://github.com/koishijs/koishi/pull/20#pullrequestreview-345349537
+LGTM`
+
+module.exports[`pull_request_review_comment.created`] = `
+[GitHub] Shigma commented on pull request review koishijs/koishi#20
+Path: packages/test-utils/src/mocks.ts
+URL: https://github.com/koishijs/koishi/pull/20#discussion_r368570320
+Naming is so hard......`
+
+module.exports[`push.commit`] = `
+[GitHub] Shigma pushed to koishijs/koishi:develop
+Compare: https://github.com/koishijs/koishi/compare/976c6e8f09a4...3ae7e7044d06
+[d7ff34] chore: adjust
+[3ae7e7] fix(core): create major context at demand`
+
+module.exports[`push.tag`] = `
+[GitHub] Shigma published tag koishijs/koishi@1.5.0`
+
+module.exports[`star.created`] = `
+[GitHub] 275761919 starred koishijs/koishi (total 189 stargazers)`
diff --git a/packages/plugin-github/tests/index.spec.ts b/packages/plugin-github/tests/index.spec.ts
index c1ed455eb4..27a376a161 100644
--- a/packages/plugin-github/tests/index.spec.ts
+++ b/packages/plugin-github/tests/index.spec.ts
@@ -1,27 +1,54 @@
-import { MockedApp } from 'koishi-test-utils'
-import { apply, webhooks } from '../src'
+import { App, BASE_SELF_ID, memory } from 'koishi-test-utils'
+import { Random } from 'koishi-utils'
+import { fn, spyOn } from 'jest-mock'
+import { expect } from 'chai'
import { readdirSync } from 'fs-extra'
import { resolve } from 'path'
+import * as github from 'koishi-plugin-github'
-const app = new MockedApp({
- githubWebhook: {
- secret: 'secret',
- },
+const secret = Random.uuid()
+
+const app = new App({ port: 10000 })
+
+app.plugin(memory)
+
+app.plugin(github, {
+ secret,
+ repos: { 'koishijs/koishi': [123] },
})
-app.plugin(apply, {
- 'koishijs/koishi': [123],
+// override listen
+const listen = spyOn(app.server, 'listen')
+listen.mockReturnValue(Promise.resolve())
+
+// spy on sendGroupMsg
+const sendGroupMsg = app.bots[0].sendGroupMsg = fn()
+
+before(async () => {
+ await app.start()
+ await app.database.getGroup(123, BASE_SELF_ID)
})
-const webhook = webhooks['/secret12140']
+const snapshot = require('./index.snap')
-readdirSync(resolve(__dirname, '__fixtures__')).forEach((file) => {
- file = file.slice(0, -5)
- const [name] = file.split('.', 1)
- const payload = require(`./__fixtures__/${file}`)
+function check(file: string) {
+ it(file, async () => {
+ sendGroupMsg.mockClear()
+ const payload = require(`./fixtures/${file}`)
+ const [name] = file.split('.', 1)
+ await app.githubWebhooks.receive({ id: Random.uuid(), name, payload })
+ if (snapshot[file]) {
+ expect(sendGroupMsg.mock.calls).to.have.length(1)
+ expect(sendGroupMsg.mock.calls[0][1]).to.equal(snapshot[file].trim())
+ } else {
+ expect(sendGroupMsg.mock.calls).to.have.length(0)
+ }
+ })
+}
- test(file, async () => {
- await webhook.receive({ id: 'id', name, payload })
- app.shouldMatchSnapshot(file)
+describe('koishi-plugin-github', () => {
+ const files = readdirSync(resolve(__dirname, 'fixtures'))
+ files.forEach(file => {
+ check(file.slice(0, -5))
})
})
diff --git a/packages/plugin-image-search/package.json b/packages/plugin-image-search/package.json
index d716f64cc5..f310d3fb98 100644
--- a/packages/plugin-image-search/package.json
+++ b/packages/plugin-image-search/package.json
@@ -37,12 +37,12 @@
"pixiv"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
"axios": "^0.20.0",
"cheerio": "^1.0.0-rc.3",
- "koishi-utils": "^3.1.2",
+ "koishi-utils": "^3.1.3",
"nhentai-api": "^3.0.2"
}
}
diff --git a/packages/plugin-mongo/package.json b/packages/plugin-mongo/package.json
index ca93eee932..aa986c1bc9 100644
--- a/packages/plugin-mongo/package.json
+++ b/packages/plugin-mongo/package.json
@@ -1,7 +1,7 @@
{
"name": "koishi-plugin-mongo",
"description": "MongoDB support for Koishi",
- "version": "1.0.1",
+ "version": "1.0.2",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
@@ -39,7 +39,7 @@
"@types/mongodb": "^3.5.26"
},
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
"mongodb": "^3.6.0"
diff --git a/packages/plugin-mongo/src/index.ts b/packages/plugin-mongo/src/index.ts
index e3aa4e5c10..6bb403afcb 100644
--- a/packages/plugin-mongo/src/index.ts
+++ b/packages/plugin-mongo/src/index.ts
@@ -112,8 +112,8 @@ extendDatabase(MongoDatabase, {
if (data.timers) {
$set.timers = {}
for (const key in data.timers) {
- if (key === '$date') $set.timer._date = data.timers.$date
- else $set.timer[key.replace(/\./gmi, '_')] = data.timers[key]
+ if (key === '$date') $set.timers._date = data.timers.$date
+ else $set.timers[key.replace(/\./gmi, '_')] = data.timers[key]
}
}
if (data.usage) {
diff --git a/packages/plugin-monitor/package.json b/packages/plugin-monitor/package.json
index 252e5ff96c..9f983ce346 100644
--- a/packages/plugin-monitor/package.json
+++ b/packages/plugin-monitor/package.json
@@ -21,9 +21,9 @@
},
"homepage": "https://github.com/koishijs/koishi#readme",
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-mysql/package.json b/packages/plugin-mysql/package.json
index bcd6603d1c..7fdf4d54fc 100644
--- a/packages/plugin-mysql/package.json
+++ b/packages/plugin-mysql/package.json
@@ -36,10 +36,10 @@
"@types/mysql": "^2.15.15"
},
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2",
+ "koishi-utils": "^3.1.3",
"mysql": "^2.18.1"
}
}
diff --git a/packages/plugin-puppeteer/package.json b/packages/plugin-puppeteer/package.json
index cb9822fbcd..0f25216ba1 100644
--- a/packages/plugin-puppeteer/package.json
+++ b/packages/plugin-puppeteer/package.json
@@ -39,12 +39,12 @@
"koishi-test-utils": "^4.0.0"
},
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
"chrome-finder": "^1.0.7",
"pngjs": "^5.0.0",
"puppeteer-core": "^5.2.1",
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-recorder/README.md b/packages/plugin-recorder/README.md
deleted file mode 100644
index 6d88da71be..0000000000
--- a/packages/plugin-recorder/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# [koishi-plugin-recorder](https://koishi.js.org/plugins/recorder.html)
-
-[![npm](https://img.shields.io/npm/v/koishi-plugin-recorder?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-recorder)
diff --git a/packages/plugin-recorder/package.json b/packages/plugin-recorder/package.json
deleted file mode 100644
index b5bcf79b8e..0000000000
--- a/packages/plugin-recorder/package.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "name": "koishi-plugin-recorder",
- "description": "Save Chat Records for Koishi",
- "version": "2.0.0-beta.7",
- "main": "dist/index.js",
- "typings": "dist/index.d.ts",
- "files": [
- "dist"
- ],
- "author": "Shigma <1700011071@pku.edu.cn>",
- "license": "MIT",
- "scripts": {
- "build": "tsc -b",
- "lint": "eslint src --ext .ts",
- "prepack": "tsc -b"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/koishijs/koishi.git"
- },
- "bugs": {
- "url": "https://github.com/koishijs/koishi/issues"
- },
- "homepage": "https://github.com/koishijs/koishi/packages/plugin-recorder#readme",
- "keywords": [
- "bot",
- "qqbot",
- "cqhttp",
- "coolq",
- "chatbot",
- "koishi",
- "plugin",
- "record",
- "recorder"
- ],
- "peerDependencies": {
- "koishi-core": "^2.0.2"
- },
- "devDependencies": {
- "del": "^5.1.0",
- "koishi-test-utils": "^4.0.0"
- },
- "dependencies": {
- "koishi-utils": "^3.1.2"
- }
-}
diff --git a/packages/plugin-recorder/src/index.ts b/packages/plugin-recorder/src/index.ts
deleted file mode 100644
index 5ad4a5ced5..0000000000
--- a/packages/plugin-recorder/src/index.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { WriteStream, createWriteStream, existsSync, mkdirSync } from 'fs'
-import { resolve, dirname } from 'path'
-import { Session, Context } from 'koishi-core'
-import { pick } from 'koishi-utils'
-
-declare module 'koishi-core/dist/context' {
- interface EventMap {
- 'before-record' (session: Session): any
- }
-}
-
-const streams: Record = {}
-
-export interface RecorderOptions {
- folder?: string
-}
-
-const cwd = process.cwd()
-
-export const name = 'recorder'
-
-export function apply(ctx: Context, options: RecorderOptions = {}) {
- async function handleMessage(session: Session) {
- if (session.subType === 'group' && session.$group.assignee !== session.selfId) return
- if (await ctx.serial('before-record', session)) return
- const output = JSON.stringify(pick(session, ['time', 'userId', 'message'])) + '\n'
- const path = resolve(cwd, options.folder || 'messages', `${session.groupId}.txt`)
- if (!streams[path]) {
- const folder = dirname(path)
- if (!existsSync(folder)) {
- mkdirSync(folder, { recursive: true })
- }
- streams[path] = createWriteStream(path, { flags: 'a' })
- }
- streams[path].write(output)
- }
-
- ctx.on('attach-group', (session: Session) => {
- handleMessage(session)
- })
-
- ctx.on('before-send', (session: Session) => {
- handleMessage(session)
- })
-}
diff --git a/packages/plugin-recorder/tests/__snapshots__/index.spec.ts.snap b/packages/plugin-recorder/tests/__snapshots__/index.spec.ts.snap
deleted file mode 100644
index 7b25290913..0000000000
--- a/packages/plugin-recorder/tests/__snapshots__/index.spec.ts.snap
+++ /dev/null
@@ -1,7 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`check content 1`] = `
-"{\\"$ctxType\\":\\"group\\",\\"$ctxId\\":321,\\"userId\\":123,\\"message\\":\\"foo\\"}
-{\\"$ctxType\\":\\"group\\",\\"$ctxId\\":321,\\"userId\\":789,\\"message\\":\\"baz\\"}
-"
-`;
diff --git a/packages/plugin-recorder/tests/index.spec.ts b/packages/plugin-recorder/tests/index.spec.ts
deleted file mode 100644
index 6081a09522..0000000000
--- a/packages/plugin-recorder/tests/index.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { MockedApp, BASE_SELF_ID } from 'koishi-test-utils'
-import { startAll, stopAll } from 'koishi-core'
-import { readFileSync } from 'fs-extra'
-import { resolve } from 'path'
-import { sleep } from 'koishi-utils'
-import * as recorder from '../src'
-import del from 'del'
-
-const app1 = new MockedApp()
-const app2 = new MockedApp({ selfId: BASE_SELF_ID + 1 })
-
-app1.plugin(recorder)
-app2.plugin(recorder)
-
-beforeAll(() => startAll())
-
-const outFolder = resolve(process.cwd(), 'messages')
-
-afterAll(() => del(outFolder))
-
-test('group message', async () => {
- const mock = jest.fn()
- app1.on('record-writing', mock)
- await app1.receiveMessage('group', 'foo', 123, 321)
- await app1.receiveMessage('group', 'bar', 456, 654)
- await app1.receiveMessage('group', 'baz', 789, 321)
- expect(mock).toBeCalledTimes(3)
-})
-
-test('private message', async () => {
- const mock = jest.fn()
- app1.on('record-writing', mock)
- await app1.receiveMessage('user', 'foo', 123)
- expect(mock).toBeCalledTimes(0)
-})
-
-test('check content', async () => {
- await stopAll()
- await sleep(100)
- expect(readFileSync(resolve(outFolder, '321.txt'), 'utf8')).toMatchSnapshot()
-})
diff --git a/packages/plugin-recorder/tsconfig.json b/packages/plugin-recorder/tsconfig.json
deleted file mode 100644
index a497f05e83..0000000000
--- a/packages/plugin-recorder/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extends": "../../tsconfig.base",
- "compilerOptions": {
- "outDir": "dist",
- "rootDir": "src",
- },
- "include": [
- "src",
- ],
-}
\ No newline at end of file
diff --git a/packages/plugin-rss/package.json b/packages/plugin-rss/package.json
index 204520bfc2..6c621bd174 100644
--- a/packages/plugin-rss/package.json
+++ b/packages/plugin-rss/package.json
@@ -36,13 +36,13 @@
"rss"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"devDependencies": {
"koishi-test-utils": "^4.0.0"
},
"dependencies": {
"rss-feed-emitter": "^3.2.2",
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-schedule/package.json b/packages/plugin-schedule/package.json
index e33b7e14ef..ef9add8ff4 100644
--- a/packages/plugin-schedule/package.json
+++ b/packages/plugin-schedule/package.json
@@ -34,14 +34,14 @@
"task"
],
"devDependencies": {
- "koishi-plugin-mongo": "^1.0.1",
+ "koishi-plugin-mongo": "^1.0.2",
"koishi-plugin-mysql": "^2.0.0",
"koishi-test-utils": "^4.0.0"
},
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-status/package.json b/packages/plugin-status/package.json
index 683a1d3e8e..189eaae487 100644
--- a/packages/plugin-status/package.json
+++ b/packages/plugin-status/package.json
@@ -32,16 +32,16 @@
"status"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"devDependencies": {
"@types/cross-spawn": "^6.0.2",
- "koishi-plugin-mongo": "^1.0.1",
+ "koishi-plugin-mongo": "^1.0.2",
"koishi-plugin-mysql": "^2.0.0",
"koishi-test-utils": "^4.0.0"
},
"dependencies": {
"cross-spawn": "^7.0.3",
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/packages/plugin-teach/package.json b/packages/plugin-teach/package.json
index ddac5a519c..7682312706 100644
--- a/packages/plugin-teach/package.json
+++ b/packages/plugin-teach/package.json
@@ -38,15 +38,15 @@
"conversation"
],
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"devDependencies": {
- "koishi-plugin-mongo": "^1.0.1",
+ "koishi-plugin-mongo": "^1.0.2",
"koishi-plugin-mysql": "^2.0.0",
"koishi-test-utils": "^4.0.0"
},
"dependencies": {
- "koishi-utils": "^3.1.2",
+ "koishi-utils": "^3.1.3",
"leven": "^3.1.0",
"regexpp": "^3.1.0"
}
diff --git a/packages/plugin-tools/package.json b/packages/plugin-tools/package.json
index 9b9f9b1a8b..931efdba23 100644
--- a/packages/plugin-tools/package.json
+++ b/packages/plugin-tools/package.json
@@ -25,13 +25,13 @@
"@types/qrcode": "^1.3.5"
},
"peerDependencies": {
- "koishi-core": "^2.0.2"
+ "koishi-core": "^2.1.0"
},
"dependencies": {
"axios": "^0.20.0",
"cheerio": "^1.0.0-rc.3",
"qrcode": "^1.4.4",
"xml-js": "^1.6.11",
- "koishi-utils": "^3.1.2"
+ "koishi-utils": "^3.1.3"
}
}
diff --git a/tsconfig.json b/tsconfig.json
index f32d0e2261..5bbe1c23f1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,7 +24,6 @@
{ "path": "./packages/plugin-github" },
{ "path": "./packages/plugin-image-search" },
{ "path": "./packages/plugin-monitor" },
- { "path": "./packages/plugin-recorder" },
{ "path": "./packages/plugin-rss" },
{ "path": "./packages/plugin-schedule" },
{ "path": "./packages/plugin-status" },