Extract and display issues linked in the PR

This commit is contained in:
Yuri Sizov
2021-09-05 23:48:27 +03:00
parent e0902c487d
commit 6cf7457c2a
3 changed files with 90 additions and 2 deletions

View File

@@ -8,7 +8,15 @@ const authors = {};
const pulls = [];
let page_count = 1;
const LINK_RE = /&page=([0-9]+)/g;
const API_LINK_RE = /&page=([0-9]+)/g;
// List of the keywords provided by https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
const GH_MAGIC_KEYWORDS = [
"close", "closes", "closed",
"fix", "fixes", "fixed",
"resolve", "resolves", "resolved",
];
const GH_MAGIC_RE = RegExp("(" + GH_MAGIC_KEYWORDS.join("|") + ") ([a-z0-9-_]+/[a-z0-9-_]+)?#([0-9]+)", "gi");
const GH_MAGIC_FULL_RE = RegExp("(" + GH_MAGIC_KEYWORDS.join("|") + ") https://github.com/([a-z0-9-_]+/[a-z0-9-_]+)/issues/([0-9]+)", "gi");
async function fetchPulls(page) {
try {
@@ -25,7 +33,7 @@ async function fetchPulls(page) {
const links = res.headers.get("link").split(",");
links.forEach((link) => {
if (link.includes('rel="last"')) {
const matches = LINK_RE.exec(link);
const matches = API_LINK_RE.exec(link);
if (matches && matches[1]) {
page_count = Number(matches[1]);
}
@@ -61,6 +69,7 @@ function processPulls(pullsRaw) {
"labels": [],
"milestone": null,
"links": [],
"teams": [],
"reviewers": [],
@@ -105,6 +114,9 @@ function processPulls(pullsRaw) {
return 0;
});
// Look for linked issues in the body.
pr.links = extractLinkedIssues(item.body);
// Add teams, if available.
if (item.requested_teams.length > 0) {
item.requested_teams.forEach((teamItem) => {
@@ -180,6 +192,44 @@ function processPulls(pullsRaw) {
});
}
function extractLinkedIssues(pullBody) {
const links = [];
if (!pullBody) {
return links;
}
const matches = [
...pullBody.matchAll(GH_MAGIC_RE),
...pullBody.matchAll(GH_MAGIC_FULL_RE)
];
matches.forEach((item) => {
let repository = item[2];
if (!repository) {
repository = "godotengine/godot";
}
let keyword = item[1].toLowerCase();
if (keyword.startsWith("clo")) {
keyword = "closes";
} else if (keyword.startsWith("fix")) {
keyword = "fixes";
} else if (keyword.startsWith("reso")) {
keyword = "resolves";
}
links.push({
"full_match": item[0],
"keyword": keyword,
"repo": repository,
"issue": item[3],
"url": `https://github.com/${repository}/issues/${item[3]}`,
});
});
return links;
}
async function main() {
console.log("[*] Building local pull request database.");

View File

@@ -128,6 +128,16 @@ export default class PullRequestItem extends LitElement {
color: var(--draft-font-color);
}
:host .pr-links {
font-size: 13px;
margin-top: 8px;
}
:host .pr-link {
font-weight: 700;
white-space: nowrap;
}
:host .pr-stats {
background-color: var(--stats-background-color);
border-radius: 4px;
@@ -208,6 +218,7 @@ export default class PullRequestItem extends LitElement {
@property({ type: Array }) labels = [];
@property({ type: String, reflect: true }) milestone = '';
@property({ type: String, reflect: true }) branch = '';
@property({ type: Array }) links = [];
@property({ type: String }) created_at = '';
@property({ type: String }) updated_at = '';
@property({ type: Object }) author = null;
@@ -330,6 +341,32 @@ export default class PullRequestItem extends LitElement {
</div>
</div>
${(this.links.length > 0 ? html`
<div class="pr-links">
<span>linked issues: </span>
${this.links.map((item, index) => {
let issueRef = "#" + item.issue;
if (item.repo !== "godotengine/godot") {
issueRef = item.repo + issueRef;
}
return html`
${(index > 0 ? html`
<span> · </span>
` : '')}
<a
class="pr-link"
href="${item.url}"
target="_blank"
title="Open the issue ${issueRef} which this PR ${item.keyword}"
>
${issueRef}
</a>
`
})}
</div>
` : '')}
<div class="pr-stats">
<div
class="pr-stat"

View File

@@ -300,6 +300,7 @@ export default class PullRequestList extends LitElement {
.labels="${item.labels}"
.milestone="${item.milestone}"
.branch="${item.target_branch}"
.links="${item.links}"
.created_at="${item.created_at}"
.updated_at="${item.updated_at}"