mirror of
https://github.com/xuexb/github-bot.git
synced 2025-12-08 17:36:07 +00:00
feat: update to es6 (#18)
* feat: use async/await * fix: fix github api bug * fix: fix auto release note bug * fix: auto release node commit message handle bug * fix: Notable changes list display bug * fix: Notable changes sub list display bug * feat: add eslint * feat: use husky to handle git hooks
This commit is contained in:
parent
d7f7b22c8e
commit
b447cbe173
@ -3,7 +3,7 @@ root = true
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
19
.eslintrc.js
Normal file
19
.eslintrc.js
Normal file
@ -0,0 +1,19 @@
|
||||
// http://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
'node': true
|
||||
},
|
||||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||
extends: 'standard',
|
||||
// add your custom rules here
|
||||
'rules': {
|
||||
// allow paren-less arrow functions
|
||||
'arrow-parens': 0,
|
||||
// allow async-await
|
||||
'generator-star-spacing': 0,
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
|
||||
}
|
||||
}
|
||||
24
package.json
24
package.json
@ -4,7 +4,10 @@
|
||||
"version": "0.0.1",
|
||||
"main": "src/app.js",
|
||||
"scripts": {
|
||||
"start": "NODE_ENV=development node src/app"
|
||||
"start": "NODE_ENV=development node src/app",
|
||||
"lint": "eslint src/**/* --quiet",
|
||||
"precommit": "npm run lint",
|
||||
"commitmsg": "validate-commit-msg"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -27,12 +30,9 @@
|
||||
"string-template": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
"node": ">= 7.8.0"
|
||||
},
|
||||
"config": {
|
||||
"ghooks": {
|
||||
"commit-msg": "validate-commit-msg"
|
||||
},
|
||||
"validate-commit-msg": {
|
||||
"types": [
|
||||
"feat",
|
||||
@ -53,10 +53,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"os": ["darwin", "linux"],
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux"
|
||||
],
|
||||
"devDependencies": {
|
||||
"ghooks": "^2.0.0",
|
||||
"eslint": "^4.9.0",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-friendly-formatter": "^3.0.0",
|
||||
"eslint-plugin-import": "^2.7.0",
|
||||
"eslint-plugin-node": "^5.2.0",
|
||||
"eslint-plugin-promise": "^3.6.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"git-pull-or-clone": "xuexb/git-pull-or-clone",
|
||||
"husky": "^0.14.3",
|
||||
"validate-commit-msg": "^2.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
76
src/app.js
76
src/app.js
@ -3,52 +3,50 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
require('dotenv').config()
|
||||
|
||||
const EventEmitter = require('events');
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const requireDir = require('require-dir');
|
||||
const {verifySignature} = require('./utils');
|
||||
const issueActions = requireDir('./modules/issues');
|
||||
const pullRequestActions = requireDir('./modules/pull_request');
|
||||
const releasesActions = requireDir('./modules/releases');
|
||||
const app = new Koa();
|
||||
const githubEvent = new EventEmitter();
|
||||
const EventEmitter = require('events')
|
||||
const Koa = require('koa')
|
||||
const bodyParser = require('koa-bodyparser')
|
||||
const requireDir = require('require-dir')
|
||||
const { verifySignature } = require('./utils')
|
||||
const issueActions = requireDir('./modules/issues')
|
||||
const pullRequestActions = requireDir('./modules/pull_request')
|
||||
const releasesActions = requireDir('./modules/releases')
|
||||
const app = new Koa()
|
||||
const githubEvent = new EventEmitter()
|
||||
|
||||
app.use(bodyParser());
|
||||
app.use(bodyParser())
|
||||
|
||||
app.use(ctx => {
|
||||
let eventName = ctx.request.headers['x-github-event'];
|
||||
if (eventName && verifySignature(ctx.request)) {
|
||||
const payload = ctx.request.body;
|
||||
const action = payload.action || payload.ref_type;
|
||||
let eventName = ctx.request.headers['x-github-event']
|
||||
if (eventName && verifySignature(ctx.request)) {
|
||||
const payload = ctx.request.body
|
||||
const action = payload.action || payload.ref_type
|
||||
|
||||
if (action) {
|
||||
eventName += `_${action}`;
|
||||
}
|
||||
|
||||
console.log(`receive event: ${eventName}`);
|
||||
|
||||
githubEvent.emit(eventName, {
|
||||
repo: payload.repository.name,
|
||||
payload
|
||||
});
|
||||
|
||||
ctx.body = 'Ok.';
|
||||
if (action) {
|
||||
eventName += `_${action}`
|
||||
}
|
||||
else {
|
||||
ctx.body = 'Go away.';
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`receive event: ${eventName}`)
|
||||
|
||||
const actions = Object.assign({}, issueActions, pullRequestActions, releasesActions);
|
||||
githubEvent.emit(eventName, {
|
||||
repo: payload.repository.name,
|
||||
payload
|
||||
})
|
||||
|
||||
ctx.body = 'Ok.'
|
||||
} else {
|
||||
ctx.body = 'Go away.'
|
||||
}
|
||||
})
|
||||
|
||||
const actions = Object.assign({}, issueActions, pullRequestActions, releasesActions)
|
||||
Object.keys(actions).forEach((key) => {
|
||||
actions[key](githubEvent.on.bind(githubEvent));
|
||||
console.log(`bind ${key} success!`);
|
||||
});
|
||||
actions[key](githubEvent.on.bind(githubEvent))
|
||||
console.log(`bind ${key} success!`)
|
||||
})
|
||||
|
||||
const port = 8000;
|
||||
app.listen(port);
|
||||
console.log(`Listening on http://0.0.0.0:${port}`);
|
||||
const port = 8000
|
||||
app.listen(port)
|
||||
console.log(`Listening on http://0.0.0.0:${port}`)
|
||||
|
||||
599
src/github.js
599
src/github.js
@ -3,293 +3,378 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const GitHub = require('github');
|
||||
const {toArray} = require('./utils');
|
||||
const GitHub = require('github')
|
||||
const { toArray } = require('./utils')
|
||||
|
||||
const github = new GitHub({
|
||||
debug: process.env.NODE_ENV === 'development'
|
||||
});
|
||||
debug: process.env.NODE_ENV === 'development'
|
||||
})
|
||||
|
||||
github.authenticate({
|
||||
type: 'token',
|
||||
token: process.env.GITHUB_TOKEN
|
||||
});
|
||||
type: 'token',
|
||||
token: process.env.GITHUB_TOKEN
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
|
||||
github,
|
||||
github,
|
||||
|
||||
/**
|
||||
* issue 是否包含某 label
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
issueHasLabel(payload, label) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.issue.number;
|
||||
/**
|
||||
* issue 是否包含某 label
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
async issueHasLabel (payload, label) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.issue.number
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
github.issues.getIssueLabels({
|
||||
owner,
|
||||
repo,
|
||||
number
|
||||
}).then(res => {
|
||||
if (res.data.map(v => v.name).indexOf(label) > -1) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
reject();
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
},
|
||||
try {
|
||||
const res = github.issues.getIssueLabels({
|
||||
owner,
|
||||
repo,
|
||||
number
|
||||
})
|
||||
|
||||
/**
|
||||
* PR 是否包含某 label
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
pullRequestHasLabel(payload, label) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.pull_request.number;
|
||||
if (res.data.map(v => v.name).indexOf(label) === -1) {
|
||||
Promise.reject(new Error('issue no label'))
|
||||
}
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
github.issues.getIssueLabels({
|
||||
owner,
|
||||
repo,
|
||||
number
|
||||
}).then(res => {
|
||||
if (res.data.map(v => v.name).indexOf(label) > -1) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
reject();
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* PR 是否包含某 label
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
async pullRequestHasLabel (payload, label) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.pull_request.number
|
||||
|
||||
/**
|
||||
* 评论 issue
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
commentIssue(payload, body) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.issue.number;
|
||||
try {
|
||||
const res = await github.issues.getIssueLabels({
|
||||
owner,
|
||||
repo,
|
||||
number
|
||||
})
|
||||
if (res.data.map(v => v.name).indexOf(label) === -1) {
|
||||
Promise.reject(new Error('pull request no label'))
|
||||
}
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
body
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 评论 issue
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
async commentIssue (payload, body) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.issue.number
|
||||
|
||||
/**
|
||||
* 评论 PR
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
commentPullRequest(payload, body) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.pull_request.number;
|
||||
try {
|
||||
const res = await github.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
body
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
body
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 评论 PR
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} body 评论内容
|
||||
*/
|
||||
async commentPullRequest (payload, body) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.pull_request.number
|
||||
|
||||
/**
|
||||
* 关闭 issue
|
||||
*
|
||||
* @param {Object} payload data
|
||||
*/
|
||||
closeIssue(payload) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.issue.number;
|
||||
try {
|
||||
const res = await github.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
body
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.edit({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
state: 'closed'
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 关闭 issue
|
||||
*
|
||||
* @param {Object} payload data
|
||||
*/
|
||||
async closeIssue (payload) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.issue.number
|
||||
|
||||
/**
|
||||
* 分派作者到 issues
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string | Array} assign 用户id
|
||||
*/
|
||||
addAssigneesToIssue(payload, assign) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.issue.number;
|
||||
try {
|
||||
const res = await github.issues.edit({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
state: 'closed'
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.edit({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
assignees: Array.isArray(assign) ? assign : [assign]
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 分派作者到 issues
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string | Array} assign 用户id
|
||||
*/
|
||||
async addAssigneesToIssue (payload, assign) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.issue.number
|
||||
|
||||
/**
|
||||
* 添加标签到 issue
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string | Array} labels 标签
|
||||
*/
|
||||
addLabelsToIssue(payload, labels) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.issue.number;
|
||||
try {
|
||||
const res = await github.issues.edit({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
assignees: Array.isArray(assign) ? assign : [assign]
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
labels: Array.isArray(labels) ? labels : [labels]
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 添加标签到 issue
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string | Array} labels 标签
|
||||
*/
|
||||
async addLabelsToIssue (payload, labels) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.issue.number
|
||||
|
||||
/**
|
||||
* 添加标签到 PR
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string | Array} labels 标签
|
||||
*/
|
||||
addLabelsToPullRequest(payload, labels) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.pull_request.number;
|
||||
try {
|
||||
const res = await github.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
labels: Array.isArray(labels) ? labels : [labels]
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
labels: Array.isArray(labels) ? labels : [labels]
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 添加标签到 PR
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string | Array} labels 标签
|
||||
*/
|
||||
async addLabelsToPullRequest (payload, labels) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.pull_request.number
|
||||
|
||||
/**
|
||||
* 删除 PR 标签
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} name 标签名
|
||||
*/
|
||||
removeLabelsToPullRequest(payload, name) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.pull_request.number;
|
||||
try {
|
||||
const res = await github.issues.addLabels({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
labels: Array.isArray(labels) ? labels : [labels]
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
name
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 删除 PR 标签
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} name 标签名
|
||||
*/
|
||||
async removeLabelsToPullRequest (payload, name) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.pull_request.number
|
||||
|
||||
/**
|
||||
* 删除 issue 标签
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} name 标签名
|
||||
*/
|
||||
removeLabelsToIssue(payload, name) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.issues.number;
|
||||
try {
|
||||
const res = await Fgithub.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
name
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
name
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 删除 issue 标签
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} name 标签名
|
||||
*/
|
||||
async removeLabelsToIssue (payload, name) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.issues.number
|
||||
try {
|
||||
const res = await github.issues.removeLabel({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
name
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建发布
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} options.tag_name tag名
|
||||
* @param {string} options.target_commitish tag hash
|
||||
* @param {string} options.name 标题
|
||||
* @param {string} options.body 内容
|
||||
* @param {boolean} options.draft 是否为草稿
|
||||
* @param {boolean} options.prerelease 是否预发布
|
||||
*/
|
||||
createRelease(payload, {tag_name, target_commitish, name, body, draft, prerelease}) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
/**
|
||||
* 创建发布
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} options.tag_name tag名
|
||||
* @param {string} options.target_commitish tag hash
|
||||
* @param {string} options.name 标题
|
||||
* @param {string} options.body 内容
|
||||
* @param {boolean} options.draft 是否为草稿
|
||||
* @param {boolean} options.prerelease 是否预发布
|
||||
*/
|
||||
async createRelease (payload, { tag_name, target_commitish, name, body, draft, prerelease }) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
try {
|
||||
const res = await github.repos.createRelease({
|
||||
owner,
|
||||
repo,
|
||||
tag_name,
|
||||
target_commitish,
|
||||
name,
|
||||
body,
|
||||
draft,
|
||||
prerelease
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
github.repos.createRelease({
|
||||
owner,
|
||||
repo,
|
||||
tag_name,
|
||||
target_commitish,
|
||||
name,
|
||||
body,
|
||||
draft,
|
||||
prerelease
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 根据tag获取发布信息
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} options.tag_name tag名
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
async getReleaseByTag (payload, { tag_name }) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
try {
|
||||
const res = await github.repos.getReleaseByTag({
|
||||
owner,
|
||||
repo,
|
||||
tag: tag_name
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据tag获取发布信息
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {string} options.tag_name tag名
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
getReleaseByTag(payload, {tag_name}) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
/**
|
||||
* 创建 review 请求
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {Array | string} options.reviewers reviewer
|
||||
* @param {Array | string} options.team_reviewers team_reviewers
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
async createReviewRequest (payload, { reviewers, team_reviewers }) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
const number = payload.pull_request.number
|
||||
try {
|
||||
const res = await github.pullRequests.createReviewRequest({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
reviewers: toArray(reviewers),
|
||||
team_reviewers: toArray(team_reviewers)
|
||||
})
|
||||
return res
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
return github.repos.getReleaseByTag({
|
||||
owner,
|
||||
repo,
|
||||
tag: tag_name
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 获得 repo 所有的tag
|
||||
*
|
||||
* @param {any} payload data
|
||||
* @returns
|
||||
*/
|
||||
async getTags (payload) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
|
||||
/**
|
||||
* 创建 review 请求
|
||||
*
|
||||
* @param {Object} payload data
|
||||
* @param {Array | string} options.reviewers reviewer
|
||||
* @param {Array | string} options.team_reviewers team_reviewers
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
createReviewRequest(payload, {reviewers, team_reviewers}) {
|
||||
const owner = payload.repository.owner.login;
|
||||
const repo = payload.repository.name;
|
||||
const number = payload.pull_request.number;
|
||||
try {
|
||||
const res = await github.repos.getTags({
|
||||
owner,
|
||||
repo
|
||||
})
|
||||
return res.data
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
},
|
||||
|
||||
return github.pullRequests.createReviewRequest({
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
reviewers: toArray(reviewers),
|
||||
team_reviewers: toArray(team_reviewers)
|
||||
});
|
||||
},
|
||||
};
|
||||
async compareCommits (payload, { base, head }) {
|
||||
const owner = payload.repository.owner.login
|
||||
const repo = payload.repository.name
|
||||
try {
|
||||
const res = await github.repos.compareCommits({
|
||||
owner,
|
||||
repo,
|
||||
base,
|
||||
head
|
||||
})
|
||||
return res.data
|
||||
} catch (e) {
|
||||
Promise.reject(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,21 +3,21 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const {getPkgConfig} = require('../../utils');
|
||||
const {addAssigneesToIssue} = require('../../github');
|
||||
const { getPkgConfig } = require('../../utils')
|
||||
const { addAssigneesToIssue } = require('../../github')
|
||||
|
||||
const config = getPkgConfig();
|
||||
const assignMap = config.labelToAuthor || {};
|
||||
const config = getPkgConfig()
|
||||
const assignMap = config.labelToAuthor || {}
|
||||
|
||||
function autoAssign(on) {
|
||||
on('issues_labeled', ({payload, repo}) => {
|
||||
if (assignMap[payload.label.name]) {
|
||||
addAssigneesToIssue(
|
||||
payload,
|
||||
assignMap[payload.label.name]
|
||||
);
|
||||
}
|
||||
});
|
||||
function autoAssign (on) {
|
||||
on('issues_labeled', ({ payload, repo }) => {
|
||||
if (assignMap[payload.label.name]) {
|
||||
addAssigneesToIssue(
|
||||
payload,
|
||||
assignMap[payload.label.name]
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = autoAssign;
|
||||
module.exports = autoAssign
|
||||
|
||||
@ -3,39 +3,39 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const format = require('string-template');
|
||||
const format = require('string-template')
|
||||
const {
|
||||
commentIssue,
|
||||
closeIssue,
|
||||
addLabelsToIssue
|
||||
} = require('../../github');
|
||||
commentIssue,
|
||||
closeIssue,
|
||||
addLabelsToIssue
|
||||
} = require('../../github')
|
||||
|
||||
const comment = [
|
||||
'hi @{user},非常感谢您的反馈,',
|
||||
'但是由于您没有使用 [规范的issue](https://github.com/xuexb/github-bot#issue-规则) 格式, 将直接被关闭, 谢谢!'
|
||||
].join('');
|
||||
'hi @{user},非常感谢您的反馈,',
|
||||
'但是由于您没有使用 [规范的issue](https://github.com/xuexb/github-bot#issue-规则) 格式, 将直接被关闭, 谢谢!'
|
||||
].join('')
|
||||
|
||||
const match = str => {
|
||||
return /node version:\s*[vV]?(\d\.?)+/.test(str);
|
||||
};
|
||||
|
||||
function replyInvalid(on) {
|
||||
on('issues_opened', ({payload}) => {
|
||||
const issue = payload.issue;
|
||||
const opener = issue.user.login;
|
||||
|
||||
if (!match(issue.body)) {
|
||||
commentIssue(
|
||||
payload,
|
||||
format(comment, {
|
||||
user: opener
|
||||
})
|
||||
);
|
||||
|
||||
closeIssue(payload);
|
||||
addLabelsToIssue(payload, 'invalid');
|
||||
}
|
||||
});
|
||||
return /node version:\s*[vV]?(\d\.?)+/.test(str)
|
||||
}
|
||||
|
||||
module.exports = replyInvalid;
|
||||
function replyInvalid (on) {
|
||||
on('issues_opened', ({ payload }) => {
|
||||
const issue = payload.issue
|
||||
const opener = issue.user.login
|
||||
|
||||
if (!match(issue.body)) {
|
||||
commentIssue(
|
||||
payload,
|
||||
format(comment, {
|
||||
user: opener
|
||||
})
|
||||
)
|
||||
|
||||
closeIssue(payload)
|
||||
addLabelsToIssue(payload, 'invalid')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = replyInvalid
|
||||
|
||||
@ -3,23 +3,22 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const format = require('string-template');
|
||||
const {commentIssue} = require('../../github');
|
||||
const format = require('string-template')
|
||||
const { commentIssue } = require('../../github')
|
||||
|
||||
const comment = 'hi @{user},请提供一个可预览的链接,如: <https://codepen.io/pen?template=KgPZrE&editors=0010>';
|
||||
const comment = 'hi @{user},请提供一个可预览的链接,如: <https://codepen.io/pen?template=KgPZrE&editors=0010>'
|
||||
|
||||
function replyNeedDemo(on) {
|
||||
on('issues_labeled', ({payload, repo}) => {
|
||||
if (payload.label.name === 'need demo') {
|
||||
commentIssue(
|
||||
payload,
|
||||
format(comment, {
|
||||
user: payload.issue.user.login
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
function replyNeedDemo (on) {
|
||||
on('issues_labeled', ({ payload, repo }) => {
|
||||
if (payload.label.name === 'need demo') {
|
||||
commentIssue(
|
||||
payload,
|
||||
format(comment, {
|
||||
user: payload.issue.user.login
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = replyNeedDemo;
|
||||
module.exports = replyNeedDemo
|
||||
|
||||
@ -3,21 +3,21 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const {getPkgConfig} = require('../../utils');
|
||||
const {createReviewRequest} = require('../../github');
|
||||
const { getPkgConfig } = require('../../utils')
|
||||
const { createReviewRequest } = require('../../github')
|
||||
|
||||
const config = getPkgConfig();
|
||||
const assignMap = config.labelToAuthor || {};
|
||||
const config = getPkgConfig()
|
||||
const assignMap = config.labelToAuthor || {}
|
||||
|
||||
module.exports = on => {
|
||||
on('pull_request_labeled', ({payload, repo}) => {
|
||||
if (assignMap[payload.label.name]) {
|
||||
createReviewRequest(
|
||||
payload,
|
||||
{
|
||||
reviewers: assignMap[payload.label.name]
|
||||
}
|
||||
);
|
||||
on('pull_request_labeled', ({ payload, repo }) => {
|
||||
if (assignMap[payload.label.name]) {
|
||||
createReviewRequest(
|
||||
payload,
|
||||
{
|
||||
reviewers: assignMap[payload.label.name]
|
||||
}
|
||||
});
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,59 +3,57 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const format = require('string-template');
|
||||
const {getPkgCommitPrefix} = require('../../utils');
|
||||
const format = require('string-template')
|
||||
const { getPkgCommitPrefix } = require('../../utils')
|
||||
const {
|
||||
commentPullRequest,
|
||||
addLabelsToPullRequest,
|
||||
removeLabelsToPullRequest,
|
||||
pullRequestHasLabel
|
||||
} = require('../../github');
|
||||
commentPullRequest,
|
||||
addLabelsToPullRequest,
|
||||
removeLabelsToPullRequest,
|
||||
pullRequestHasLabel
|
||||
} = require('../../github')
|
||||
|
||||
const actions = getPkgCommitPrefix();
|
||||
const actions = getPkgCommitPrefix()
|
||||
const match = title => {
|
||||
return actions.some(action => title.indexOf(`${action}:`) === 0);
|
||||
};
|
||||
return actions.some(action => title.indexOf(`${action}:`) === 0)
|
||||
}
|
||||
|
||||
const commentSuccess = [
|
||||
'hi @{user},非常感谢您及时修正标题格式,祝您玩的开心!'
|
||||
].join('');
|
||||
'hi @{user},非常感谢您及时修正标题格式,祝您玩的开心!'
|
||||
].join('')
|
||||
|
||||
const commentError = [
|
||||
'hi @{user},非常感谢您的 PR ,',
|
||||
'但是您没有使用 [PR 标题规则](https://github.com/xuexb/github-bot#commit-log-和-pr-标题规则) 格式,',
|
||||
'请及时修改, 谢谢!'
|
||||
].join('');
|
||||
'hi @{user},非常感谢您的 PR ,',
|
||||
'但是您没有使用 [PR 标题规则](https://github.com/xuexb/github-bot#commit-log-和-pr-标题规则) 格式,',
|
||||
'请及时修改, 谢谢!'
|
||||
].join('')
|
||||
|
||||
module.exports = on => {
|
||||
if (actions.length) {
|
||||
on('pull_request_opened', ({payload, repo}) => {
|
||||
if (!match(payload.pull_request.title)) {
|
||||
commentPullRequest(
|
||||
payload,
|
||||
format(commentError, {
|
||||
user: payload.pull_request.user.login
|
||||
})
|
||||
);
|
||||
if (actions.length) {
|
||||
on('pull_request_opened', ({ payload, repo }) => {
|
||||
if (!match(payload.pull_request.title)) {
|
||||
commentPullRequest(
|
||||
payload,
|
||||
format(commentError, {
|
||||
user: payload.pull_request.user.login
|
||||
})
|
||||
)
|
||||
|
||||
addLabelsToPullRequest(payload, 'invalid');
|
||||
}
|
||||
});
|
||||
addLabelsToPullRequest(payload, 'invalid')
|
||||
}
|
||||
})
|
||||
|
||||
on('pull_request_edited', ({payload, repo}) => {
|
||||
if (match(payload.pull_request.title)) {
|
||||
pullRequestHasLabel(payload, 'invalid').then(() => {
|
||||
commentPullRequest(
|
||||
payload,
|
||||
format(commentSuccess, {
|
||||
user: payload.pull_request.user.login
|
||||
})
|
||||
);
|
||||
on('pull_request_edited', async ({ payload, repo }) => {
|
||||
if (match(payload.pull_request.title)) {
|
||||
await pullRequestHasLabel(payload, 'invalid')
|
||||
commentPullRequest(
|
||||
payload,
|
||||
format(commentSuccess, {
|
||||
user: payload.pull_request.user.login
|
||||
})
|
||||
)
|
||||
|
||||
removeLabelsToPullRequest(payload, 'invalid');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
removeLabelsToPullRequest(payload, 'invalid')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,31 +4,31 @@
|
||||
*/
|
||||
|
||||
const {
|
||||
addLabelsToPullRequest,
|
||||
pullRequestHasLabel
|
||||
} = require('../../github');
|
||||
addLabelsToPullRequest,
|
||||
pullRequestHasLabel
|
||||
} = require('../../github')
|
||||
|
||||
const getAction = title => {
|
||||
return (title.match(/^(\w+?):/) || [])[1];
|
||||
};
|
||||
return (title.match(/^(\w+?):/) || [])[1]
|
||||
}
|
||||
|
||||
const ACTION_TO_LABEL_MAP = {
|
||||
feat: 'enhancement',
|
||||
fix: 'bug',
|
||||
docs: 'document'
|
||||
};
|
||||
feat: 'enhancement',
|
||||
fix: 'bug',
|
||||
docs: 'document'
|
||||
}
|
||||
|
||||
const handle = ({payload, repo}) => {
|
||||
const action = getAction(payload.pull_request.title);
|
||||
const handle = ({ payload, repo }) => {
|
||||
const action = getAction(payload.pull_request.title)
|
||||
|
||||
if (action && ACTION_TO_LABEL_MAP[action]) {
|
||||
pullRequestHasLabel(payload, ACTION_TO_LABEL_MAP[action]).catch(() => {
|
||||
addLabelsToPullRequest(payload, ACTION_TO_LABEL_MAP[action]);
|
||||
});
|
||||
}
|
||||
};
|
||||
if (action && ACTION_TO_LABEL_MAP[action]) {
|
||||
pullRequestHasLabel(payload, ACTION_TO_LABEL_MAP[action]).catch(() => {
|
||||
addLabelsToPullRequest(payload, ACTION_TO_LABEL_MAP[action])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = on => {
|
||||
on('pull_request_edited', handle);
|
||||
on('pull_request_opened', handle);
|
||||
};
|
||||
on('pull_request_edited', handle)
|
||||
on('pull_request_opened', handle)
|
||||
}
|
||||
|
||||
@ -3,79 +3,92 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const {getReleaseByTag, createRelease} = require('../../github');
|
||||
const {updateRepo, getTags, getFirstCommitHash, getCommitLog} = require('../../utils');
|
||||
const { getTags, compareCommits, getReleaseByTag, createRelease } = require('../../github')
|
||||
|
||||
const RELEASE_CHANGE_MAP = {
|
||||
document: 'docs',
|
||||
feature: 'feat',
|
||||
bugfix: 'fix',
|
||||
close: 'close'
|
||||
};
|
||||
document: 'docs',
|
||||
feature: 'feat',
|
||||
bugfix: 'fix',
|
||||
close: 'close'
|
||||
}
|
||||
|
||||
module.exports = on => {
|
||||
on('create_tag', ({payload, repo}) => {
|
||||
getReleaseByTag(payload, {
|
||||
tag_name: payload.ref
|
||||
}).then(() => {}, () => {
|
||||
updateRepo({
|
||||
url: payload.repository.clone_url,
|
||||
repo
|
||||
}).then(repoDir => {
|
||||
const tags = getTags({
|
||||
dir: repoDir
|
||||
});
|
||||
const after = tags[0];
|
||||
const before = tags.length > 1 ? tags[1] : getFirstCommitHash({
|
||||
dir: repoDir
|
||||
});
|
||||
const log = getCommitLog({
|
||||
dir: repoDir,
|
||||
before,
|
||||
after
|
||||
});
|
||||
on('create_tag', async ({ payload, repo }) => {
|
||||
const tag = await getReleaseByTag(payload, {
|
||||
tag_name: payload.ref
|
||||
})
|
||||
// 如果该 tag 存在则直接返回
|
||||
if (tag !== false) {
|
||||
return
|
||||
}
|
||||
|
||||
const hash = getCommitLog({
|
||||
dir: repoDir,
|
||||
before,
|
||||
after,
|
||||
html_url: payload.repository.html_url,
|
||||
hash: true
|
||||
});
|
||||
// 创建 release note
|
||||
try {
|
||||
const tags = await getTags(payload)
|
||||
const head = tags[0].name
|
||||
const base = tags.length > 1 ? tags[1].name : tags[0].name
|
||||
|
||||
const changes = Object.keys(RELEASE_CHANGE_MAP).map(title => {
|
||||
return {
|
||||
title,
|
||||
data: log.filter(log => log.indexOf(`- ${RELEASE_CHANGE_MAP[title]}:`) === 0)
|
||||
}
|
||||
}).filter(v => v.data.length);
|
||||
const commitsLog = await compareCommits(payload, {
|
||||
base,
|
||||
head
|
||||
})
|
||||
|
||||
let body = [];
|
||||
const commits = commitsLog.commits
|
||||
const changes = Object.keys(RELEASE_CHANGE_MAP).map(title => {
|
||||
let data = []
|
||||
commits.map((commit) => {
|
||||
if (commit.commit.message.indexOf(`${RELEASE_CHANGE_MAP[title]}:`) === 0) {
|
||||
let message = commit.commit.message
|
||||
// 处理 squash merge 的 commit message
|
||||
// 后期看看有没有更好的解决办法?
|
||||
if (message.indexOf('\n') !== -1) {
|
||||
message = message.substr(0, message.indexOf('\n'))
|
||||
}
|
||||
data.push(`- ${message}, by @${commit.commit.author.name} <<${commit.commit.author.email}>>`)
|
||||
}
|
||||
})
|
||||
return {
|
||||
title,
|
||||
data
|
||||
}
|
||||
}).filter(v => v.data.length)
|
||||
|
||||
if (changes.length) {
|
||||
body.push('## Notable changes\n');
|
||||
changes.forEach(v => {
|
||||
body.push([
|
||||
`- ${v.title}`
|
||||
]);
|
||||
const hashChanges = commits.map((commit) => {
|
||||
let message = commit.commit.message
|
||||
// 处理 squash merge 的 commit message
|
||||
if (message.indexOf('\n') !== -1) {
|
||||
message = message.substr(0, message.indexOf('\n'))
|
||||
}
|
||||
return `- [${commit.sha.substr(0, 7)}](${commit.html_url}) - ${message}, by @${commit.commit.author.name} <<${commit.commit.author.email}>>`
|
||||
})
|
||||
|
||||
v.data.forEach(line => body.push(' ' + line));
|
||||
});
|
||||
}
|
||||
let body = []
|
||||
|
||||
if (hash.length) {
|
||||
body.push('\n## Commits\n');
|
||||
body = body.concat(hash);
|
||||
}
|
||||
if (changes.length) {
|
||||
body.push('## Notable changes\n')
|
||||
changes.forEach(v => {
|
||||
body.push([
|
||||
`- ${v.title}`
|
||||
])
|
||||
|
||||
if (body.length) {
|
||||
createRelease(payload, {
|
||||
tag_name: payload.ref,
|
||||
name: `${payload.ref} @${payload.repository.owner.login}`,
|
||||
body: body.join('\n')
|
||||
});
|
||||
}
|
||||
}).catch(err => console.error(err));
|
||||
});
|
||||
});
|
||||
v.data.forEach(line => body.push(' ' + line))
|
||||
})
|
||||
}
|
||||
|
||||
if (hashChanges.length) {
|
||||
body.push('\n## Commits\n')
|
||||
body = body.concat(hashChanges)
|
||||
}
|
||||
|
||||
if (body.length) {
|
||||
createRelease(payload, {
|
||||
tag_name: payload.ref,
|
||||
name: `${payload.ref} @${payload.repository.owner.login}`,
|
||||
body: body.join('\n')
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
315
src/utils.js
315
src/utils.js
@ -3,168 +3,167 @@
|
||||
* @author xuexb <fe.xiaowu@gmail.com>
|
||||
*/
|
||||
|
||||
const format = require('string-template');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const {fixedTimeComparison} = require('cryptiles');
|
||||
const {execSync, exec} = require('child_process');
|
||||
const gitPullOrClone = require('git-pull-or-clone');
|
||||
const format = require('string-template')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const crypto = require('crypto')
|
||||
const { fixedTimeComparison } = require('cryptiles')
|
||||
const { execSync } = require('child_process')
|
||||
const gitPullOrClone = require('git-pull-or-clone')
|
||||
|
||||
const utils = {
|
||||
|
||||
/**
|
||||
* 验证请求
|
||||
*
|
||||
* @param {Object} request req
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
verifySignature(request) {
|
||||
let signature = crypto.createHmac('sha1', process.env.GITHUB_SECRET_TOKEN)
|
||||
.update(request.rawBody)
|
||||
.digest('hex');
|
||||
signature = `sha1=${signature}`;
|
||||
return fixedTimeComparison(signature, request.headers['x-hub-signature']);
|
||||
},
|
||||
/**
|
||||
* 验证请求
|
||||
*
|
||||
* @param {Object} request req
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
verifySignature (request) {
|
||||
let signature = crypto.createHmac('sha1', process.env.GITHUB_SECRET_TOKEN)
|
||||
.update(request.rawBody)
|
||||
.digest('hex')
|
||||
signature = `sha1=${signature}`
|
||||
return fixedTimeComparison(signature, request.headers['x-hub-signature'])
|
||||
},
|
||||
|
||||
/**
|
||||
* 目录是否存在
|
||||
*
|
||||
* @param {string} file 路径
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isDirectory(file) {
|
||||
try {
|
||||
return fs.statSync(file).isDirectory();
|
||||
}
|
||||
catch (e) {
|
||||
if (e.code !== 'ENOENT') {
|
||||
throw e;
|
||||
}
|
||||
/**
|
||||
* 目录是否存在
|
||||
*
|
||||
* @param {string} file 路径
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
isDirectory (file) {
|
||||
try {
|
||||
return fs.statSync(file).isDirectory()
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') {
|
||||
throw e
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取本地 git 目录的第一个提交,主要处理当第一次给项目打标签时不能用2个标签去 ..
|
||||
*
|
||||
* @param {string} options.dir git 目录
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getFirstCommitHash({dir}) {
|
||||
return execSync(`cd ${dir} && git log --oneline --pretty=format:"%h"`).toString()
|
||||
.split(/\n+/).slice(-1)[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取本地 git 目录的日志
|
||||
*
|
||||
* @param {Object} options 配置数据
|
||||
* @param {string} options.dir git 目录
|
||||
* @param {string} options.before 开始版本号
|
||||
* @param {string} options.after 结束版本号
|
||||
* @param {string} options.html_url 预览的html地址, 用来拼 hash commit
|
||||
* @param {boolean} [options.hash=false] 是否携带 commit hash log
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getCommitLog(options) {
|
||||
const shell = [
|
||||
'cd {dir}',
|
||||
options.hash
|
||||
? 'git log {before}..{after} --no-merges --pretty=format:"- [%h]({html_url}/commit/%H) - %s, by @%aN <<%ae>>"'
|
||||
: 'git log {before}..{after} --no-merges --pretty=format:"- %s, by @%aN <<%ae>>"'
|
||||
].join(' && ');
|
||||
|
||||
return execSync(format(shell, options)).toString().split(/\n+/);
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新 github 项目
|
||||
*
|
||||
* @param {string} options.repo 项目名
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
updateRepo({url, repo}) {
|
||||
const repoDir = path.resolve(__dirname, '../github/', repo);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
gitPullOrClone(url, repoDir, err => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
resolve(repoDir);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取本地 git 目录的 tag 列表
|
||||
*
|
||||
* @param {Object} options 配置
|
||||
* @param {string} options.dir git 目录
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getTags(options) {
|
||||
const shell = [
|
||||
'cd {dir}',
|
||||
'git describe --tags `git rev-list --tags --abbrev=0` --abbrev=0 | uniq'
|
||||
].join(' && ');
|
||||
|
||||
return execSync(format(shell, options)).toString().split(/\n+/).filter(tag => !!tag);
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 package.json 里的 config.github-bot
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
getPkgConfig() {
|
||||
const pkg = require('../package.json');
|
||||
const config = Object.assign({
|
||||
'github-bot': {}
|
||||
}, pkg.config);
|
||||
|
||||
return config['github-bot'];
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 commit log 前缀白名单
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getPkgCommitPrefix() {
|
||||
const pkg = require('../package.json');
|
||||
const config = Object.assign({
|
||||
'validate-commit-msg': {
|
||||
'types': []
|
||||
}
|
||||
}, pkg.config);
|
||||
|
||||
return config['validate-commit-msg'].types;
|
||||
},
|
||||
|
||||
/**
|
||||
* 转化成 Array
|
||||
*
|
||||
* @param {string | Array} str 目标值
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
toArray(str) {
|
||||
if (str) {
|
||||
return Array.isArray(str) ? str : [str];
|
||||
}
|
||||
|
||||
return str;
|
||||
return false
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
module.exports = utils;
|
||||
/**
|
||||
* 获取本地 git 目录的第一个提交,主要处理当第一次给项目打标签时不能用2个标签去 ..
|
||||
*
|
||||
* @param {string} options.dir git 目录
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
getFirstCommitHash ({ dir }) {
|
||||
return execSync(`cd ${dir} && git log --oneline --pretty=format:"%h"`).toString()
|
||||
.split(/\n+/).slice(-1)[0]
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取本地 git 目录的日志
|
||||
*
|
||||
* @param {Object} options 配置数据
|
||||
* @param {string} options.dir git 目录
|
||||
* @param {string} options.before 开始版本号
|
||||
* @param {string} options.after 结束版本号
|
||||
* @param {string} options.html_url 预览的html地址, 用来拼 hash commit
|
||||
* @param {boolean} [options.hash=false] 是否携带 commit hash log
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getCommitLog (options) {
|
||||
const shell = [
|
||||
'cd {dir}',
|
||||
options.hash
|
||||
? 'git log {before}..{after} --no-merges --pretty=format:"- [%h]({html_url}/commit/%H) - %s, by @%aN <<%ae>>"'
|
||||
: 'git log {before}..{after} --no-merges --pretty=format:"- %s, by @%aN <<%ae>>"'
|
||||
].join(' && ')
|
||||
|
||||
return execSync(format(shell, options)).toString().split(/\n+/)
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新 github 项目
|
||||
*
|
||||
* @param {string} options.repo 项目名
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
updateRepo ({ url, repo }) {
|
||||
const repoDir = path.resolve(__dirname, '../github/', repo)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
gitPullOrClone(url, repoDir, err => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
resolve(repoDir)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取本地 git 目录的 tag 列表
|
||||
*
|
||||
* @param {Object} options 配置
|
||||
* @param {string} options.dir git 目录
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getTags (options) {
|
||||
const shell = [
|
||||
'cd {dir}',
|
||||
'git describe --tags `git rev-list --tags --abbrev=0` --abbrev=0 | uniq'
|
||||
].join(' && ')
|
||||
|
||||
return execSync(format(shell, options)).toString().split(/\n+/).filter(tag => !!tag)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 package.json 里的 config.github-bot
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
getPkgConfig () {
|
||||
const pkg = require('../package.json')
|
||||
const config = Object.assign({
|
||||
'github-bot': {}
|
||||
}, pkg.config)
|
||||
|
||||
return config['github-bot']
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 commit log 前缀白名单
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
getPkgCommitPrefix () {
|
||||
const pkg = require('../package.json')
|
||||
const config = Object.assign({
|
||||
'validate-commit-msg': {
|
||||
'types': []
|
||||
}
|
||||
}, pkg.config)
|
||||
|
||||
return config['validate-commit-msg'].types
|
||||
},
|
||||
|
||||
/**
|
||||
* 转化成 Array
|
||||
*
|
||||
* @param {string | Array} str 目标值
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
toArray (str) {
|
||||
if (str) {
|
||||
return Array.isArray(str) ? str : [str]
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = utils
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user