From 5829b8b54a6a99e6c1f9f605befc39dbc4ee0e3b Mon Sep 17 00:00:00 2001 From: xuexb Date: Sun, 22 Oct 2017 22:17:36 +0800 Subject: [PATCH 1/5] feat: unified api --- src/github.js | 118 +++++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/src/github.js b/src/github.js index f79275f..0f32b2d 100755 --- a/src/github.js +++ b/src/github.js @@ -16,14 +16,12 @@ github.authenticate({ }) module.exports = { - - github, - /** * issue 是否包含某 label * * @param {Object} payload data * @param {string} body 评论内容 + * @return {boolean} */ async issueHasLabel (payload, label) { const owner = payload.repository.owner.login @@ -31,17 +29,14 @@ module.exports = { const number = payload.issue.number try { - const res = github.issues.getIssueLabels({ + const res = await github.issues.getIssueLabels({ owner, repo, number }) - - if (res.data.map(v => v.name).indexOf(label) === -1) { - Promise.reject(new Error('issue no label')) - } + return res.data.map(v => v.name).indexOf(label) > -1 } catch (e) { - Promise.reject(e) + return false } }, @@ -50,6 +45,7 @@ module.exports = { * * @param {Object} payload data * @param {string} body 评论内容 + * @return {boolean} */ async pullRequestHasLabel (payload, label) { const owner = payload.repository.owner.login @@ -62,11 +58,9 @@ module.exports = { repo, number }) - if (res.data.map(v => v.name).indexOf(label) === -1) { - Promise.reject(new Error('pull request no label')) - } + return res.data.map(v => v.name).indexOf(label) > -1 } catch (e) { - Promise.reject(e) + return false } }, @@ -75,6 +69,7 @@ module.exports = { * * @param {Object} payload data * @param {string} body 评论内容 + * @return {boolean} 是否成功 */ async commentIssue (payload, body) { const owner = payload.repository.owner.login @@ -82,15 +77,15 @@ module.exports = { const number = payload.issue.number try { - const res = await github.issues.createComment({ + await github.issues.createComment({ owner, repo, number, body }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -99,6 +94,7 @@ module.exports = { * * @param {Object} payload data * @param {string} body 评论内容 + * @return {boolean} 是否成功 */ async commentPullRequest (payload, body) { const owner = payload.repository.owner.login @@ -106,15 +102,15 @@ module.exports = { const number = payload.pull_request.number try { - const res = await github.issues.createComment({ + await github.issues.createComment({ owner, repo, number, body }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -122,6 +118,7 @@ module.exports = { * 关闭 issue * * @param {Object} payload data + * @return {boolean} 是否成功 */ async closeIssue (payload) { const owner = payload.repository.owner.login @@ -129,15 +126,15 @@ module.exports = { const number = payload.issue.number try { - const res = await github.issues.edit({ + await github.issues.edit({ owner, repo, number, state: 'closed' }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -146,6 +143,7 @@ module.exports = { * * @param {Object} payload data * @param {string | Array} assign 用户id + * @return {boolean} 是否成功 */ async addAssigneesToIssue (payload, assign) { const owner = payload.repository.owner.login @@ -153,15 +151,15 @@ module.exports = { const number = payload.issue.number try { - const res = await github.issues.edit({ + await github.issues.edit({ owner, repo, number, - assignees: Array.isArray(assign) ? assign : [assign] + assignees: toArray(assign) }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -170,6 +168,7 @@ module.exports = { * * @param {Object} payload data * @param {string | Array} labels 标签 + * @return {boolean} 是否成功 */ async addLabelsToIssue (payload, labels) { const owner = payload.repository.owner.login @@ -177,15 +176,15 @@ module.exports = { const number = payload.issue.number try { - const res = await github.issues.addLabels({ + await github.issues.addLabels({ owner, repo, number, - labels: Array.isArray(labels) ? labels : [labels] + labels: toArray(labels) }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -194,6 +193,7 @@ module.exports = { * * @param {Object} payload data * @param {string | Array} labels 标签 + * @return {boolean} 是否成功 */ async addLabelsToPullRequest (payload, labels) { const owner = payload.repository.owner.login @@ -201,15 +201,15 @@ module.exports = { const number = payload.pull_request.number try { - const res = await github.issues.addLabels({ + await github.issues.addLabels({ owner, repo, number, - labels: Array.isArray(labels) ? labels : [labels] + labels: toArray(labels) }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -218,6 +218,7 @@ module.exports = { * * @param {Object} payload data * @param {string} name 标签名 + * @return {boolean} 是否成功 */ async removeLabelsToPullRequest (payload, name) { const owner = payload.repository.owner.login @@ -225,15 +226,15 @@ module.exports = { const number = payload.pull_request.number try { - const res = await github.issues.removeLabel({ + await github.issues.removeLabel({ owner, repo, number, name }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -242,21 +243,22 @@ module.exports = { * * @param {Object} payload data * @param {string} name 标签名 + * @return {boolean} 是否成功 */ 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({ + await github.issues.removeLabel({ owner, repo, number, name }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -270,12 +272,13 @@ module.exports = { * @param {string} options.body 内容 * @param {boolean} options.draft 是否为草稿 * @param {boolean} options.prerelease 是否预发布 + * @return {boolean} 是否成功 */ 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({ + await github.repos.createRelease({ owner, repo, tag_name, @@ -285,9 +288,9 @@ module.exports = { draft, prerelease }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -297,7 +300,7 @@ module.exports = { * @param {Object} payload data * @param {string} options.tag_name tag名 * - * @return {Promise} + * @return {Object | null} */ async getReleaseByTag (payload, { tag_name }) { const owner = payload.repository.owner.login @@ -308,9 +311,9 @@ module.exports = { repo, tag: tag_name }) - return res + return res.data } catch (e) { - return false + return null } }, @@ -321,23 +324,23 @@ module.exports = { * @param {Array | string} options.reviewers reviewer * @param {Array | string} options.team_reviewers team_reviewers * - * @return {Promise} + * @return {boolean} 是否成功 */ 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({ + await github.pullRequests.createReviewRequest({ owner, repo, number, reviewers: toArray(reviewers), team_reviewers: toArray(team_reviewers) }) - return res + return true } catch (e) { - Promise.reject(e) + return false } }, @@ -345,12 +348,11 @@ module.exports = { * 获得 repo 所有的tag * * @param {any} payload data - * @returns + * @return {Array} */ async getTags (payload) { const owner = payload.repository.owner.login const repo = payload.repository.name - try { const res = await github.repos.getTags({ owner, @@ -358,10 +360,18 @@ module.exports = { }) return res.data } catch (e) { - Promise.reject(e) + return [] } }, + /** + * 对比2个提交 + * + * @param {Object} payload data + * @param {string} options.base 基点 + * @param {string} options.head diff + * @return {Array | null} + */ async compareCommits (payload, { base, head }) { const owner = payload.repository.owner.login const repo = payload.repository.name @@ -374,7 +384,7 @@ module.exports = { }) return res.data } catch (e) { - Promise.reject(e) + return null } } } From 8700425d946dfcb1046f9ad7c787961bc1d7eb6a Mon Sep 17 00:00:00 2001 From: xuexb Date: Sun, 22 Oct 2017 22:19:02 +0800 Subject: [PATCH 2/5] style: remove the git clone code --- README.md | 2 +- src/utils.js | 92 ---------------------------------------------------- 2 files changed, 1 insertion(+), 93 deletions(-) diff --git a/README.md b/README.md index f4cb9da..4131e8e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Github robot ### Release -- [x] 当往远程第一次推送新版本号时,自动列出最新版本距离上一版本的 commit log 并发布 release notes ,会把项目 clone 到 `./github/{项目名}/` 去分析 commit log +- [x] 当往远程第一次推送新版本号时,自动列出最新版本距离上一版本的 commit log 并发布 release notes ,由于需要使用两个 tag 去对比,所以项目的第一个 tag 就不处理 ## 规则 - Rules diff --git a/src/utils.js b/src/utils.js index c1f7afd..25ffe4c 100755 --- a/src/utils.js +++ b/src/utils.js @@ -28,98 +28,6 @@ const utils = { 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 - } - - 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 * From d5463b12dd2e16952e87b6ee25c4cff7b1e02042 Mon Sep 17 00:00:00 2001 From: xuexb Date: Sun, 22 Oct 2017 22:19:45 +0800 Subject: [PATCH 3/5] feat: unified api --- src/modules/pull_request/replyInvalidTitle.js | 3 +- .../pull_request/titlePrefixToLabel.js | 8 +- src/modules/releases/autoReleaseNote.js | 106 +++++++++--------- 3 files changed, 56 insertions(+), 61 deletions(-) diff --git a/src/modules/pull_request/replyInvalidTitle.js b/src/modules/pull_request/replyInvalidTitle.js index 1e01e1d..1e2fc9b 100644 --- a/src/modules/pull_request/replyInvalidTitle.js +++ b/src/modules/pull_request/replyInvalidTitle.js @@ -43,8 +43,7 @@ module.exports = on => { }) on('pull_request_edited', async ({ payload, repo }) => { - if (match(payload.pull_request.title)) { - await pullRequestHasLabel(payload, 'invalid') + if (match(payload.pull_request.title) && await pullRequestHasLabel(payload, 'invalid')) { commentPullRequest( payload, format(commentSuccess, { diff --git a/src/modules/pull_request/titlePrefixToLabel.js b/src/modules/pull_request/titlePrefixToLabel.js index 57d7c09..dbf54d2 100644 --- a/src/modules/pull_request/titlePrefixToLabel.js +++ b/src/modules/pull_request/titlePrefixToLabel.js @@ -18,13 +18,13 @@ const ACTION_TO_LABEL_MAP = { docs: 'document' } -const handle = ({ payload, repo }) => { +const handle = async ({ payload, repo }) => { const action = getAction(payload.pull_request.title) - if (action && ACTION_TO_LABEL_MAP[action]) { - pullRequestHasLabel(payload, ACTION_TO_LABEL_MAP[action]).catch(() => { + const exist = await pullRequestHasLabel(payload, ACTION_TO_LABEL_MAP[action]) + if (!exist) { addLabelsToPullRequest(payload, ACTION_TO_LABEL_MAP[action]) - }) + } } } diff --git a/src/modules/releases/autoReleaseNote.js b/src/modules/releases/autoReleaseNote.js index c6b44d5..d79b79a 100644 --- a/src/modules/releases/autoReleaseNote.js +++ b/src/modules/releases/autoReleaseNote.js @@ -18,77 +18,73 @@ module.exports = on => { tag_name: payload.ref }) // 如果该 tag 存在则直接返回 - if (tag !== false) { + if (tag !== null) { return } - // 创建 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 tags = await getTags(payload) - const commitsLog = await compareCommits(payload, { - base, - head - }) + // 如果只有一个 tag 则没法对比,忽略 + if (tags.length < 2) { + return + } - 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) { + const head = tags[0].name + const base = tags[1].name + + const commitsLog = await compareCommits(payload, { + base, + head + }) + + const commits = commitsLog.commits + const changes = Object.keys(RELEASE_CHANGE_MAP).map(title => { + return { + title, + data: commits + .filter((commit) => commit.commit.message.indexOf(`${RELEASE_CHANGE_MAP[title]}:`) === 0) + .map((commit) => { 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) + return `- ${message}, by @${commit.author.login} <<${commit.commit.author.email}>>` + }) + } + }).filter(v => v.data.length) - 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}>>` - }) + 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.author.login} <<${commit.commit.author.email}>>` + }) - let body = [] + let body = [] - if (changes.length) { - body.push('## Notable changes\n') - changes.forEach(v => { - body.push([ - `- ${v.title}` - ]) + if (changes.length) { + body.push('## Notable changes\n') + changes.forEach(v => { + body.push(`- ${v.title}`) - v.data.forEach(line => body.push(' ' + line)) - }) - } + v.data.forEach(line => body.push(' ' + line)) + }) + } - if (hashChanges.length) { - body.push('\n## Commits\n') - body = body.concat(hashChanges) - } + 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) + if (body.length) { + createRelease(payload, { + tag_name: payload.ref, + name: `${payload.ref} @${payload.repository.owner.login}`, + body: body.join('\n') + }) } }) } From 7a18c6361476d6fac43631d82202a0d249de20c7 Mon Sep 17 00:00:00 2001 From: xuexb Date: Sun, 22 Oct 2017 22:20:18 +0800 Subject: [PATCH 4/5] chore: add the commit message type --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 8c533c9..c71fe2a 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,11 @@ "fix", "docs", "style", + "refactor", "test", "chore", "revert", + "release", "close" ] }, From b29ea2ccf321d6776ed32f0a278a4f7d87ffb649 Mon Sep 17 00:00:00 2001 From: xuexb Date: Sun, 22 Oct 2017 22:33:18 +0800 Subject: [PATCH 5/5] style: remove the git clone code --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index c71fe2a..e41e48a 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,6 @@ "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" }