mirror of
https://gitea.com/Lydanne/pr-extract-issues.git
synced 2025-08-22 19:49:18 +08:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1fd5a8721a | ||
![]() |
b08ec27ac5 | ||
![]() |
0ca412d0d2 | ||
![]() |
3a607d78a3 | ||
![]() |
2befaf5c85 | ||
![]() |
a6c6e82280 | ||
![]() |
cb11554dba | ||
![]() |
4a030f7ef5 | ||
![]() |
7954d992a5 | ||
![]() |
d5061b2c0b | ||
![]() |
9a83c18c43 | ||
![]() |
7c5763d4cc | ||
![]() |
78a8afb859 | ||
![]() |
dd11fb5133 | ||
![]() |
ae5b70b9f0 | ||
![]() |
ec59498db2 |
4
.github/workflows/extract-issues.yml
vendored
4
.github/workflows/extract-issues.yml
vendored
@@ -10,8 +10,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions-cool/pr-extract-issues@main
|
- uses: actions-cool/pr-extract-issues@main
|
||||||
with:
|
with:
|
||||||
way: 'commit'
|
way: 'title'
|
||||||
issues-labels: 'l1, l2'
|
issues-labels: 'l1, l2'
|
||||||
|
remove-labels: 'bug, bug2'
|
||||||
|
filter-label: 'bug'
|
||||||
issues-comment: |
|
issues-comment: |
|
||||||
HI。这个 issue: ${number} 已经被修复了。
|
HI。这个 issue: ${number} 已经被修复了。
|
||||||
issues-close: true
|
issues-close: true
|
||||||
|
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,7 +1,40 @@
|
|||||||
|
<!--
|
||||||
|
🐞 Bug fix
|
||||||
|
🚀 New feature
|
||||||
|
💄 Perf
|
||||||
|
📝 Docs
|
||||||
|
⚡️ Code style
|
||||||
|
🛠 refactor
|
||||||
|
-->
|
||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.2.2
|
||||||
|
|
||||||
|
`2025.02.10`
|
||||||
|
|
||||||
|
- 🐞 fix: undefined body. [#27](https://github.com/actions-cool/pr-extract-issues/pull/27) [@middiu](https://github.com/middiu)
|
||||||
|
|
||||||
|
## v1.2.1
|
||||||
|
|
||||||
|
`2022.09.23`
|
||||||
|
|
||||||
|
- fix: remove no exit label.
|
||||||
|
|
||||||
|
## v1.2.0
|
||||||
|
|
||||||
|
`2022.09.17`
|
||||||
|
|
||||||
|
- feat: support `remove-labels`.
|
||||||
|
|
||||||
|
## v1.1.0
|
||||||
|
|
||||||
|
`2021.03.17`
|
||||||
|
|
||||||
|
- feat: add `filter-label`. [#19](https://github.com/actions-cool/pr-extract-issues/pull/19)
|
||||||
|
|
||||||
## v1.0.0
|
## v1.0.0
|
||||||
|
|
||||||
`2021.xx.xx`
|
`2021.03.12`
|
||||||
|
|
||||||
- 🎉 Init.
|
- 🎉 Init.
|
||||||
|
10
README.md
10
README.md
@@ -1,9 +1,11 @@
|
|||||||
# 🤠 PR Extract Issues
|
# 🤠 PR Extract Issues
|
||||||
|
|
||||||

|

|
||||||
[](https://github.com/marketplace/actions/pr-extract-issues)
|
[](https://github.com/marketplace/actions/pr-extract-issues)
|
||||||
[](https://github.com/actions-cool/pr-extract-issues/releases)
|
[](https://github.com/actions-cool/pr-extract-issues/releases)
|
||||||
|
|
||||||
|
A GitHub Action help you extract issues from pr commit or title or body.
|
||||||
|
|
||||||
## 🚀 How to use?
|
## 🚀 How to use?
|
||||||
|
|
||||||
### Preview
|
### Preview
|
||||||
@@ -23,10 +25,11 @@ jobs:
|
|||||||
extract:
|
extract:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions-cool/pr-extract-issues@v1.0.0
|
- uses: actions-cool/pr-extract-issues@v1
|
||||||
with:
|
with:
|
||||||
way: 'commit'
|
way: 'commit'
|
||||||
issues-labels: 'l1, l2'
|
issues-labels: 'l1, l2'
|
||||||
|
remove-labels: 'bug1, bug2'
|
||||||
issues-comment: |
|
issues-comment: |
|
||||||
HI。这个 issue: ${number} 已经被修复了。
|
HI。这个 issue: ${number} 已经被修复了。
|
||||||
issues-close: true
|
issues-close: true
|
||||||
@@ -38,7 +41,9 @@ jobs:
|
|||||||
| -- | -- | -- | -- |
|
| -- | -- | -- | -- |
|
||||||
| token | GitHub token | string | ✖ |
|
| token | GitHub token | string | ✖ |
|
||||||
| way | The way to query issues. Options: `title` `body` `commit` | string | ✔ |
|
| way | The way to query issues. Options: `title` `body` `commit` | string | ✔ |
|
||||||
|
| filter-label | Further filter issues through label | string | ✖ |
|
||||||
| issues-labels | Extra labels on issues | string | ✖ |
|
| issues-labels | Extra labels on issues | string | ✖ |
|
||||||
|
| remove-labels | Remove labels on issues | string | ✖ |
|
||||||
| issues-comment | Extra comment on issues | string | ✖ |
|
| issues-comment | Extra comment on issues | string | ✖ |
|
||||||
| issues-close | Extra close issues | string | ✖ |
|
| issues-close | Extra close issues | string | ✖ |
|
||||||
|
|
||||||
@@ -52,6 +57,7 @@ jobs:
|
|||||||
- Like: https://github.com/actions-cool/pr-extract-issues/pull/4
|
- Like: https://github.com/actions-cool/pr-extract-issues/pull/4
|
||||||
- Branch whole line display with # start
|
- Branch whole line display with # start
|
||||||
- `commit`: Like `title`
|
- `commit`: Like `title`
|
||||||
|
- `filter-label`: Note that github default hooks. That is, `fix` `close` `resolve` directly followed by issue number will be closed after success merge
|
||||||
- `issues-labels`: Support multiple, need to be separated by comma
|
- `issues-labels`: Support multiple, need to be separated by comma
|
||||||
- `issues-comment`: `${number}` will be replaced with the current issue number
|
- `issues-comment`: `${number}` will be replaced with the current issue number
|
||||||
- `issues-close`: Whether close issue
|
- `issues-close`: Whether close issue
|
||||||
|
10
action.yml
10
action.yml
@@ -10,22 +10,26 @@ branding:
|
|||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
token:
|
token:
|
||||||
description: Secret GitHub API token to use for making API requests.
|
description: Secret GitHub API token to use for making API requests
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
required: true
|
required: true
|
||||||
way:
|
way:
|
||||||
description: The way to query issues.
|
description: The way to query issues
|
||||||
required: true
|
required: true
|
||||||
|
filter-label:
|
||||||
|
description: Further filter issues through label
|
||||||
issues-labels:
|
issues-labels:
|
||||||
description: Extra operations on issues
|
description: Extra operations on issues
|
||||||
issues-comment:
|
issues-comment:
|
||||||
description: Extra operations on issues
|
description: Extra operations on issues
|
||||||
|
remove-labels:
|
||||||
|
description: Will remove labels on issues
|
||||||
issues-close:
|
issues-close:
|
||||||
description: Extra operations on issues
|
description: Extra operations on issues
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
issues:
|
issues:
|
||||||
description: Get issues numbers.
|
description: Get issues numbers
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
|
31480
dist/index.js
vendored
31480
dist/index.js
vendored
File diff suppressed because one or more lines are too long
20
package.json
20
package.json
@@ -1,16 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "pr-extract-issues",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "A GitHub Action help you extract issues from pr commit or title or body.",
|
"description": "A GitHub Action help you extract issues from pr commit or title or body.",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "xrkffgg",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"package": "ncc build",
|
"package": "ncc build",
|
||||||
"format": "prettier --write src/*.js",
|
"format": "prettier --write src/*.js",
|
||||||
"format-check": "prettier --check src/*.js"
|
"format-check": "prettier --check src/*.js",
|
||||||
|
"pub": "sh -e ./scripts/pub.sh",
|
||||||
|
"check-commit": "node ./scripts/check-commit.js",
|
||||||
|
"tag": "node ./scripts/tag.js",
|
||||||
|
"release": "node ./scripts/release"
|
||||||
},
|
},
|
||||||
"author": "xrkffgg",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/github": "^4.0.0",
|
"@actions/github": "^4.0.0",
|
||||||
@@ -19,7 +21,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@umijs/fabric": "^2.5.6",
|
"@umijs/fabric": "^2.5.6",
|
||||||
"@vercel/ncc": "^0.27.0",
|
"@vercel/ncc": "0.34.0",
|
||||||
"prettier": "^2.2.1"
|
"chalk": "^4.1.2",
|
||||||
|
"new-github-release-url": "^1.0.0",
|
||||||
|
"open": "^7.3.0",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
|
"simple-git": "^2.46.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
scripts/check-commit.js
Executable file
23
scripts/check-commit.js
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
const chalk = require('chalk');
|
||||||
|
const simpleGit = require('simple-git/promise');
|
||||||
|
|
||||||
|
const cwd = process.cwd();
|
||||||
|
const git = simpleGit(cwd);
|
||||||
|
|
||||||
|
async function checkCommit({ files }) {
|
||||||
|
if (files.length) {
|
||||||
|
console.log(chalk.yellow('🙄 You forgot something to commit.'));
|
||||||
|
files.forEach(({ path: filePath }) => {
|
||||||
|
console.log(' -', chalk.red(filePath));
|
||||||
|
});
|
||||||
|
console.log('');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const status = await git.status();
|
||||||
|
await checkCommit(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
9
scripts/const.js
Normal file
9
scripts/const.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
const CHANGELOG_NAME = 'CHANGELOG.md';
|
||||||
|
const user = 'actions-cool';
|
||||||
|
const repo = 'pr-extract-issues';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
CHANGELOG_NAME,
|
||||||
|
user,
|
||||||
|
repo,
|
||||||
|
};
|
14
scripts/pub.sh
Normal file
14
scripts/pub.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
echo "[TEST] check format"
|
||||||
|
npm run format-check
|
||||||
|
|
||||||
|
echo "[TEST] test package"
|
||||||
|
npm run package
|
||||||
|
|
||||||
|
echo "[TEST] test commit"
|
||||||
|
npm run check-commit
|
||||||
|
|
||||||
|
echo "[Action] do tag"
|
||||||
|
npm run tag
|
||||||
|
|
||||||
|
echo "[Action] do release"
|
||||||
|
npm run release
|
55
scripts/release.js
Normal file
55
scripts/release.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
const chalk = require('chalk');
|
||||||
|
const open = require('open');
|
||||||
|
const newGithubReleaseUrl = require('new-github-release-url');
|
||||||
|
const { readFileSync } = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const {
|
||||||
|
CHANGELOG_NAME,
|
||||||
|
user,
|
||||||
|
repo
|
||||||
|
} = require('./const');
|
||||||
|
|
||||||
|
let tag = '';
|
||||||
|
|
||||||
|
function getChangelog(content) {
|
||||||
|
const lines = content.split('\n');
|
||||||
|
const changeLog = [];
|
||||||
|
const pin = /^## /;
|
||||||
|
let begin = false;
|
||||||
|
for (let i = 0; i < lines.length; i += 1) {
|
||||||
|
const line = lines[i];
|
||||||
|
if (begin && pin.test(line)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (begin && line) {
|
||||||
|
changeLog.push(line);
|
||||||
|
}
|
||||||
|
if (!begin) {
|
||||||
|
begin = pin.test(line);
|
||||||
|
if (begin) {
|
||||||
|
tag = line.substring(3, line.length).trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changeLog.join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
const changelogPath = path.join(__dirname, '..', CHANGELOG_NAME);
|
||||||
|
const changelog = readFileSync(changelogPath, 'utf-8');
|
||||||
|
|
||||||
|
const body = getChangelog(changelog);
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const url = newGithubReleaseUrl({
|
||||||
|
user,
|
||||||
|
repo,
|
||||||
|
tag,
|
||||||
|
body: body,
|
||||||
|
});
|
||||||
|
|
||||||
|
await open(url);
|
||||||
|
|
||||||
|
console.log(chalk.yellow('🚀 Please check tag and changelog. Then click publish!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
70
scripts/tag.js
Normal file
70
scripts/tag.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
const chalk = require('chalk');
|
||||||
|
const simpleGit = require('simple-git/promise');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const { readFileSync } = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { CHANGELOG_NAME } = require('./const');
|
||||||
|
|
||||||
|
const CHANGELOG_PATH = path.join(__dirname, '..', CHANGELOG_NAME);
|
||||||
|
const CHANGELOG = readFileSync(CHANGELOG_PATH, 'utf-8');
|
||||||
|
|
||||||
|
const cwd = process.cwd();
|
||||||
|
const git = simpleGit(cwd);
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
execSync(`git pull`);
|
||||||
|
|
||||||
|
const data = await git.tags();
|
||||||
|
const tags = data.all;
|
||||||
|
let tag = tags.reverse()[0];
|
||||||
|
console.log(chalk.green(`[Git Query] tag: ${tag}`));
|
||||||
|
|
||||||
|
const tagChangelog = getChangelogTag(CHANGELOG);
|
||||||
|
if (tagChangelog && tag != tagChangelog) {
|
||||||
|
console.log(chalk.yellow(`[Git Action] Push new ${tagChangelog} tag!`));
|
||||||
|
execSync(`git tag ${tagChangelog}`);
|
||||||
|
execSync(`git push origin ${tagChangelog}:${tagChangelog}`);
|
||||||
|
execSync(`git pull`);
|
||||||
|
tag = tagChangelog;
|
||||||
|
} else {
|
||||||
|
console.log(chalk.yellow('🙄 Please add new release changelog first.'));
|
||||||
|
console.log('');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagSimple = tag.startsWith('v') ? tag.substring(0, 2) : tag.substring(0, 1);
|
||||||
|
console.log(chalk.green(`[Git Query] tagSimple: ${tagSimple}`));
|
||||||
|
|
||||||
|
if (tags.includes(tagSimple)) {
|
||||||
|
console.log(chalk.yellow(`[Git Action] Delete ${tagSimple} tag`));
|
||||||
|
execSync(`git push origin :refs/tags/${tagSimple}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.yellow(`[Git Action] Add new simple ${tagSimple} tag`));
|
||||||
|
execSync(`git push origin ${tag}:${tagSimple}`);
|
||||||
|
console.log(chalk.green('🎉 Done!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChangelogTag(content) {
|
||||||
|
const lines = content.split('\n');
|
||||||
|
const pin = /^## /;
|
||||||
|
let begin = false;
|
||||||
|
let tag = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length; i += 1) {
|
||||||
|
const line = lines[i];
|
||||||
|
if (begin && pin.test(line)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!begin) {
|
||||||
|
begin = pin.test(line);
|
||||||
|
if (begin) {
|
||||||
|
tag = line.substring(3, line.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
46
src/main.js
46
src/main.js
@@ -1,7 +1,7 @@
|
|||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
const { Octokit } = require('@octokit/rest');
|
const { Octokit } = require('@octokit/rest');
|
||||||
const github = require('@actions/github');
|
const github = require('@actions/github');
|
||||||
const { dealStringToArr } = require('actions-util');
|
const { dealStringToArr, THANKS } = require('actions-util');
|
||||||
|
|
||||||
// **********************************************************
|
// **********************************************************
|
||||||
const token = core.getInput('token');
|
const token = core.getInput('token');
|
||||||
@@ -27,7 +27,7 @@ async function run() {
|
|||||||
issues.push(it.replace('#', ''));
|
issues.push(it.replace('#', ''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (way === 'body') {
|
} else if (way === 'body' && body) {
|
||||||
let arr = body.split('\n');
|
let arr = body.split('\n');
|
||||||
arr.forEach(it => {
|
arr.forEach(it => {
|
||||||
if (it.startsWith('#')) {
|
if (it.startsWith('#')) {
|
||||||
@@ -55,10 +55,31 @@ async function run() {
|
|||||||
core.setFailed('Wrong way!');
|
core.setFailed('Wrong way!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterLabel = core.getInput('filter-label');
|
||||||
|
if (filterLabel) {
|
||||||
|
let arr = [];
|
||||||
|
for await (const no of issues) {
|
||||||
|
const {
|
||||||
|
data: { labels },
|
||||||
|
} = await octokit.issues.get({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: no,
|
||||||
|
});
|
||||||
|
let o = labels.find(k => k.name == filterLabel);
|
||||||
|
if (o) {
|
||||||
|
arr.push(no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
issues = [...arr];
|
||||||
|
}
|
||||||
|
|
||||||
core.info(`[Action: Query Issues][${issues}]`);
|
core.info(`[Action: Query Issues][${issues}]`);
|
||||||
core.setOutput('issues', issues);
|
core.setOutput('issues', issues);
|
||||||
|
|
||||||
const labels = core.getInput('issues-labels');
|
const labels = core.getInput('issues-labels');
|
||||||
|
const removeLabelsString = core.getInput('remove-labels');
|
||||||
|
const removeLabels = dealStringToArr(removeLabelsString);
|
||||||
const comment = core.getInput('issues-comment');
|
const comment = core.getInput('issues-comment');
|
||||||
const close = core.getInput('issues-close');
|
const close = core.getInput('issues-close');
|
||||||
|
|
||||||
@@ -66,7 +87,7 @@ async function run() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for await (let issue of issues) {
|
for await (const issue of issues) {
|
||||||
if (labels) {
|
if (labels) {
|
||||||
await octokit.issues.addLabels({
|
await octokit.issues.addLabels({
|
||||||
owner,
|
owner,
|
||||||
@@ -76,6 +97,24 @@ async function run() {
|
|||||||
});
|
});
|
||||||
core.info(`Actions: [add-labels][${issue}][${labels}] success!`);
|
core.info(`Actions: [add-labels][${issue}][${labels}] success!`);
|
||||||
}
|
}
|
||||||
|
if (removeLabels && removeLabels.length) {
|
||||||
|
const issueInfo = await octokit.issues.get({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: issue,
|
||||||
|
});
|
||||||
|
const baseLabels = issueInfo.data.labels.map(({ name }) => name);
|
||||||
|
const removes = baseLabels.filter(name => removeLabels.includes(name));
|
||||||
|
for (const label of removes) {
|
||||||
|
await octokit.issues.removeLabel({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: issue,
|
||||||
|
name: label,
|
||||||
|
});
|
||||||
|
core.info(`Actions: [remove-label][${issue}][${label}] success!`);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (comment) {
|
if (comment) {
|
||||||
const body = comment.replace('${number}', `#${issue}`);
|
const body = comment.replace('${number}', `#${issue}`);
|
||||||
await octokit.issues.createComment({
|
await octokit.issues.createComment({
|
||||||
@@ -99,6 +138,7 @@ async function run() {
|
|||||||
} else {
|
} else {
|
||||||
core.setFailed(outEventErr);
|
core.setFailed(outEventErr);
|
||||||
}
|
}
|
||||||
|
core.info(THANKS);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user