17 |
18 |
19 | body-include: ''
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: '❓ 疑问或需要帮助'
3 | about: Question or need help
4 | title: '[Question] Help'
5 | labels: 'question'
6 | assignees: ''
7 | ---
8 |
9 | ### 🧐 问题描述 Problem Description
10 |
11 |
12 |
13 |
14 | ### 💻 示例代码 Sample code
15 |
16 |
17 |
18 |
19 | ### 🚑 其他信息 Other information
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐛 报告 bug
3 | about: Report Bug.
4 | title: '[BUG] Report bug'
5 | labels: 'bug'
6 | assignees:
7 | ---
8 |
9 | ### 🐛 Bug 描述 Bug description
10 |
11 |
12 |
13 |
14 | ### 🏞 期望结果 Desired result
15 |
16 |
17 |
18 |
19 | ### 🚑 其他信息 Other information
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🌟 需求、功能、建议
3 | about: Needs, functions, suggestions.
4 | title: '[Feature] New function'
5 | labels: 'feature'
6 | assignees:
7 | ---
8 |
9 | ### 🥰 需求描述 Description of Requirement
10 |
11 |
12 |
13 |
14 | ### 🧐 解决方案 Solution
15 |
16 |
17 |
18 |
19 | ### 🚑 其他信息 Other information
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import * as github from '@actions/github';
2 | import { dealStringToArr, THANKS } from 'actions-util';
3 |
4 | import * as core from './core';
5 | import { IssueHelperEngine } from './helper';
6 | import type { TAction } from './types';
7 |
8 | async function main() {
9 | try {
10 | const actions = core.getInput('actions', { required: true });
11 | const showThanks = core.getBooleanInput('show-thanks');
12 | const IHE = new IssueHelperEngine(github.context);
13 | for (const action of dealStringToArr(actions)) {
14 | await IHE.doExeAction(action as TAction);
15 | }
16 | if (showThanks) {
17 | core.baseInfo(`\n${THANKS}`);
18 | }
19 | } catch (err: any) {
20 | core.setFailed(err.message);
21 | }
22 | }
23 |
24 | main();
25 |
--------------------------------------------------------------------------------
/src/core/index.ts:
--------------------------------------------------------------------------------
1 | import * as core from '@actions/core';
2 |
3 | export const baseInfo = (mess: string) => {
4 | core.info(mess);
5 | };
6 |
7 | export const info = (mess: string) => {
8 | core.info(`[📝 AC] ${mess}`);
9 | };
10 |
11 | export const error = (mess: string) => {
12 | core.error(`[💥 AC] ${mess}`);
13 | };
14 |
15 | export const notice = (mess: string) => {
16 | core.notice(`[🏷 AC] ${mess}`);
17 | };
18 |
19 | export const warning = (mess: string) => {
20 | core.warning(`[🎃 AC] ${mess}`);
21 | };
22 |
23 | export const getInput = core.getInput;
24 | export const getBooleanInput = core.getBooleanInput;
25 |
26 | export const setOutput = core.setOutput;
27 |
28 | export const setFailed = (mess: string) => {
29 | core.setFailed(`[🚨 AC] ${mess}`);
30 | };
31 |
--------------------------------------------------------------------------------
/web/docs/guide/index.zh-CN.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 🍭 介 绍
3 | ---
4 |
5 | Issues 助手是一个轻松帮你自动管理 issues 的 GitHub Action。
6 |
7 | ### GitHub Actions 是什么?
8 |
9 | GitHub Actions 是由 GitHub 官方提供在存储库中自动化、自定义和执行软件开发工作流程。您可以发现,创建和共享操作以执行所需的任何工作(包括CI / CD),并在完全定制的工作流程中组合操作。[更多介绍](https://docs.github.com/en/free-pro-team@latest/actions)。
10 |
11 | `issues-helper` 就是以此为基础,利用 GitHub Actions 来帮你处理各种关于 issue 方面的操作。
12 |
13 | ### ✨ 特性
14 |
15 | - 😎 完全免费
16 | - 🚀 全自动操作
17 | - 🏖 托管于 GitHub 服务器,只要 GitHub 不宕机,它就不受影响
18 |
19 | ### ⚡ 反馈
20 |
21 | 非常欢迎你来尝试使用,并提出意见,你可以通过以下方式:
22 |
23 | - 通过 [Issue](https://github.com/actions-cool/issues-helper/issues) 报告 bug 或进行咨询
24 | - 通过 [Discussions](https://github.com/actions-cool/issues-helper/discussions) 进行讨论
25 | - 提交 [Pull Request](https://github.com/actions-cool/issues-helper/pulls) 改进 `issues-helper` 的代码
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # @source: https://github.com/xrkffgg/gitignore/blob/master/.gitignore
2 |
3 | # production
4 | # /dist
5 | /docs-dist
6 |
7 | # Log file
8 | *.log
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 |
13 | # Private
14 | .env
15 |
16 | # misc
17 | .DS_Store
18 |
19 | # dependencies
20 | node_modules
21 | # yarn.lock
22 | package-lock.json
23 |
24 | # local env files
25 | .env.local
26 | .env.*.local
27 |
28 | # Compiled file
29 | *.class
30 | *.css.map
31 | *.sass.map
32 | *.scss.map
33 |
34 | # Editor directories and files
35 | .idea
36 | .vscode
37 | *.suo
38 | *.ntvs*
39 | *.njsproj
40 | *.sln
41 | *.sw?
42 | ~$*.*
43 |
44 | # umi
45 | .umi
46 | .umi-production
47 | .umi-test
48 | .env.local
49 |
50 | # dumi
51 | web/.dumi/tmp
52 | web/.dumi/tmp-test
53 | web/.dumi/tmp-production
54 |
55 | # cache
56 | .sass-cache/
57 |
58 | # test
59 | coverage
60 |
--------------------------------------------------------------------------------
/.github/workflows/preview-build.yml:
--------------------------------------------------------------------------------
1 | name: Preview Build
2 |
3 | on:
4 | pull_request:
5 | types: [opened, synchronize, reopened]
6 |
7 | jobs:
8 | build-preview:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v2
13 | with:
14 | ref: ${{ github.event.pull_request.head.sha }}
15 |
16 | - name: build
17 | run: |
18 | yarn
19 | yarn docs:preview
20 |
21 | - run: |
22 | zip -r dist.zip docs-dist
23 |
24 | - name: upload dist artifact
25 | uses: actions/upload-artifact@v4
26 | with:
27 | name: dist
28 | path: dist.zip
29 | retention-days: 5
30 |
31 | - name: Save PR number
32 | if: ${{ always() }}
33 | run: echo ${{ github.event.number }} > ./pr-id.txt
34 |
35 | - name: Upload PR number
36 | if: ${{ always() }}
37 | uses: actions/upload-artifact@v4
38 | with:
39 | name: pr
40 | path: ./pr-id.txt
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-present xrkffgg
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/web/docs/guide/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 🍭 Guide
3 | ---
4 |
5 | The Issues Helper is a GitHub Action that easily helps you automatically manage issues.
6 |
7 | ### What are GitHub Actions?
8 |
9 | Automate, customize, and execute your software development workflows right in your repository with GitHub Actions. You can discover, create, and share actions to perform any job you'd like, including CI/CD, and combine actions in a completely customized workflow. [More](https://docs.github.com/en/free-pro-team@latest/actions).
10 |
11 | `issues-helper` is based on this, using GitHub Actions to help you deal with various operations on issues.
12 |
13 | ### ✨ Feature
14 |
15 | - 😎 Complete free
16 | - 🚀 Fully automatic
17 | - 🏖 Hosted on the GitHub server, as long as GitHub is not down, it is not affected
18 |
19 | ### ⚡ Feedback
20 |
21 | You are very welcome to try it out and put forward your comments. You can use the following methods:
22 |
23 | - Report bugs or consult with [Issue](https://github.com/actions-cool/issues-helper/issues)
24 | - Discuss via [Discussions](https://github.com/actions-cool/issues-helper/discussions)
25 | - Submit [Pull Request](https://github.com/actions-cool/issues-helper/pulls) to improve the code of `issues-helper`
26 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
5 |
6 | ### 🤔 这个变动的性质是?/ What is the nature of this change?
7 |
8 | - [ ] 新特性提交 / New feature
9 | - [ ] bug 修复 / Fix bug
10 | - [ ] 样式优化 / Style optimization
11 | - [ ] 代码风格优化 / Code style optimization
12 | - [ ] 性能优化 / Performance optimization
13 | - [ ] 构建优化 / Build optimization
14 | - [ ] 网站、文档、Demo 改进 / Website, documentation, demo improvements
15 | - [ ] 重构代码或样式 / Refactor code or style
16 | - [ ] 测试相关 / Test related
17 | - [ ] 其他 / Other
18 |
19 | ### 🔗 相关 Issue / Related Issue
20 |
21 |
25 |
26 | ### 💡 需求背景和解决方案 / Background or solution
27 |
28 |
32 |
33 | ### 📝 更新日志 / Changelog
34 |
35 |
39 |
40 | | Language | Changelog |
41 | | ---------- | --------- |
42 | | 🇺🇸 English | |
43 | | 🇨🇳 Chinese | |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/util/index.ts:
--------------------------------------------------------------------------------
1 | import { dealStringToArr } from 'actions-util';
2 | import sampleSize from 'lodash/sampleSize';
3 |
4 | export const dealRandomAssignees = (assignees: string, randomTo: string | void): string[] => {
5 | let arr = dealStringToArr(assignees);
6 | if (randomTo && Number(randomTo) > 0 && Number(randomTo) < arr.length) {
7 | arr = sampleSize(arr, Number(randomTo));
8 | }
9 | return arr;
10 | };
11 |
12 | export const matchKeyword = (content: string = '', keywords: string[]): boolean => {
13 | return !!keywords.find(item => content?.toLowerCase().includes(item));
14 | };
15 |
16 | export const checkDuplicate = (body: string | void): boolean => {
17 | if (!body || !body.startsWith('Duplicate of')) {
18 | return false;
19 | }
20 | const arr = body.split(' ');
21 | return arr[0] == 'Duplicate' && arr[1] == 'of';
22 | };
23 |
24 | export const getPreMonth = (m: number): number => {
25 | return m == 1 ? 12 : m - 1;
26 | };
27 |
28 | // replace some & split & cull empty
29 | export const replaceStr2Arr = (str: string, replace: string, split: string): string[] => {
30 | return str
31 | .replace(replace, '')
32 | .trim()
33 | .split(split)
34 | .reduce((result: string[], it) => (it ? [...result, it.trim()] : result), []);
35 | };
36 |
--------------------------------------------------------------------------------
/tests/index.test.ts:
--------------------------------------------------------------------------------
1 | import { replaceStr2Arr } from '../src/util';
2 |
3 | describe('Test', () => {
4 | it('test doQueryIssues', () => {
5 | const issues = [
6 | {
7 | id: 0,
8 | labels: [{ name: '0' }, { name: '1' }],
9 | },
10 | {
11 | id: 1,
12 | labels: [{ name: '1' }, { name: '2' }],
13 | },
14 | {
15 | id: 2,
16 | labels: [{ name: '2' }, { name: '3' }],
17 | },
18 | {
19 | id: 3,
20 | labels: [{ name: '1' }, { name: '4' }],
21 | },
22 | {
23 | id: 4,
24 | labels: [{ name: '1' }, { name: '3' }],
25 | },
26 | {
27 | id: 5,
28 | labels: [{ name: '1' }, { name: '5' }],
29 | },
30 | ];
31 |
32 | let ex = ['2', '4'];
33 | let r = [];
34 |
35 | issues.forEach(iss => {
36 | for (let i = 0; i < iss.labels.length; i += 1) {
37 | if (ex.includes(iss.labels[i].name)) return;
38 | }
39 | r.push(iss);
40 | });
41 |
42 | expect(r[0].id).toEqual(0);
43 | expect(r[1].id).toEqual(4);
44 | expect(r[2].id).toEqual(5);
45 | expect(r.length).toEqual(3);
46 | });
47 |
48 | it('test replaceStr2Arr', () => {
49 | const st = '/assign @1 @2 @3@a 3 @s @1_2 2';
50 | const re = '/assign';
51 | const sp = '@';
52 |
53 | expect(replaceStr2Arr(st, re, sp)).toEqual(['1', '2', '3', 'a 3', 's', '1_2 2']);
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/scripts/release.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const open = require('open');
3 | const newGithubReleaseUrl = require('new-github-release-url');
4 | const { readFileSync } = require('fs');
5 | const path = require('path');
6 |
7 | let tag = '';
8 |
9 | const CHANGELOG_NAME = 'CHANGELOG.md';
10 | const user = 'actions-cool';
11 | const repo = 'issues-helper';
12 |
13 | function getChangelog(content) {
14 | const lines = content.split('\n');
15 | const changeLog = [];
16 | const pin = /^## /;
17 | let begin = false;
18 | for (let i = 0; i < lines.length; i += 1) {
19 | const line = lines[i];
20 | if (begin && pin.test(line)) {
21 | break;
22 | }
23 | if (begin && line) {
24 | changeLog.push(line);
25 | }
26 | if (!begin) {
27 | begin = pin.test(line);
28 | if (begin) {
29 | tag = line.substring(3, line.length).trim();
30 | }
31 | }
32 | }
33 | return changeLog.join('\n\n');
34 | }
35 |
36 | const changelogPath = path.join(__dirname, '..', CHANGELOG_NAME);
37 | const changelog = readFileSync(changelogPath, 'utf-8');
38 |
39 | const body = getChangelog(changelog);
40 |
41 | async function run() {
42 | const url = newGithubReleaseUrl({
43 | user,
44 | repo,
45 | tag,
46 | body: body,
47 | });
48 |
49 | await open(url);
50 |
51 | console.log(chalk.yellow('🚀 Please check tag and changelog in a auto new webview tab. Then click publish!'));
52 | }
53 |
54 | run();
55 |
--------------------------------------------------------------------------------
/web/docs/guide/note.zh-CN.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 🎗 记 录
3 | ---
4 |
5 | :::success{title="😊"}
6 | 这里记录自己在使用中总结的一些东西,希望可以帮助到你。
7 | :::
8 |
9 | ## `yml` 中包含判断
10 |
11 | ```yml
12 | if: contains(github.event.issue.body, 'ie') == false
13 | ```
14 |
15 | - 当 issue body 不包含 `ie` 触发
16 | - 测试 yml 中不支持 js `includes()` 语法
17 | - 大小写不校验,`IE` 还有同时类似 `kiekk` 也可满足
18 |
19 | 更多[查看](https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#functions)。
20 |
21 | ## `yml` 中传值和输出
22 |
23 | ```
24 | with:
25 | actions: 'month-statistics'
26 | token: ${{ secrets.GITHUB_TOKEN }}
27 | count-labels: 'true'
28 | ```
29 |
30 | - `count-labels`:不管设置 `true` 还是 `'ture'`,在程序里接收到的都是字符串格式
31 |
32 | 同时输出的也是字符串格式。[参看](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idoutputs)。
33 |
34 | - `check-result`:判断条件为 `if: steps.xxid.outputs.check-result == 'true'`
35 |
36 | ## `GitHub Actions bot` 触发
37 |
38 | 当设置了一个 Actions,如为给一个 issue 新增 label `x1` 时,Actions 自动为该 issue 增加 `x2` label。
39 |
40 | 但如果这个是由 `GitHub Actions bot` 完成的(即 actions 中 token 不传,或使用默认 `token: ${{ secrets.GITHUB_TOKEN }}`),则不会触发 label `x2` 的 Actions。
41 |
42 | ref: [GitHub docs](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token)
43 |
44 | ## `assignees` 范围
45 |
46 | - 仓库的所有者或协作者,若有组织,包括成员
47 | - issue 的参与者,包括创建者、评论者
48 | - 最多支持 10 个
49 |
50 | ## 运行基准
51 |
52 | 比如:我用 Tag 触发一个 Action,触发基准的代码就会走这个 Tag 对应代码的 Action 定义,而非主分支代码。
53 |
--------------------------------------------------------------------------------
/web/.dumirc.ts:
--------------------------------------------------------------------------------
1 | // more config: https://d.umijs.org/config
2 | import { defineConfig } from 'dumi';
3 | import path from 'path';
4 | import remarkPlugin from './remark-plugins';
5 |
6 | const name = 'issues-helper';
7 |
8 | const isProdSite =
9 | // 不是预览模式 同时是生产环境
10 | process.env.PREVIEW !== 'true' && process.env.NODE_ENV === 'production';
11 |
12 | const logo =
13 | 'https://gw.alipayobjects.com/mdn/rms_f97235/afts/img/A*8xDgSL-O6O4AAAAAAAAAAAAAARQnAQ';
14 |
15 | export default defineConfig({
16 | title: 'Issues Helper',
17 | outputPath: '../docs-dist',
18 | base: isProdSite ? `/${name}/` : '/',
19 | publicPath: isProdSite ? `/${name}/` : '/',
20 | locales: [
21 | { id: 'en-US', name: 'English', },
22 | { id: 'zh-CN', name: '中文' },
23 | ],
24 | favicons: [logo],
25 | extraRemarkPlugins: [remarkPlugin],
26 | themeConfig: {
27 | logo,
28 | nav: {
29 | 'zh-CN': [
30 | { title: '指 南', link: '/zh-CN/guide' },
31 | { title: '基 础', link: '/zh-CN/base' },
32 | { title: '进 阶', link: '/zh-CN/advanced' },
33 | { title: '更新日志', link: '/zh-CN/changelog' }
34 | ],
35 | 'en-US': [
36 | { title: 'Guide', link: '/guide' },
37 | { title: 'Base', link: '/base' },
38 | { title: 'Advanced', link: '/advanced' },
39 | { title: 'Changelog', link: '/changelog' },
40 | ],
41 | },
42 | socialLinks: {
43 | github: 'https://github.com/actions-cool/issues-helper'
44 | },
45 | footer: 'Open-source MIT Licensed | Copyright © 2020-present
62 |
63 |
64 | body-include: ''
65 | number: ${{ steps.pr.outputs.id }}
66 |
67 | failed:
68 | runs-on: ubuntu-latest
69 | if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure'
70 | steps:
71 | - name: download pr artifact
72 | uses: dawidd6/action-download-artifact@v6
73 | with:
74 | workflow: ${{ github.event.workflow_run.workflow_id }}
75 | name: pr
76 |
77 | - name: save PR id
78 | id: pr
79 | run: echo "::set-output name=id::$(|
49 |
50 | |
53 |
54 |
55 | |
58 |
59 |
60 | |
63 |
64 |
65 | |
68 |
| ant-design | 71 |ant-design-blazor | 72 |ant-design-mobile | 73 |ant-design-vue | 74 |
|
76 |
77 | |
80 |
81 |
82 | |
85 |
86 |
87 | |
90 |
91 |
92 | |
95 |
| bootstrap | 98 |core | 99 |dumi | 100 |electron | 101 |
|
103 |
104 | |
107 |
108 |
109 | |
112 |
113 |
114 | |
117 |
118 |
119 | |
122 |
| element-plus | 125 |formily | 126 |jsx-next | 127 |material-ui | 128 |
|
130 |
131 | |
134 |
135 |
136 | |
139 |
140 |
141 | |
144 |
145 |
146 | |
149 |
| nutui | 152 |prettier | 153 |react-component | 154 |react-music-player | 155 |
|
157 |
158 | |
161 |
162 |
163 | |
166 |
167 |
168 | |
171 |
172 |
173 | |
176 |
| S2 | 179 |swiper | 180 |umi | 181 |vite | 182 |
|
184 |
185 | |
188 |
189 |
190 | |
193 |
194 |
195 | |
198 |
199 |
200 | |
203 |
| vitest | 206 |vue-request | 207 |vuepress-next | 208 |zoo | 209 |