-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquery.mjs
148 lines (115 loc) · 4.6 KB
/
query.mjs
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 { Octokit } from "octokit";
import * as fs from 'fs';
import { execSync } from "child_process";
const loadFromJsonfile = (filename) => {
const data = fs.readFileSync(filename, 'utf8');
return JSON.parse(data);
}
const includeWhitelisted = (url) => {
return whitelist.includes(url);
}
const includeHasCitationcff = async (url) => {
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const { data: { default_branch } } = await octokit.request('GET /repos/{owner}/{repo}', { owner, repo });
const { data: { tree } } = await octokit.rest.git.getTree({
owner,
repo,
tree_sha: default_branch
});
return tree.filter(treeitem => treeitem.path == 'CITATION.cff').length == 1;
}
const includeHasValidcff = async (url) => {
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const { data: { default_branch } } = await octokit.request('GET /repos/{owner}/{repo}', { owner, repo });
const dockerCommand = `docker run --rm -i citationcff/cffconvert:2.0.0 --validate --url ${url}/tree/${default_branch}`;
const outputWhenValid = "Citation metadata are valid according to schema";
let result;
try {
result = execSync(dockerCommand, {stdio: ['pipe', 'pipe', 'ignore']});
} catch {
return false;
}
if (result === null) {
return false;
}
return result.toString().startsWith(outputWhenValid);
}
const includeUsesPullRequests = async (url) => {
if (npull_requests_minimum > 30) {
console.warn("Filter function does not account for pagination of the API--results may be affected.");
}
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const pull_requests = await octokit.rest.pulls.list({
owner,
repo,
state: 'all'
});
const npull_requests = pull_requests.data.length;
return npull_requests >= npull_requests_minimum;
}
const includeUsesWorkflows = async (url) => {
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const { data: { total_count: nworkflows } } = await octokit.rest.actions.listRepoWorkflows({
owner,
repo,
});
return nworkflows >= nworkflows_minimum;
}
const hasMultipleChangesToCitationcff = async (url) => {
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const commits = await octokit.rest.repos.listCommits({
owner,
repo,
path: 'CITATION.cff'
});
return commits.data.length > 1
}
const hasRecentCommits = async (url) => {
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const commits = await octokit.rest.repos.listCommits({
owner,
repo,
per_page: 1
});
const commit_date = new Date(commits.data[0].commit.author.date);
const elapsed = Date.now() - commit_date
return elapsed <= inactivity_threshold
}
const hasSufficientContributors = async (url) => {
const [ owner, repo, ...unuseds ] = url.slice("https://github.com/".length).split('/');
const contributors = await octokit.rest.repos.listContributors({
owner,
repo,
});
const ncontributors = contributors.data
.filter(contributor => contributor.contributions >= ncontributions_minimum)
.length
return ncontributors >= ncontributors_minimum;
}
const filterAsync = async (arr, asyncCallback) => {
const promises = arr.map(asyncCallback);
const results = await Promise.all(promises);
return results.map((result, index) => {
return {
result: result,
value: arr[index]
}
})
.filter(item => item.result === true)
.map(item => item.value);
}
const nworkflows_minimum = 1;
const npull_requests_minimum = 5;
const inactivity_threshold = 12 * 30 * 24 * 60 * 60 * 1000 // X months in milliseconds -> X months * 30 days/month * 24 hours/day * 60 min/hour * 60 sec/min * 1000
const ncontributors_minimum = 3;
const ncontributions_minimum = 5;
const octokit = new Octokit({auth: process.env.GITHUB_TOKEN});
let urls = loadFromJsonfile('./rsd-urls.json');
urls = await filterAsync(urls, includeHasCitationcff);
urls = await filterAsync(urls, includeUsesPullRequests);
urls = await filterAsync(urls, hasMultipleChangesToCitationcff);
urls = await filterAsync(urls, includeUsesWorkflows);
urls = await filterAsync(urls, hasRecentCommits);
urls = await filterAsync(urls, hasSufficientContributors);
urls = await filterAsync(urls, includeHasValidcff);
urls.forEach(url => console.log(url))