Skip to content

Commit fba5d0c

Browse files
gh-12942: Fixed github pull requests not getting fetched (gh-12958)
Co-authored-by: mr. m <mr.m@tuta.com>
1 parent 1089e72 commit fba5d0c

1 file changed

Lines changed: 134 additions & 56 deletions

File tree

src/zen/live-folders/providers/GithubLiveFolder.sys.mjs

Lines changed: 134 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
1010
constructor({ id, state, manager }) {
1111
super({ id, state, manager });
1212

13-
this.state.url = "https://github.com/issues/assigned";
1413
this.state.type = state.type;
14+
this.state.url =
15+
this.state.type === "pull-requests"
16+
? "https://github.com/pulls"
17+
: "https://github.com/issues/assigned";
1518

1619
this.state.options = state.options ?? {};
1720
this.state.repos = new Set(state.repos ?? []);
@@ -29,22 +32,106 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
2932
return "zen-live-folder-github-no-filter";
3033
}
3134

32-
const searchParams = this.#buildSearchOptions();
33-
const url = `${this.state.url}?${searchParams}`;
35+
const queries = this.#buildSearchOptions();
36+
const requests = await Promise.all(
37+
queries.map(query => {
38+
const url = new URL(this.state.url);
39+
url.searchParams.set("q", query);
3440

35-
const { text, status } = await this.fetch(url);
41+
if (this.state.type === "pull-requests") {
42+
return this.parsePullRequests(url.href);
43+
}
44+
45+
return this.parseIssues(url.href);
46+
})
47+
);
48+
49+
const combinedItems = new Map();
50+
const combinedActiveRepos = new Set();
51+
52+
for (const { status, items, activeRepos } of requests) {
53+
// Assume no auth
54+
if (status === 404) {
55+
return "zen-live-folder-github-no-auth";
56+
}
57+
58+
if (items) {
59+
items.forEach(item => combinedItems.set(item.id, item));
60+
}
3661

37-
// Assume no auth
38-
if (status === 404) {
39-
return "zen-live-folder-github-no-auth";
62+
if (activeRepos) {
63+
activeRepos.forEach(repo => combinedActiveRepos.add(repo));
64+
}
4065
}
4166

67+
this.state.repos = combinedActiveRepos;
68+
return Array.from(combinedItems.values());
69+
} catch (error) {
70+
console.error("Error fetching or parsing GitHub issues:", error);
71+
return "zen-live-folder-failed-fetch";
72+
}
73+
}
74+
75+
async parsePullRequests(url) {
76+
const { text, status } = await this.fetch(url);
77+
78+
try {
79+
const document = new DOMParser().parseFromString(text, "text/html");
80+
const issues = document.querySelectorAll("div[id^=issue_]");
81+
const items = [];
82+
const activeRepos = [];
83+
84+
if (issues.length) {
85+
const authors = document.querySelectorAll(".opened-by a");
86+
const titles = document.querySelectorAll("a[id^=issue_]");
87+
88+
for (let i = 0; i < issues.length; i++) {
89+
const author = authors[i].textContent;
90+
const title = titles[i].textContent;
91+
92+
const repo = titles[i].previousElementSibling.textContent.trim();
93+
if (repo) {
94+
activeRepos.push(repo);
95+
}
96+
97+
const idMatch = authors[i].parentElement.textContent
98+
.match(/#[0-9]+/)
99+
.shift();
100+
101+
items.push({
102+
title,
103+
subtitle: author,
104+
icon: "chrome://browser/content/zen-images/favicons/github.svg",
105+
url: new URL(titles[i].href, this.state.url),
106+
id: `${repo}${idMatch}`,
107+
});
108+
}
109+
}
110+
111+
return {
112+
status,
113+
114+
items,
115+
activeRepos,
116+
};
117+
} catch (err) {
118+
console.error("Failed to parse Github pull requests", err);
119+
return {
120+
status,
121+
};
122+
}
123+
}
124+
125+
async parseIssues(url) {
126+
const { text, status } = await this.fetch(url);
127+
128+
try {
42129
const document = new DOMParser().parseFromString(text, "text/html");
43130
const issues = document.querySelectorAll(
44131
"div[class^=IssueItem-module__defaultRepoContainer]"
45132
);
46133
const items = [];
47-
const activeRepos = new Set();
134+
const activeRepos = [];
48135

49136
if (issues.length) {
50137
const authors = document.querySelectorAll(
@@ -65,7 +152,7 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
65152

66153
const repo = rawRepo.textContent?.trim();
67154
if (repo) {
68-
activeRepos.add(repo);
155+
activeRepos.push(repo);
69156
}
70157

71158
const numberMatch = rawNumber?.textContent?.match(/[0-9]+/);
@@ -81,76 +168,67 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
81168
}
82169
}
83170

84-
this.state.repos = activeRepos;
85-
86-
return items;
87-
} catch (error) {
88-
console.error("Error fetching or parsing GitHub issues:", error);
89-
return "zen-live-folder-failed-fetch";
171+
return {
172+
status,
173+
174+
items,
175+
activeRepos,
176+
};
177+
} catch (err) {
178+
console.error("Failed to parse Github Issues", err);
179+
return {
180+
status,
181+
};
90182
}
91183
}
92184

93185
#buildSearchOptions() {
94-
let searchParams = new URLSearchParams();
186+
const baseQuery = [
187+
this.state.type === "pull-requests" ? "is:pr" : "is:issue",
188+
"state:open",
189+
"sort:updated-desc",
190+
];
191+
95192
const options = [
96193
{
97-
value: "state:open",
98-
enabled: true,
194+
value: "author:@me",
195+
enabled: this.state.options.authorMe ?? false,
99196
},
100197
{
101-
value: "sort:updated-desc",
102-
enabled: true,
198+
value: "assignee:@me",
199+
enabled: this.state.options.assignedMe ?? true,
200+
},
201+
{
202+
value: "review-requested:@me",
203+
enabled: this.state.options.reviewRequested ?? false,
103204
},
104-
[
105-
{
106-
value: "is:pr",
107-
enabled: this.state.type === "pull-requests",
108-
},
109-
{
110-
value: "is:issue",
111-
enabled: this.state.type === "issues",
112-
},
113-
],
114-
[
115-
{
116-
value: "author:@me",
117-
enabled: this.state.options.authorMe ?? false,
118-
},
119-
{
120-
value: "assignee:@me",
121-
enabled: this.state.options.assignedMe ?? true,
122-
},
123-
{
124-
value: "review-requested:@me",
125-
enabled: this.state.options.reviewRequested ?? false,
126-
},
127-
],
128205
];
129206

130207
const excluded = this.state.options.repoExcludes;
131208
for (const repo of excluded) {
132209
if (repo && repo.trim()) {
133-
options.push({ value: `-repo:${repo.trim()}`, enabled: true });
210+
baseQuery.push(`-repo:${repo.trim()}`);
134211
}
135212
}
136213

137-
let outputString = "";
214+
const queries = [];
138215
for (const option of options) {
139-
if (Array.isArray(option)) {
140-
const enabledOptions = option.filter(x => x.enabled).map(x => x.value);
141-
if (enabledOptions.length) {
142-
outputString += ` (${enabledOptions.join(" OR ")}) `;
143-
}
144-
continue;
216+
if (option.enabled) {
217+
queries.push(option.value);
145218
}
219+
}
146220

147-
if (option.enabled) {
148-
outputString += ` ${option.value} `;
221+
const searchParams = [];
222+
if (this.state.type === "pull-requests") {
223+
for (const query of queries) {
224+
searchParams.push(`${baseQuery.join(" ")} ${query}`);
149225
}
226+
227+
return searchParams;
150228
}
151229

152-
searchParams.set("q", outputString.trim().replace(/ +(?= )/g, ""));
153-
return searchParams.toString();
230+
// type: issues
231+
return [`${baseQuery.join(" ")} ${queries.join(" OR ")}`];
154232
}
155233

156234
get options() {

0 commit comments

Comments
 (0)