This repository was archived by the owner on Mar 4, 2021. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathissues.ts
More file actions
105 lines (93 loc) · 2.54 KB
/
issues.ts
File metadata and controls
105 lines (93 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { requestData } from './utils/graphql.js';
import { TTLCache } from './utils/cache.js';
type IssueState = 'OPEN' | 'CLOSED';
type Label = { name: string; color: string };
interface GraphQLResponse {
repository: {
[issue: string]: {
title: string;
state: IssueState;
bodyHTML: string;
labels: {
nodes: Label[];
};
};
};
}
export interface Issue {
title: string;
state: IssueState;
bodyHTML: string;
labels: Label[];
}
const cacheDuration = 12 * 60 * 60 * 1000; // 12 hours
const cache = new TTLCache<string, Issue>(cacheDuration);
/**
* @param owner Repository owner/organization
* @param name Repository name
* @param issues List of issue numbers to get details for
*/
export async function getIssues(owner: string, name: string, issues: number[]) {
const result: { [issueNumber: string]: Issue | null } = {};
const issuesToFetch = [];
for (const issueNumber of issues) {
const cacheKey = createCacheKey(owner, name, issueNumber);
const cachedData = cache.get(cacheKey);
if (cachedData) {
result[issueNumber] = cachedData;
} else {
issuesToFetch.push(issueNumber);
}
}
if (!issuesToFetch.length) return result;
const query = createQuery(issuesToFetch);
const response: GraphQLResponse = await requestData(query, { owner, name });
if (!response.repository) {
return null;
}
for (const [id, details] of Object.entries(response.repository)) {
const issueNumber = antiAlias(id);
if (!details) {
result[issueNumber] = null;
} else {
const issue = { ...details, labels: details.labels.nodes };
result[issueNumber] = issue;
const cacheKey = createCacheKey(owner, name, issueNumber);
cache.set(cacheKey, issue);
}
}
return result;
}
function createQuery(issues: number[]) {
const subQueries = issues.map(
issue => `${alias(issue)}: issue(number: ${issue}) { ...issue }`,
);
return `
query($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
${subQueries.join('\n ')}
}
}
fragment issue on Issue {
title
state
bodyHTML
labels(first: 10) {
nodes {
name
color
}
}
}`;
}
// sending number in GraphQL query alias isn't allowed
function alias(issue: number) {
return `i${issue}`;
}
// opposite of alias
function antiAlias(id: string) {
return parseInt(id.slice(1));
}
function createCacheKey(owner: string, name: string, issue: number) {
return `${owner}/${name}/${issue}`;
}