diff --git a/.gitignore b/.gitignore index 1c5e02c..acbc377 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ yarn-error.log* # misc .DS_Store +.env # dependencies node_modules diff --git a/README.md b/README.md index 71aa0da..f6ea0c4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,13 @@ -# Issue Helper +# 🤖 Issue Helper A GitHub action to help you deal with the issue. -## Usage +最开始: +- 确保 token 拥有当前项目的 push 权限。 +## Usage ### `add-assignees` +### `add-labels` + +### `create-comment` \ No newline at end of file diff --git a/README.zh-CN.md b/README.zh-CN.md index 6781fa9..4cb2ff6 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,8 +1,59 @@ -# Issue Helper +# 🤖 Issue Helper + +一个完全帮你处理 issue 的 GitHub Action。 + +## 列表 + + -一个可以帮助你处理 issue 的 GitHub Action。 ## 使用 +### 基础 +#### `add-assignees` + +将一个 issue 增加指定人 + +```yml +- name: Add assigness + uses: actions-cool/issue-helper@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: 1 + assignees: 'xrkffgg' +``` + +| 参数 | 描述 | 类型 | 必填 | 版本 | +| -- | -- | -- | -- | -- | +| token | [token](#token) | string | ✖ | v1 | +| issue-number | 指定的 issue,可通过 url 查看 | number | ✔ | v1 | + +## 参考 + +### token + +需拥有 push 权限的人员 token。 + +- [个人 token 申请](https://github.com/settings/tokens) + - 需勾选 `Full control of private repositories` +- 项目添加 secrets + - 选择 settings,选择 secrets,选择 `New repository secret` + - `Name` 与 actions 中保持一致 + - `Value` 填写刚才个人申请的 token + +当 actions 不填写 token 时,会默认为 github-actions bot。 + +### Reactions types + +| content | emoji | +| -- | -- | +| `+1` | 👍 | +| `-1` | 👎 | +| `laugh` | 😄 | +| `confused` | 😕 | +| `heart` | ❤️ | +| `hooray` | 🎉 | +| `rocket` | 🚀 | +| `eyes` | 👀 | diff --git a/action.yml b/action.yml index 3d014d5..9b04904 100644 --- a/action.yml +++ b/action.yml @@ -8,6 +8,11 @@ inputs: github_token: description: 'github_token' default: ${{ github.token }} +outputs: + issue_number: + description: 'Create Issue Number' + comment-id: + description: 'Create comment ID' runs: using: node12 main: 'dist/index.js' diff --git a/src/base.js b/src/base.js new file mode 100644 index 0000000..3efb239 --- /dev/null +++ b/src/base.js @@ -0,0 +1,287 @@ +require('dotenv').config(); +const core = require("@actions/core"); +const { Octokit } = require('@octokit/rest'); + +const ALLREACTIONS = [ + "+1", + "-1", + "laugh", + "confused", + "heart", + "hooray", + "rocket", + "eyes", +]; + +const token = core.getInput('token') || process.env.GH_TOKEN; +const octokit = new Octokit({ auth: `token ${token}` }); + +const contents = core.getInput("contents"); + +async function doAddAssignees (owner, repo, issueNumber, assignees) { + await octokit.issues.addAssignees({ + owner, + repo, + issue_number: issueNumber, + assignees + }); + core.info(`Actions: [add-assignees][${assignees}] success!`); +}; + +async function doAddLabels (owner, repo, issueNumber, labels) { + await octokit.issues.addLabels({ + owner, + repo, + issue_number: issueNumber, + labels + }); + core.info(`Actions: [add-labels][${labels}] success!`); +}; + +async function doCreateComment (owner, repo, issueNumber, body) { + const { data } = await octokit.issues.createComment({ + owner, + repo, + issue_number: issueNumber, + body + }); + core.info(`Actions: [create-comment][${body}] success!`); + core.setOutput("comment-id", data.id); + + if (contents) { + await doCreateCommentContent(owner, repo, data.id, contents); + } +}; + +async function doCreateCommentContent(owner, repo, commentId) { + if (typeof(contents) === 'object') { + contents.forEach(async item => { + if (testContent(item)) { + await octokit.reactions.createForIssueComment({ + owner, + repo, + comment_id: commentId, + content: item + }); + core.info(`Actions: [create-reactions][${item}] success!`); + } + }) + } else if (typeof(contents) === 'string' && testContent(contents)) { + await octokit.reactions.createForIssueComment({ + owner, + repo, + comment_id: commentId, + content: contents + }); + core.info(`Actions: [create-reactions][${contents}] success!`); + } +}; + +async function doCreateIssue (owner, repo, title, body, labels, assignees) { + let params = { + owner, + repo, + title, + body, + labels + }; + if (typeof(assignees) === 'string') { + params.assignee = assignees; + } else { + params.assignees = assignees; + } + const { data } = await octokit.issues.create(params); + core.info(`Actions: [create-issue][${title}] success!`); + core.setOutput("issue_number", data.number); + + if (contents) { + await doCreateIssueContent(owner, repo, data.number, contents); + } +}; + +async function doCreateIssueContent(owner, repo, issueNumber) { + if (typeof(contents) === 'object') { + contents.forEach(async item => { + if (testContent(item)) { + await octokit.reactions.createForIssue({ + owner, + repo, + issue_number: issueNumber, + content: item + }); + core.info(`Actions: [create-reactions][${item}] success!`); + } + }) + } else if (typeof(contents) === 'string' && testContent(contents)) { + await octokit.reactions.createForIssue({ + owner, + repo, + issue_number: issueNumber, + content: contents + }); + core.info(`Actions: [create-reactions][${contents}] success!`); + } +}; + +async function doDeleteComment (owner, repo, commentId) { + await octokit.issues.deleteComment({ + owner, + repo, + comment_id: commentId + }); + core.info(`Actions: [delete-comment][${commentId}] success!`); +}; + +async function doLockIssue (owner, repo, issueNumber) { + await octokit.issues.lock({ + owner, + repo, + issue_number: issueNumber, + }); + core.info(`Actions: [lock-issue][${issueNumber}] success!`); +}; + +async function doRemoveAssignees (owner, repo, issueNumber, assignees) { + await octokit.issues.removeAssignees({ + owner, + repo, + issue_number: issueNumber, + assignees + }); + core.info(`Actions: [remove-assignees][${assignees}] success!`); +}; + +async function doSetLabels (owner, repo, issueNumber, labels) { + await octokit.issues.setLabels({ + owner, + repo, + issue_number: issueNumber, + labels + }); + core.info(`Actions: [set-labels][${labels}] success!`); +}; + +async function doUnlockIssue (owner, repo, issueNumber) { + await octokit.issues.unlock({ + owner, + repo, + issue_number: issueNumber, + }); + core.info(`Actions: [unlock-issue][${issueNumber}] success!`); +}; + +async function doUpdateIssue ( + owner, + repo, + issueNumber, + state, + title, + body, + updateMode, + assignees, + labels +) { + const issue = await octokit.issues.get({ + owner, + repo, + issue_number: issueNumber + }) + const issue_body = issue.data.body; + const issue_title = issue.data.title; + const issue_labels = issue.data.labels; + + let params = { + owner, + repo, + issue_number: issueNumber, + state + }; + + params.title = core.getInput("title") ? title : issue_title; + + let next_body; + if (core.getInput("body")) { + if (updateMode === 'append') { + next_body = `${issue_body}\n${body}`; + } else { + next_body = body; + } + } else { + next_body = issue_body; + } + params.body = next_body; + + if (typeof(assignees) === 'string') { + params.assignee = assignees; + } else { + params.assignees = assignees; + } + + params.labels = labels ? labels : issue_labels; + + await octokit.issues.update(params); + core.info(`Actions: [update-issue][${issueNumber}] success!`); + + if (contents) { + await doCreateIssueContent(owner, repo, issueNumber, contents); + } +}; + +async function doUpdateComment ( + owner, + repo, + commentId, + body, + updateMode +) { + const comment = await octokit.issues.getComment({ + owner, + repo, + comment_id: commentId + }) + const comment_body = comment.data.body; + + let params = { + owner, + repo, + comment_id: commentId + }; + + if (updateMode === 'append') { + params.body = `${comment_body}\n${body}`; + } else { + params.body = body; + } + + await octokit.issues.updateComment(params); + core.info(`Actions: [update-comment][${commentId}] success!`); + + if (contents) { + await doCreateCommentContent(owner, repo, commentId, contents); + } +}; + +function testContent(con) { + if (ALLREACTIONS.includes(con)) { + return true; + } else { + core.setFailed("This actions not supported!"); + return false; + } +}; + +module.exports = { + doAddAssignees, + doAddLabels, + doCreateComment, + doCreateCommentContent, + doCreateIssue, + doCreateIssueContent, + doDeleteComment, + doLockIssue, + doRemoveAssignees, + doSetLabels, + doUnlockIssue, + doUpdateIssue, + doUpdateComment +}; diff --git a/src/main.js b/src/main.js index 8a5cca3..066c24f 100644 --- a/src/main.js +++ b/src/main.js @@ -1,35 +1,60 @@ -require('dotenv').config(); - const core = require("@actions/core"); const github = require("@actions/github"); -const { Octokit } = require('@octokit/rest'); const { - doAddAssignees -} = require('./tool'); + doAddAssignees, + doAddLabels, + doCreateComment, + doCreateCommentContent, + doCreateIssue, + doCreateIssueContent, + doDeleteComment, + doLockIssue, + doRemoveAssignees, + doSetLabels, + doUnlockIssue, + doUpdateIssue, + doUpdateComment +} = require('./base.js'); const ALLACTIONS = [ 'add-assignees', - 'add-labels' + 'add-labels', + 'create-comment', + 'create-issue', + 'delete-comment', + 'lock-issue', + 'remove-assignees', + 'set-labels', + 'unlock-issue', + 'update-issue', + 'update-comment', ]; async function main() { - try { - const token = core.getInput('token') || process.env.GH_TOKEN; - - const octokit = new Octokit({ auth: `token ${token}` }); - // const owner = github.context.repo.owner; - // const repo = github.context.repo.repo; - const owner = 'actions-cool'; - const repo = 'issue-helper'; - const issueNumber = core.getInput('issue-number') || 1; + try { + const owner = github.context.repo.owner; + const repo = github.context.repo.repo; + const issueNumber = core.getInput('issue-number'); const commentId = core.getInput('comment-id'); - const body = core.getInput("body"); - // const assignees = core.getInput("assignees"); - const assignees = 'xrkffgg' - const actions = ['add-assignees', 'add-labels']; - // const actions = core.getInput("actions", { required: true }); + const defaultBody = `Currently at ${owner}/${repo}. And this is default comment.` + const body = core.getInput("body") || defaultBody; + + const defaultTitle = `Default Title`; + const title = core.getInput("title") || defaultTitle; + + const assignees = core.getInput("assignees"); + + const labels = core.getInput("labels"); + const state = core.getInput("state"); + + let updateMode = core.getInput("state") || 'replace'; + if (updateMode !== 'append') { + updateMode = 'replace'; + } + + const actions = core.getInput("actions", { required: true }); if (typeof(actions) === 'object') { actions.forEach(item => { @@ -50,11 +75,56 @@ async function main() { async function choseActions(action) { switch (action) { case 'add-assignees': - await doAddAssignees(octokit, owner, repo, issueNumber, assignees); - default: + await doAddAssignees(owner, repo, issueNumber, assignees); + break; + case 'add-labels': + await doAddLabels(owner, repo, issueNumber, labels); + break; + case 'create-comment': + await doCreateComment(owner, repo, issueNumber, body); + break; + case 'create-issue': + await doCreateIssue(owner, repo, title, body, labels, assignees); + break; + case 'delete-comment': + await doDeleteComment(owner, repo, commentId); + break; + case 'lock-issue': + await doLockIssue(owner, repo, issueNumber); + break; + case 'remove-assignees': + await doRemoveAssignees(owner, repo, issueNumber, assignees); + break; + case 'set-labels': + await doSetLabels(owner, repo, issueNumber, labels); + break; + case 'unlock-issue': + await doUnlockIssue(owner, repo, issueNumber); + break; + case 'update-issue': + await doUpdateIssue( + owner, + repo, + issueNumber, + state, + title, + body, + updateMode, + assignees, + labels + ); + case 'update-comment': + await doUpdateComment( + owner, + repo, + commentId, + body, + updateMode + ); + default: break; } - } + }; } catch (error) { core.setFailed(error.message); diff --git a/src/tool.js b/src/tool.js deleted file mode 100644 index 00910a3..0000000 --- a/src/tool.js +++ /dev/null @@ -1,30 +0,0 @@ -const REACTION_TYPES = [ - "+1", - "-1", - "laugh", - "confused", - "heart", - "hooray", - "rocket", - "eyes", -]; - -const doAddAssignees = async ({ - octokit, - owner, - repo, - issueNumber, - assignees -}) => { - await octokit.issues.addAssignees({ - owner, - repo, - issue_number: issueNumber, - assignees - }); -}; - - -module.exports = { - doAddAssignees -};