mirror of
https://github.com/godotengine/godot-team-reports.git
synced 2025-12-31 13:48:17 +03:00
Extract and display issues linked in the PR
This commit is contained in:
@@ -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.");
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user