Skip to content

Commit c66a5f4

Browse files
committed
feat: support Waffle.io issue keywords
1 parent 3dbff9a commit c66a5f4

File tree

5 files changed

+367
-30
lines changed

5 files changed

+367
-30
lines changed

README.md

+116-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# issue-parser
22

3-
Parser for Github, GitLab and Bitbucket issues actions, references and mentions
3+
Parser for [Github](https://github.com), [GitLab](https://gitlab.com), [Bitbucket](https://bitbucket.org) and [Waffle](https://waffle.io) issues actions, references and mentions
44

55
[![Travis](https://img.shields.io/travis/pvdlg/issue-parser.svg)](https://travis-ci.org/pvdlg/issue-parser)
66
[![Codecov](https://img.shields.io/codecov/c/github/pvdlg/issue-parser.svg)](https://codecov.io/gh/pvdlg/issue-parser)
@@ -10,6 +10,7 @@ The parser can identify:
1010
- GitHub [closing keywords](https://help.github.com/articles/closing-issues-using-keywords), [duplicate keyword](https://help.github.com/articles/about-duplicate-issues-and-pull-requests), [issue references](https://guides.github.com/features/issues/#notifications) and [user mentions](https://guides.github.com/features/issues/#notifications)
1111
- GitLab [closing keywords](https://docs.gitlab.com/ee/user/project/issues/automatic_issue_closing.html), [duplicate keyword](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12845), [issue references](https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected) and [user mentions](https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected)
1212
- Bitbucket [closing keywords](https://confluence.atlassian.com/bitbucket/resolve-issues-automatically-when-users-push-code-221451126.html), [issue references](https://confluence.atlassian.com/bitbucket/mark-up-comments-issues-and-commit-messages-321859781.html) and [user mentions](https://confluence.atlassian.com/bitbucket/mark-up-comments-issues-and-commit-messages-321859781.html)
13+
- Waffle.io [epics](https://help.waffle.io/epics/which-keywords-are-supported-with-epics) and [dependencies](https://help.waffle.io/dependencies/which-keywords-are-supported-with-dependencies) keywords
1314

1415
## Install
1516

@@ -67,7 +68,26 @@ parse('Issue description, ref user/package#1, fixing #2. /cc @user');
6768
{
6869
refs: [{raw: 'user/package#1', slug: 'user/package', prefix: '#', issue: '1'}],
6970
actions: [{raw: 'fixing #2', action: 'Fixing', prefix: '#', issue: '2'}],
70-
duplicates: [],
71+
mentions: [{raw: '@user', prefix: '@', user: 'user'}],
72+
}
73+
*/
74+
```
75+
76+
### Waffle format
77+
78+
```js
79+
const issueParser = require('issue-parser');
80+
const parse = issueParser('waffle');
81+
82+
parse('Issue description, ref user/package#1, Fix #2, blocks user/package#3, Require #4, Parent of #5, Child of #6 /cc @user');
83+
/*
84+
{
85+
refs: [{raw: 'user/package#1', slug: 'user/package', prefix: '#', issue: '1'}],
86+
actions: [{raw: 'Fix #2', action: 'Fix', prefix: '#', issue: '2'}],
87+
blocks: [{raw: 'blocks user/package#3', action: 'Blocks', slug: 'user/package', prefix: '#', issue: '3'}],
88+
requires: [{raw: 'Require #4', action: 'Require', prefix: '#', issue: '4'}],
89+
parentOf: [{raw: 'Parent of #5', action: 'Parent of', prefix: '#', issue: '5'}],
90+
childOf: [{raw: 'Child of #6', action: 'Child of', prefix: '#', issue: '6'}],
7191
mentions: [{raw: '@user', prefix: '@', user: 'user'}],
7292
}
7393
*/
@@ -77,15 +97,14 @@ parse('Issue description, ref user/package#1, fixing #2. /cc @user');
7797

7898
```js
7999
const issueParser = require('issue-parser');
80-
const parse = issueParser({referenceActions: ['complete'], issuePrefixes: ['🐛']});
100+
const parse = issueParser({referenceActions: ['complete'], blocksActions: ['holds up'], issuePrefixes: ['🐛']});
81101

82-
parse('Issue description, related to user/package🐛1, Complete 🐛2');
102+
parse('Issue description, related to user/package🐛1, Complete 🐛2, holds up 🐛3');
83103
/*
84104
{
85105
refs: [{raw: 'user/package🐛1', slug: 'user/package', prefix: '🐛', issue: '1'}],
86106
actions: [{raw: 'Complete 🐛2', action: 'Complete', prefix: '🐛', issue: '2'}],
87-
duplicates: [],
88-
mentions: [],
107+
blocks: [{raw: 'holds up 🐛3', action: 'Holds up', prefix: '🐛', issue: '3'}],
89108
}
90109
*/
91110
```
@@ -282,6 +301,34 @@ Default: `['close', 'closes', 'closed', 'closing', 'fix', 'fixes', 'fixed', 'fix
282301

283302
List of action keywords used to close issues and pull requests.
284303

304+
##### blocksActions
305+
306+
Type: `Array<String>` `String`<br>
307+
Default: `['blocks', 'block', 'required by', 'needed by', 'dependency of']`
308+
309+
List of action keywords used to make an issue or pull request block another one.
310+
311+
##### requiresActions
312+
313+
Type: `Array<String>` `String`<br>
314+
Default: `['blocked by', 'requires', 'require', 'need', 'needs', 'depends on']`
315+
316+
List of action keywords used to make an issue or pull request blocked by another one.
317+
318+
##### parentOfActions
319+
320+
Type: `Array<String>` `String`<br>
321+
Default: `['parent of', 'parent to', 'parent']`
322+
323+
List of action keywords used to make an issue or pull request the parent of another one.
324+
325+
##### childOfActions
326+
327+
Type: `Array<String>` `String`<br>
328+
Default: `['child of', 'child to', 'child']`
329+
330+
List of action keywords used to make an issue or pull request the child of another one.
331+
285332
##### duplicateActions
286333

287334
Type: `Array<String>` `String`<br>
@@ -355,6 +402,66 @@ Each action has the following properties:
355402
| prefix | `String` | The prefix used to identify the issue. |
356403
| issue | `String` | The issue number. |
357404

405+
#### blocks
406+
407+
Type: `Array<Object>`
408+
409+
List of issues and pull requests blocked.<br>
410+
Each action has the following properties:
411+
412+
| Name | Type | Description |
413+
|--------|----------|---------------------------------------------------------------------------------------|
414+
| raw | `String` | The raw value parsed, for example `Blocks #1`. |
415+
| action | `String` | The keyword used to identify the action, capitalized. |
416+
| slug | `String` | The repository owner and name, for issue referred as `<owner>/<repo>#<issue number>`. |
417+
| prefix | `String` | The prefix used to identify the issue. |
418+
| issue | `String` | The issue number. |
419+
420+
#### requires
421+
422+
Type: `Array<Object>`
423+
424+
List of issues and pull requests required.<br>
425+
Each action has the following properties:
426+
427+
| Name | Type | Description |
428+
|--------|----------|---------------------------------------------------------------------------------------|
429+
| raw | `String` | The raw value parsed, for example `Requires #1`. |
430+
| action | `String` | The keyword used to identify the action, capitalized. |
431+
| slug | `String` | The repository owner and name, for issue referred as `<owner>/<repo>#<issue number>`. |
432+
| prefix | `String` | The prefix used to identify the issue. |
433+
| issue | `String` | The issue number. |
434+
435+
#### parentOf
436+
437+
Type: `Array<Object>`
438+
439+
List of child issues and pull requests.<br>
440+
Each action has the following properties:
441+
442+
| Name | Type | Description |
443+
|--------|----------|---------------------------------------------------------------------------------------|
444+
| raw | `String` | The raw value parsed, for example `Parent of #1`. |
445+
| action | `String` | The keyword used to identify the action, capitalized. |
446+
| slug | `String` | The repository owner and name, for issue referred as `<owner>/<repo>#<issue number>`. |
447+
| prefix | `String` | The prefix used to identify the issue. |
448+
| issue | `String` | The issue number. |
449+
450+
#### childOf
451+
452+
Type: `Array<Object>`
453+
454+
List of parent issues and pull requests.<br>
455+
Each action has the following properties:
456+
457+
| Name | Type | Description |
458+
|--------|----------|---------------------------------------------------------------------------------------|
459+
| raw | `String` | The raw value parsed, for example `Child of #1`. |
460+
| action | `String` | The keyword used to identify the action, capitalized. |
461+
| slug | `String` | The repository owner and name, for issue referred as `<owner>/<repo>#<issue number>`. |
462+
| prefix | `String` | The prefix used to identify the issue. |
463+
| issue | `String` | The issue number. |
464+
358465
#### duplicates
359466

360467
Type: `Array<Object>`
@@ -364,7 +471,7 @@ Each duplicate has the following properties:
364471

365472
| Name | Type | Description |
366473
|--------|----------|---------------------------------------------------------------------------------------|
367-
| raw | `String` | The raw value parsed, for example `Fix #1`. |
474+
| raw | `String` | The raw value parsed, for example `Duplicate of #1`. |
368475
| action | `String` | The keyword used to identify the duplicate, capitalized. |
369476
| slug | `String` | The repository owner and name, for issue referred as `<owner>/<repo>#<issue number>`. |
370477
| prefix | `String` | The prefix used to identify the issue. |
@@ -379,7 +486,7 @@ Each reference has the following properties:
379486

380487
| Name | Type | Description |
381488
|--------|----------|---------------------------------------------------------------------------------------|
382-
| raw | `String` | The raw value parsed, for example `Fix #1`. |
489+
| raw | `String` | The raw value parsed, for example `#1`. |
383490
| slug | `String` | The repository owner and name, for issue referred as `<owner>/<repo>#<issue number>`. |
384491
| prefix | `String` | The prefix used to identify the issue. |
385492
| issue | `String` | The issue number. |
@@ -393,7 +500,7 @@ Each mention has the following properties:
393500

394501
| Name | Type | Description |
395502
|--------|----------|---------------------------------------------|
396-
| raw | `String` | The raw value parsed, for example `Fix #1`. |
503+
| raw | `String` | The raw value parsed, for example `@user`. |
397504
| prefix | `String` | The prefix used to identify the mention. |
398505
| user | `String` | The user name |
399506

index.js

+50-9
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,22 @@ function buildMentionsRegexp({mentionsPrefixes}) {
4242
return `((?:(?:[^\\w\\n\\v\\r]|^)+(?:${join(mentionsPrefixes)})[\\w-\\.]+[^\\W])+)`;
4343
}
4444

45-
function buildRefRegexp({referenceActions, duplicateActions, issuePrefixes, issueURLSegments, hosts}) {
46-
return `(?:(?:[^\\w\\n\\v\\r]|^)+(${join([].concat(referenceActions, duplicateActions))}))?(?:${['[^\\w\\n\\v\\r]|^']
47-
.concat(join(issuePrefixes.concat(issueURLSegments)))
48-
.join('|')})+${hosts.length > 0 ? `(?:${join(hosts)})?` : ''}((?:(?:[\\w-\\.]+)\\/)+(?:[\\w-\\.]+))?(${join(
49-
issuePrefixes.concat(issueURLSegments)
50-
)})(\\d+)(?!\\w)`;
45+
function buildRefRegexp({
46+
referenceActions,
47+
blocksActions,
48+
requiresActions,
49+
parentOfActions,
50+
childOfActions,
51+
duplicateActions,
52+
issuePrefixes,
53+
issueURLSegments,
54+
hosts,
55+
}) {
56+
return `(?:(?:[^\\w\\n\\v\\r]|^)+(${join(
57+
[].concat(referenceActions, blocksActions, requiresActions, parentOfActions, childOfActions, duplicateActions)
58+
)}))?(?:${['[^\\w\\n\\v\\r]|^'].concat(join(issuePrefixes.concat(issueURLSegments))).join('|')})+${
59+
hosts.length > 0 ? `(?:${join(hosts)})?` : ''
60+
}((?:(?:[\\w-\\.]+)\\/)+(?:[\\w-\\.]+))?(${join(issuePrefixes.concat(issueURLSegments))})(\\d+)(?!\\w)`;
5161
}
5262

5363
function buildRegexp(opts) {
@@ -63,9 +73,32 @@ function buildMentionRegexp({mentionsPrefixes}) {
6373
return new RegExp(`(${join(mentionsPrefixes)})([\\w-.]+)`, 'gim');
6474
}
6575

66-
function parse(text, regexp, mentionRegexp, {issuePrefixes, hosts, referenceActions, duplicateActions}) {
76+
function parse(
77+
text,
78+
regexp,
79+
mentionRegexp,
80+
{
81+
issuePrefixes,
82+
hosts,
83+
referenceActions,
84+
blocksActions,
85+
requiresActions,
86+
parentOfActions,
87+
childOfActions,
88+
duplicateActions,
89+
}
90+
) {
6791
let parsed;
68-
const results = {actions: [], refs: [], duplicates: [], mentions: []};
92+
const results = {
93+
actions: [],
94+
blocks: [],
95+
requires: [],
96+
parentOf: [],
97+
childOf: [],
98+
duplicates: [],
99+
refs: [],
100+
mentions: [],
101+
};
69102
let noCodeBlock = inverse(inverse(text.replace(FENCE_BLOCK_REGEXP, '')).replace(CODE_BLOCK_REGEXP, ''));
70103

71104
while (regexp.test(noCodeBlock)) {
@@ -87,6 +120,14 @@ function parse(text, regexp, mentionRegexp, {issuePrefixes, hosts, referenceActi
87120

88121
if (includesIgnoreCase(referenceActions, action)) {
89122
results.actions.push({raw, action, slug, prefix, issue});
123+
} else if (includesIgnoreCase(blocksActions, action)) {
124+
results.blocks.push({raw, action, slug, prefix, issue});
125+
} else if (includesIgnoreCase(requiresActions, action)) {
126+
results.requires.push({raw, action, slug, prefix, issue});
127+
} else if (includesIgnoreCase(parentOfActions, action)) {
128+
results.parentOf.push({raw, action, slug, prefix, issue});
129+
} else if (includesIgnoreCase(childOfActions, action)) {
130+
results.childOf.push({raw, action, slug, prefix, issue});
90131
} else if (includesIgnoreCase(duplicateActions, action)) {
91132
results.duplicates.push({raw, action, slug, prefix, issue});
92133
} else if (issue) {
@@ -150,7 +191,7 @@ module.exports = (options = 'default', overrides = {}) => {
150191

151192
Reflect.defineProperty(results, 'allRefs', {
152193
get() {
153-
return this.actions.concat(this.refs, this.duplicates);
194+
return this.actions.concat(this.refs, this.duplicates, this.blocks, this.requires, this.parentOf, this.childOf);
154195
},
155196
});
156197
return results;

lib/hosts-config.js

+34
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ module.exports = {
22
github: {
33
// https://help.github.com/articles/closing-issues-using-keywords
44
referenceActions: ['close', 'closes', 'closed', 'fix', 'fixes', 'fixed', 'resolve', 'resolves', 'resolved'],
5+
blocksActions: [],
6+
requiresActions: [],
7+
parentOfActions: [],
8+
childOfActions: [],
59
// https://help.github.com/articles/about-duplicate-issues-and-pull-requests
610
duplicateActions: ['Duplicate of'],
711
// https://guides.github.com/features/issues/#notifications
@@ -26,6 +30,10 @@ module.exports = {
2630
'resolved',
2731
'resolving',
2832
],
33+
blocksActions: [],
34+
requiresActions: [],
35+
parentOfActions: [],
36+
childOfActions: [],
2937
duplicateActions: [],
3038
// https://confluence.atlassian.com/bitbucket/mark-up-comments-issues-and-commit-messages-321859781.html
3139
mentionsPrefixes: ['@'],
@@ -54,6 +62,10 @@ module.exports = {
5462
'implemented',
5563
'implementing',
5664
],
65+
blocksActions: [],
66+
requiresActions: [],
67+
parentOfActions: [],
68+
childOfActions: [],
5769
// https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12845
5870
duplicateActions: ['/duplicate'],
5971
// https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected
@@ -63,6 +75,24 @@ module.exports = {
6375
hosts: ['https://gitlab.com'],
6476
issueURLSegments: ['issues', 'merge_requests'],
6577
},
78+
waffle: {
79+
// https://help.waffle.io/dependencies/which-keywords-are-supported-with-dependencies
80+
referenceActions: ['close', 'closes', 'closed', 'fix', 'fixes', 'fixed', 'resolve', 'resolves', 'resolved'],
81+
// https://help.github.com/articles/closing-issues-using-keywords
82+
blocksActions: ['blocks', 'block', 'required by', 'needed by', 'dependency of'],
83+
requiresActions: ['blocked by', 'requires', 'require', 'need', 'needs', 'depends on'],
84+
// https://help.waffle.io/epics/which-keywords-are-supported-with-epics
85+
parentOfActions: ['parent of', 'parent to', 'parent'],
86+
// https://help.waffle.io/epics/which-keywords-are-supported-with-epics
87+
childOfActions: ['child of', 'child to', 'child'],
88+
// https://help.github.com/articles/about-duplicate-issues-and-pull-requests
89+
duplicateActions: ['Duplicate of'],
90+
// https://guides.github.com/features/issues/#notifications
91+
mentionsPrefixes: ['@'],
92+
issuePrefixes: ['#', 'gh-'],
93+
hosts: ['https://github.com'],
94+
issueURLSegments: ['issues', 'pull'],
95+
},
6696
default: {
6797
referenceActions: [
6898
'close',
@@ -82,6 +112,10 @@ module.exports = {
82112
'implemented',
83113
'implementing',
84114
],
115+
blocksActions: ['blocks', 'block', 'required by', 'needed by', 'dependency of'],
116+
requiresActions: ['blocked by', 'requires', 'require', 'need', 'needs', 'depends on'],
117+
parentOfActions: ['parent of', 'parent to', 'parent'],
118+
childOfActions: ['child of', 'child to', 'child'],
85119
duplicateActions: ['Duplicate of', '/duplicate'],
86120
mentionsPrefixes: ['@'],
87121
issuePrefixes: ['#', 'gh-'],

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "issue-parser",
3-
"description": "Parser for Github, GitLab and Bitbucket issues actions, references and mentions",
3+
"description": "Parser for Github, GitLab, Bitbucket and Waffle issues actions, references and mentions",
44
"version": "0.0.0-development",
55
"author": "Pierre Vanduynslager (https://github.com/pvdlg)",
66
"bugs": {
@@ -40,7 +40,8 @@
4040
"pr",
4141
"pull-request",
4242
"references",
43-
"resolve"
43+
"resolve",
44+
"waffle"
4445
],
4546
"license": "MIT",
4647
"main": "index.js",

0 commit comments

Comments
 (0)