generated from ubiquity/ts-template
-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathindex.ts
148 lines (136 loc) · 5.61 KB
/
index.ts
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import dotenv from "dotenv";
import twitter from "./helpers/twitter";
import {
DEVPOOL_OWNER_NAME,
DEVPOOL_REPO_NAME,
forceCloseMissingIssues,
getAllIssues,
getDevpoolIssueLabels,
getIssueByLabel,
getProjectUrls,
getRepoCredentials,
getSocialMediaText,
GitHubIssue,
GitHubLabel,
checkIfForked,
LABELS,
octokit,
} from "./helpers/github";
// init octokit
dotenv.config();
/**
* Main function
* TODO: retry on rate limit error
* TODO: handle project deletion
*/
async function main() {
try {
// get devpool issues
const devpoolIssues: GitHubIssue[] = await getAllIssues(DEVPOOL_OWNER_NAME, DEVPOOL_REPO_NAME);
// aggregate projects.urls and opt settings
const projectUrls = await getProjectUrls();
// aggregate all project issues
const allProjectIssues: GitHubIssue[] = [];
const isFork = await checkIfForked();
// for each project URL
for (const projectUrl of projectUrls) {
// get owner and repository names from project URL
const [ownerName, repoName] = getRepoCredentials(projectUrl);
// get all project issues (opened and closed)
const projectIssues: GitHubIssue[] = await getAllIssues(ownerName, repoName);
// aggregate all project issues
allProjectIssues.push(...projectIssues);
// for all issues
for (const projectIssue of projectIssues) {
// if issue exists in devpool
const devpoolIssue = getIssueByLabel(devpoolIssues, `id: ${projectIssue.node_id}`);
const body = isFork ? projectIssue.html_url.replace("https://github.com", "https://www.github.com") : projectIssue.html_url;
if (devpoolIssue) {
// If project issue doesn't have the "Price" label (i.e. it has been removed) then close
// the devpool issue if it is not already closed, no need to pollute devpool repo with draft issues
if (!(projectIssue.labels as GitHubLabel[]).some((label) => label.name.includes(LABELS.PRICE))) {
if (devpoolIssue.state === "open") {
await octokit.rest.issues.update({
owner: DEVPOOL_OWNER_NAME,
repo: DEVPOOL_REPO_NAME,
issue_number: devpoolIssue.number,
state: "closed",
});
console.log(`Closed (price label not set): ${devpoolIssue.html_url} (${projectIssue.html_url})`);
} else {
console.log(`Already closed (price label not set): ${devpoolIssue.html_url} (${projectIssue.html_url})`);
}
continue;
}
// prepare for issue updating
const isDevpoolUnavailableLabel = (devpoolIssue.labels as GitHubLabel[])?.some((label) => label.name === LABELS.UNAVAILABLE);
const devpoolIssueLabelsStringified = (devpoolIssue.labels as GitHubLabel[])
.map((label) => label.name)
.sort()
.toString();
const projectIssueLabelsStringified = getDevpoolIssueLabels(projectIssue, projectUrl).sort().toString();
// Update devpool issue if any of the following has been updated:
// - issue title
// - issue state (open/closed)
// - assignee (exists or not)
// - repository name (devpool issue body contains a partner project issue URL)
// - any label
if (
devpoolIssue.title !== projectIssue.title ||
devpoolIssue.state !== projectIssue.state ||
(!isDevpoolUnavailableLabel && projectIssue.assignee?.login) ||
(isDevpoolUnavailableLabel && !projectIssue.assignee?.login) ||
devpoolIssue.body !== projectIssue.html_url ||
devpoolIssueLabelsStringified !== projectIssueLabelsStringified
) {
await octokit.rest.issues.update({
owner: DEVPOOL_OWNER_NAME,
repo: DEVPOOL_REPO_NAME,
issue_number: devpoolIssue.number,
title: projectIssue.title,
body,
state: projectIssue.state as "open" | "closed",
labels: getDevpoolIssueLabels(projectIssue, projectUrl),
});
console.log(`Updated: ${devpoolIssue.html_url} (${projectIssue.html_url})`);
} else {
console.log(`No updates: ${devpoolIssue.html_url} (${projectIssue.html_url})`);
}
} else {
// issue does not exist in devpool
// if issue is "closed" then skip it, no need to copy/paste already "closed" issues
if (projectIssue.state === "closed") continue;
// if issue doesn't have the "Price" label then skip it, no need to pollute repo with draft issues
if (!(projectIssue.labels as GitHubLabel[]).some((label) => label.name.includes(LABELS.PRICE))) continue;
// create a new issue
const createdIssue = await octokit.rest.issues.create({
owner: DEVPOOL_OWNER_NAME,
repo: DEVPOOL_REPO_NAME,
title: projectIssue.title,
body,
labels: getDevpoolIssueLabels(projectIssue, projectUrl),
});
console.log(`Created: ${createdIssue.data.html_url} (${projectIssue.html_url})`);
// post to social media
const socialMediaText = getSocialMediaText(createdIssue.data);
await twitter.postTweet(socialMediaText);
}
}
}
// close missing issues
await forceCloseMissingIssues(devpoolIssues, allProjectIssues);
} catch (err) {
console.error(err);
}
}
void (async () => {
try {
await main();
} catch (error) {
console.error(error);
}
})();
// Expose the main only for testing purposes
if (process.env.NODE_ENV === "test") {
exports.main = main;
}