@rawdash/connector-github 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -1
- package/dist/index.js +382 -155
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ declare class GitHubActionsConnector extends BaseConnector<GitHubActionsSettings
|
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
32
|
private buildHeaders;
|
|
33
|
+
private get;
|
|
34
|
+
private paginate;
|
|
33
35
|
private syncWorkflowRuns;
|
|
34
36
|
private syncPullRequests;
|
|
35
37
|
private syncIssues;
|
|
@@ -37,7 +39,7 @@ declare class GitHubActionsConnector extends BaseConnector<GitHubActionsSettings
|
|
|
37
39
|
private syncReleases;
|
|
38
40
|
private syncContributors;
|
|
39
41
|
private syncRepoStats;
|
|
40
|
-
sync(
|
|
42
|
+
sync(options: SyncOptions, storage: StorageHandle, signal?: AbortSignal): Promise<void>;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export { GitHubActionsConnector, type GitHubActionsSettings, configFields };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,295 @@
|
|
|
1
|
+
// ../../connector-shared/dist/index.js
|
|
2
|
+
var HttpClientError = class extends Error {
|
|
3
|
+
response;
|
|
4
|
+
constructor(message, response) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = new.target.name;
|
|
7
|
+
this.response = response;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var TransientError = class extends HttpClientError {
|
|
11
|
+
kind = "transient";
|
|
12
|
+
};
|
|
13
|
+
var RateLimitError = class extends HttpClientError {
|
|
14
|
+
kind = "rate_limit";
|
|
15
|
+
retryAfter;
|
|
16
|
+
constructor(message, response, retryAfter) {
|
|
17
|
+
super(message, response);
|
|
18
|
+
this.retryAfter = retryAfter;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var AuthError = class extends HttpClientError {
|
|
22
|
+
kind = "auth";
|
|
23
|
+
};
|
|
24
|
+
var UpstreamBugError = class extends HttpClientError {
|
|
25
|
+
kind = "upstream_bug";
|
|
26
|
+
};
|
|
27
|
+
var ClientBugError = class extends HttpClientError {
|
|
28
|
+
kind = "client_bug";
|
|
29
|
+
};
|
|
30
|
+
function classifyStatus(status) {
|
|
31
|
+
if (status === 429) {
|
|
32
|
+
return "rate_limit";
|
|
33
|
+
}
|
|
34
|
+
if (status === 401 || status === 403) {
|
|
35
|
+
return "auth";
|
|
36
|
+
}
|
|
37
|
+
if (status === 408) {
|
|
38
|
+
return "transient";
|
|
39
|
+
}
|
|
40
|
+
if (status >= 500) {
|
|
41
|
+
return "upstream_bug";
|
|
42
|
+
}
|
|
43
|
+
if (status >= 400) {
|
|
44
|
+
return "client_bug";
|
|
45
|
+
}
|
|
46
|
+
return "client_bug";
|
|
47
|
+
}
|
|
48
|
+
function errorForStatus(message, response, retryAfter) {
|
|
49
|
+
const kind = classifyStatus(response.status);
|
|
50
|
+
switch (kind) {
|
|
51
|
+
case "rate_limit":
|
|
52
|
+
return new RateLimitError(message, response, retryAfter);
|
|
53
|
+
case "auth":
|
|
54
|
+
return new AuthError(message, response);
|
|
55
|
+
case "transient":
|
|
56
|
+
return new TransientError(message, response);
|
|
57
|
+
case "upstream_bug":
|
|
58
|
+
return new UpstreamBugError(message, response);
|
|
59
|
+
case "client_bug":
|
|
60
|
+
return new ClientBugError(message, response);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
var defaultRetryOn = (status, err) => {
|
|
64
|
+
if (err instanceof RateLimitError) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (err instanceof TransientError) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
if (status === null) {
|
|
71
|
+
return err instanceof Error && !(err instanceof HttpClientError);
|
|
72
|
+
}
|
|
73
|
+
if (status === 408 || status === 429) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (status >= 500) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
};
|
|
81
|
+
function parseRetryAfter(headerValue, now = /* @__PURE__ */ new Date()) {
|
|
82
|
+
if (!headerValue) {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
const trimmed = headerValue.trim();
|
|
86
|
+
if (/^\d+$/.test(trimmed)) {
|
|
87
|
+
return new Date(now.getTime() + Number(trimmed) * 1e3);
|
|
88
|
+
}
|
|
89
|
+
const parsed = Date.parse(trimmed);
|
|
90
|
+
if (Number.isNaN(parsed)) {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
return new Date(parsed);
|
|
94
|
+
}
|
|
95
|
+
function sleep(ms, signal) {
|
|
96
|
+
if (signal?.aborted) {
|
|
97
|
+
return Promise.reject(signal.reason ?? new Error("Aborted"));
|
|
98
|
+
}
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
const onAbort = () => {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
reject(signal.reason ?? new Error("Aborted"));
|
|
103
|
+
};
|
|
104
|
+
const timer = setTimeout(() => {
|
|
105
|
+
signal?.removeEventListener("abort", onAbort);
|
|
106
|
+
resolve();
|
|
107
|
+
}, ms);
|
|
108
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
var HTTP_CLIENT_VERSION = "0.0.0";
|
|
112
|
+
var DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;
|
|
113
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
114
|
+
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
115
|
+
var DEFAULT_INITIAL_DELAY_MS = 1e3;
|
|
116
|
+
var DEFAULT_MAX_DELAY_MS = 6e4;
|
|
117
|
+
function mergeHeaders(defaults, overrides) {
|
|
118
|
+
const merged = {};
|
|
119
|
+
for (const [k, v] of Object.entries(defaults)) {
|
|
120
|
+
merged[k.toLowerCase()] = v;
|
|
121
|
+
}
|
|
122
|
+
if (overrides) {
|
|
123
|
+
for (const [k, v] of Object.entries(overrides)) {
|
|
124
|
+
merged[k.toLowerCase()] = v;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return merged;
|
|
128
|
+
}
|
|
129
|
+
function linkTimeoutSignal(parent, timeoutMs) {
|
|
130
|
+
const controller = new AbortController();
|
|
131
|
+
const onParentAbort = () => {
|
|
132
|
+
controller.abort(parent?.reason);
|
|
133
|
+
};
|
|
134
|
+
if (parent) {
|
|
135
|
+
if (parent.aborted) {
|
|
136
|
+
controller.abort(parent.reason);
|
|
137
|
+
} else {
|
|
138
|
+
parent.addEventListener("abort", onParentAbort, { once: true });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const timer = setTimeout(() => {
|
|
142
|
+
controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));
|
|
143
|
+
}, timeoutMs);
|
|
144
|
+
return {
|
|
145
|
+
signal: controller.signal,
|
|
146
|
+
cancel: () => {
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
if (parent) {
|
|
149
|
+
parent.removeEventListener("abort", onParentAbort);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async function readBody(res, parseJson) {
|
|
155
|
+
if (res.status === 204 || res.status === 205) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
159
|
+
if (parseJson && contentType.includes("application/json")) {
|
|
160
|
+
const text = await res.text();
|
|
161
|
+
if (text.length === 0) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return JSON.parse(text);
|
|
165
|
+
}
|
|
166
|
+
return res.text();
|
|
167
|
+
}
|
|
168
|
+
async function request(req, options = {}) {
|
|
169
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
170
|
+
const retry = req.retry ?? {};
|
|
171
|
+
const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
172
|
+
const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
|
|
173
|
+
const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
|
|
174
|
+
const retryOn = retry.retryOn ?? defaultRetryOn;
|
|
175
|
+
const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
176
|
+
const parseJson = req.parseJson ?? true;
|
|
177
|
+
const headers = mergeHeaders(
|
|
178
|
+
{
|
|
179
|
+
"User-Agent": DEFAULT_USER_AGENT,
|
|
180
|
+
Accept: "application/json"
|
|
181
|
+
},
|
|
182
|
+
req.headers
|
|
183
|
+
);
|
|
184
|
+
let lastErr;
|
|
185
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
186
|
+
req.signal?.throwIfAborted();
|
|
187
|
+
const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);
|
|
188
|
+
let res;
|
|
189
|
+
try {
|
|
190
|
+
res = await fetchImpl(req.url, {
|
|
191
|
+
method: req.method ?? "GET",
|
|
192
|
+
headers,
|
|
193
|
+
body: req.body,
|
|
194
|
+
signal
|
|
195
|
+
});
|
|
196
|
+
} catch (err2) {
|
|
197
|
+
cancel();
|
|
198
|
+
if (req.signal?.aborted) {
|
|
199
|
+
throw req.signal.reason ?? err2;
|
|
200
|
+
}
|
|
201
|
+
const error = err2 instanceof Error ? err2 : new Error(String(err2));
|
|
202
|
+
lastErr = error;
|
|
203
|
+
if (attempt < maxAttempts - 1 && retryOn(null, error)) {
|
|
204
|
+
const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);
|
|
205
|
+
await sleep(delay, req.signal);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
throw new TransientError(error.message);
|
|
209
|
+
}
|
|
210
|
+
cancel();
|
|
211
|
+
const body = await readBody(res, parseJson);
|
|
212
|
+
const httpResponse = {
|
|
213
|
+
status: res.status,
|
|
214
|
+
headers: res.headers,
|
|
215
|
+
body
|
|
216
|
+
};
|
|
217
|
+
if (req.rateLimit) {
|
|
218
|
+
const state = req.rateLimit.parse(res.headers);
|
|
219
|
+
if (state) {
|
|
220
|
+
httpResponse.rateLimitState = state;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (res.ok) {
|
|
224
|
+
return httpResponse;
|
|
225
|
+
}
|
|
226
|
+
const retryAfter = parseRetryAfter(res.headers.get("retry-after"));
|
|
227
|
+
const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? "GET"} ${req.url}`;
|
|
228
|
+
const err = errorForStatus(message, httpResponse, retryAfter);
|
|
229
|
+
if (attempt < maxAttempts - 1 && retryOn(res.status, err) && !(err instanceof AuthError) && !(err instanceof ClientBugError)) {
|
|
230
|
+
lastErr = err;
|
|
231
|
+
let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);
|
|
232
|
+
if (err instanceof RateLimitError && retryAfter) {
|
|
233
|
+
const wait = retryAfter.getTime() - Date.now();
|
|
234
|
+
if (wait > 0) {
|
|
235
|
+
delay = Math.min(wait, maxDelayMs);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
await sleep(delay, req.signal);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
throw err;
|
|
242
|
+
}
|
|
243
|
+
throw lastErr ?? new UpstreamBugError("Exhausted retry attempts");
|
|
244
|
+
}
|
|
245
|
+
function computeDelay(attempt, initialDelayMs, maxDelayMs) {
|
|
246
|
+
const base = initialDelayMs * 2 ** attempt;
|
|
247
|
+
const jitter = base * 0.25 * Math.random();
|
|
248
|
+
return Math.min(base + jitter, maxDelayMs);
|
|
249
|
+
}
|
|
250
|
+
var githubRateLimit = {
|
|
251
|
+
parse(h) {
|
|
252
|
+
const remainingRaw = h.get("x-ratelimit-remaining");
|
|
253
|
+
const resetRaw = h.get("x-ratelimit-reset");
|
|
254
|
+
if (remainingRaw === null || resetRaw === null) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
const remaining = Number(remainingRaw);
|
|
258
|
+
const reset = Number(resetRaw);
|
|
259
|
+
if (!Number.isFinite(remaining) || !Number.isFinite(reset) || reset < 0) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
return { remaining, resetAt: new Date(reset * 1e3) };
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
function parseLinkHeader(header) {
|
|
266
|
+
if (!header) {
|
|
267
|
+
return {};
|
|
268
|
+
}
|
|
269
|
+
const result = {};
|
|
270
|
+
for (const part of header.split(",")) {
|
|
271
|
+
const match = part.match(/<([^>]+)>\s*;\s*rel="([^"]+)"/);
|
|
272
|
+
if (match) {
|
|
273
|
+
result[match[2]] = match[1];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
async function* paginateLink(initial, parse) {
|
|
279
|
+
let next = initial.url;
|
|
280
|
+
while (next) {
|
|
281
|
+
const res = await request({
|
|
282
|
+
...initial,
|
|
283
|
+
url: next
|
|
284
|
+
});
|
|
285
|
+
for (const item of parse(res.body)) {
|
|
286
|
+
yield item;
|
|
287
|
+
}
|
|
288
|
+
const links = parseLinkHeader(res.headers.get("link"));
|
|
289
|
+
next = links["next"] ?? null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
1
293
|
// src/github-actions.ts
|
|
2
294
|
import {
|
|
3
295
|
BaseConnector,
|
|
@@ -51,19 +343,34 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
51
343
|
}
|
|
52
344
|
return headers;
|
|
53
345
|
}
|
|
54
|
-
|
|
346
|
+
get(url, signal) {
|
|
347
|
+
const req = {
|
|
348
|
+
url,
|
|
349
|
+
headers: this.buildHeaders(),
|
|
350
|
+
signal,
|
|
351
|
+
rateLimit: githubRateLimit
|
|
352
|
+
};
|
|
353
|
+
return request(req);
|
|
354
|
+
}
|
|
355
|
+
async *paginate(url, signal) {
|
|
356
|
+
yield* paginateLink(
|
|
357
|
+
{
|
|
358
|
+
url,
|
|
359
|
+
headers: this.buildHeaders(),
|
|
360
|
+
signal,
|
|
361
|
+
rateLimit: githubRateLimit
|
|
362
|
+
},
|
|
363
|
+
(body) => body
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
async syncWorkflowRuns(storage, options, signal) {
|
|
55
367
|
const { owner, repo } = this.settings;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const res = await fetch(
|
|
368
|
+
if (options.mode === "latest") {
|
|
369
|
+
const res = await this.get(
|
|
59
370
|
`https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,
|
|
60
|
-
|
|
371
|
+
signal
|
|
61
372
|
);
|
|
62
|
-
|
|
63
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
64
|
-
}
|
|
65
|
-
const data = await res.json();
|
|
66
|
-
const run = data.workflow_runs[0];
|
|
373
|
+
const run = res.body.workflow_runs[0];
|
|
67
374
|
if (run) {
|
|
68
375
|
await storage.event({
|
|
69
376
|
name: "workflow_run",
|
|
@@ -82,20 +389,21 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
82
389
|
}
|
|
83
390
|
return;
|
|
84
391
|
}
|
|
85
|
-
const cutoff =
|
|
392
|
+
const cutoff = options.since ? new Date(options.since).getTime() : null;
|
|
86
393
|
const allEvents = [];
|
|
87
|
-
|
|
88
|
-
|
|
394
|
+
const iter = paginateLink(
|
|
395
|
+
{
|
|
396
|
+
url: `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100`,
|
|
397
|
+
headers: this.buildHeaders(),
|
|
398
|
+
signal,
|
|
399
|
+
rateLimit: githubRateLimit
|
|
400
|
+
},
|
|
401
|
+
(body) => [body]
|
|
402
|
+
);
|
|
403
|
+
let stop = false;
|
|
404
|
+
for await (const page of iter) {
|
|
89
405
|
signal?.throwIfAborted();
|
|
90
|
-
const
|
|
91
|
-
`https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100&page=${page}`,
|
|
92
|
-
{ headers, signal }
|
|
93
|
-
);
|
|
94
|
-
if (!res.ok) {
|
|
95
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
96
|
-
}
|
|
97
|
-
const data = await res.json();
|
|
98
|
-
const runs = data.workflow_runs;
|
|
406
|
+
const runs = page.workflow_runs;
|
|
99
407
|
if (runs.length === 0) {
|
|
100
408
|
break;
|
|
101
409
|
}
|
|
@@ -122,35 +430,22 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
122
430
|
}
|
|
123
431
|
const lastRun = runs.at(-1);
|
|
124
432
|
if (cutoff !== null && new Date(lastRun.created_at).getTime() < cutoff && new Date(lastRun.updated_at).getTime() < cutoff) {
|
|
433
|
+
stop = true;
|
|
434
|
+
}
|
|
435
|
+
if (stop) {
|
|
125
436
|
break;
|
|
126
437
|
}
|
|
127
|
-
page++;
|
|
128
438
|
}
|
|
129
439
|
await storage.events(allEvents, { names: ["workflow_run"] });
|
|
130
440
|
}
|
|
131
441
|
async syncPullRequests(storage, signal) {
|
|
132
442
|
const { owner, repo } = this.settings;
|
|
133
|
-
const headers = this.buildHeaders();
|
|
134
443
|
const allPRs = [];
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
signal
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
{ headers, signal }
|
|
141
|
-
);
|
|
142
|
-
if (!res.ok) {
|
|
143
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
144
|
-
}
|
|
145
|
-
const prs = await res.json();
|
|
146
|
-
if (prs.length === 0) {
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
allPRs.push(...prs);
|
|
150
|
-
if (prs.length < 100) {
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
page++;
|
|
444
|
+
for await (const pr of this.paginate(
|
|
445
|
+
`https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100`,
|
|
446
|
+
signal
|
|
447
|
+
)) {
|
|
448
|
+
allPRs.push(pr);
|
|
154
449
|
}
|
|
155
450
|
await storage.entities(
|
|
156
451
|
allPRs.map((pr) => ({
|
|
@@ -170,17 +465,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
170
465
|
const reviewEdges = [];
|
|
171
466
|
for (const pr of allPRs) {
|
|
172
467
|
signal?.throwIfAborted();
|
|
173
|
-
const res = await
|
|
468
|
+
const res = await this.get(
|
|
174
469
|
`https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,
|
|
175
|
-
|
|
470
|
+
signal
|
|
176
471
|
);
|
|
177
|
-
|
|
178
|
-
throw new Error(
|
|
179
|
-
`GitHub API error fetching reviews for PR #${pr.number}: ${res.status} ${res.statusText}`
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
const reviews = await res.json();
|
|
183
|
-
for (const review of reviews) {
|
|
472
|
+
for (const review of res.body) {
|
|
184
473
|
if (!review.user) {
|
|
185
474
|
continue;
|
|
186
475
|
}
|
|
@@ -190,49 +479,30 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
190
479
|
kind: "reviewed_by",
|
|
191
480
|
to_type: "user",
|
|
192
481
|
to_id: review.user.login,
|
|
193
|
-
attributes: {
|
|
194
|
-
state: review.state
|
|
195
|
-
},
|
|
482
|
+
attributes: { state: review.state },
|
|
196
483
|
updated_at: new Date(review.submitted_at).getTime()
|
|
197
484
|
});
|
|
198
485
|
}
|
|
199
486
|
}
|
|
200
487
|
await storage.edges(reviewEdges, { kinds: ["reviewed_by"] });
|
|
201
488
|
}
|
|
202
|
-
async syncIssues(storage,
|
|
489
|
+
async syncIssues(storage, options, signal) {
|
|
203
490
|
const { owner, repo } = this.settings;
|
|
204
|
-
const
|
|
491
|
+
const url = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);
|
|
492
|
+
url.searchParams.set("state", "all");
|
|
493
|
+
url.searchParams.set("per_page", "100");
|
|
494
|
+
if (options.since) {
|
|
495
|
+
url.searchParams.set("since", options.since);
|
|
496
|
+
}
|
|
205
497
|
const allIssues = [];
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
signal
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
url.searchParams.set("state", "all");
|
|
213
|
-
url.searchParams.set("per_page", "100");
|
|
214
|
-
url.searchParams.set("page", String(page));
|
|
215
|
-
if (request.since) {
|
|
216
|
-
url.searchParams.set("since", request.since);
|
|
217
|
-
}
|
|
218
|
-
const res = await fetch(url.toString(), { headers, signal });
|
|
219
|
-
if (!res.ok) {
|
|
220
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
221
|
-
}
|
|
222
|
-
const issues = await res.json();
|
|
223
|
-
if (issues.length === 0) {
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
for (const issue of issues) {
|
|
227
|
-
if (issue.pull_request !== void 0) {
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
allIssues.push(issue);
|
|
231
|
-
}
|
|
232
|
-
if (issues.length < 100) {
|
|
233
|
-
break;
|
|
498
|
+
for await (const issue of this.paginate(
|
|
499
|
+
url.toString(),
|
|
500
|
+
signal
|
|
501
|
+
)) {
|
|
502
|
+
if (issue.pull_request !== void 0) {
|
|
503
|
+
continue;
|
|
234
504
|
}
|
|
235
|
-
|
|
505
|
+
allIssues.push(issue);
|
|
236
506
|
}
|
|
237
507
|
await storage.entities(
|
|
238
508
|
allIssues.map((issue) => ({
|
|
@@ -256,41 +526,22 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
256
526
|
}
|
|
257
527
|
async syncDeployments(storage, signal) {
|
|
258
528
|
const { owner, repo } = this.settings;
|
|
259
|
-
const headers = this.buildHeaders();
|
|
260
529
|
const allDeployments = [];
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
signal
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
{ headers, signal }
|
|
267
|
-
);
|
|
268
|
-
if (!res.ok) {
|
|
269
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
270
|
-
}
|
|
271
|
-
const deployments = await res.json();
|
|
272
|
-
if (deployments.length === 0) {
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
allDeployments.push(...deployments);
|
|
276
|
-
if (deployments.length < 100) {
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
page++;
|
|
530
|
+
for await (const d of this.paginate(
|
|
531
|
+
`https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100`,
|
|
532
|
+
signal
|
|
533
|
+
)) {
|
|
534
|
+
allDeployments.push(d);
|
|
280
535
|
}
|
|
281
536
|
const entities = [];
|
|
282
537
|
for (const deployment of allDeployments) {
|
|
283
538
|
signal?.throwIfAborted();
|
|
284
|
-
const res = await
|
|
539
|
+
const res = await this.get(
|
|
285
540
|
`https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,
|
|
286
|
-
|
|
541
|
+
signal
|
|
287
542
|
);
|
|
288
|
-
if (!res.ok) {
|
|
289
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
290
|
-
}
|
|
291
|
-
const statuses = await res.json();
|
|
292
543
|
const createdMs = new Date(deployment.created_at).getTime();
|
|
293
|
-
const statusUpdatedMs =
|
|
544
|
+
const statusUpdatedMs = res.body[0]?.updated_at ? new Date(res.body[0].updated_at).getTime() : null;
|
|
294
545
|
entities.push({
|
|
295
546
|
type: "deployment",
|
|
296
547
|
id: String(deployment.id),
|
|
@@ -300,7 +551,7 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
300
551
|
sha: deployment.sha,
|
|
301
552
|
creator: deployment.creator?.login ?? "",
|
|
302
553
|
created_at: createdMs,
|
|
303
|
-
latest_status:
|
|
554
|
+
latest_status: res.body[0]?.state ?? "unknown"
|
|
304
555
|
},
|
|
305
556
|
updated_at: Math.max(createdMs, statusUpdatedMs ?? 0)
|
|
306
557
|
});
|
|
@@ -309,27 +560,12 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
309
560
|
}
|
|
310
561
|
async syncReleases(storage, signal) {
|
|
311
562
|
const { owner, repo } = this.settings;
|
|
312
|
-
const headers = this.buildHeaders();
|
|
313
563
|
const allReleases = [];
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
signal
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
{ headers, signal }
|
|
320
|
-
);
|
|
321
|
-
if (!res.ok) {
|
|
322
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
323
|
-
}
|
|
324
|
-
const releases = await res.json();
|
|
325
|
-
if (releases.length === 0) {
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
allReleases.push(...releases);
|
|
329
|
-
if (releases.length < 100) {
|
|
330
|
-
break;
|
|
331
|
-
}
|
|
332
|
-
page++;
|
|
564
|
+
for await (const r of this.paginate(
|
|
565
|
+
`https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`,
|
|
566
|
+
signal
|
|
567
|
+
)) {
|
|
568
|
+
allReleases.push(r);
|
|
333
569
|
}
|
|
334
570
|
await storage.entities(
|
|
335
571
|
allReleases.map((release) => ({
|
|
@@ -353,22 +589,18 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
353
589
|
}
|
|
354
590
|
async syncContributors(storage, signal) {
|
|
355
591
|
const { owner, repo } = this.settings;
|
|
356
|
-
const headers = this.buildHeaders();
|
|
357
592
|
const contributors = await this.withRetry(
|
|
358
593
|
async (sig) => {
|
|
359
|
-
const res = await
|
|
594
|
+
const res = await this.get(
|
|
360
595
|
`https://api.github.com/repos/${owner}/${repo}/stats/contributors`,
|
|
361
|
-
|
|
596
|
+
sig
|
|
362
597
|
);
|
|
363
598
|
if (res.status === 202) {
|
|
364
599
|
return { status: "retry" };
|
|
365
600
|
}
|
|
366
|
-
if (!res.ok) {
|
|
367
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
368
|
-
}
|
|
369
601
|
return {
|
|
370
602
|
status: "done",
|
|
371
|
-
value:
|
|
603
|
+
value: res.body ?? []
|
|
372
604
|
};
|
|
373
605
|
},
|
|
374
606
|
{ maxAttempts: 15, initialDelayMs: 1e3, maxDelayMs: 1e4, signal }
|
|
@@ -403,24 +635,19 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
403
635
|
}
|
|
404
636
|
async syncRepoStats(storage, signal) {
|
|
405
637
|
const { owner, repo } = this.settings;
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
headers,
|
|
638
|
+
const res = await this.get(
|
|
639
|
+
`https://api.github.com/repos/${owner}/${repo}`,
|
|
409
640
|
signal
|
|
410
|
-
|
|
411
|
-
if (!res.ok) {
|
|
412
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
413
|
-
}
|
|
414
|
-
const data = await res.json();
|
|
641
|
+
);
|
|
415
642
|
await storage.entities(
|
|
416
643
|
[
|
|
417
644
|
{
|
|
418
645
|
type: "repo",
|
|
419
646
|
id: `${owner}/${repo}`,
|
|
420
647
|
attributes: {
|
|
421
|
-
stars:
|
|
422
|
-
forks:
|
|
423
|
-
watchers:
|
|
648
|
+
stars: res.body.stargazers_count,
|
|
649
|
+
forks: res.body.forks_count,
|
|
650
|
+
watchers: res.body.subscribers_count
|
|
424
651
|
},
|
|
425
652
|
updated_at: Date.now()
|
|
426
653
|
}
|
|
@@ -428,11 +655,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
428
655
|
{ types: ["repo"] }
|
|
429
656
|
);
|
|
430
657
|
}
|
|
431
|
-
async sync(
|
|
658
|
+
async sync(options, storage, signal) {
|
|
432
659
|
await this.syncRepoStats(storage, signal);
|
|
433
|
-
await this.syncWorkflowRuns(storage,
|
|
660
|
+
await this.syncWorkflowRuns(storage, options, signal);
|
|
434
661
|
await this.syncPullRequests(storage, signal);
|
|
435
|
-
await this.syncIssues(storage,
|
|
662
|
+
await this.syncIssues(storage, options, signal);
|
|
436
663
|
await this.syncDeployments(storage, signal);
|
|
437
664
|
await this.syncReleases(storage, signal);
|
|
438
665
|
await this.syncContributors(storage, signal);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/github-actions.ts"],"sourcesContent":["import {\n BaseConnector,\n type CredentialsSchema,\n type StorageHandle,\n type SyncOptions,\n defineConfigFields,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n owner: z.string().min(1).meta({\n label: 'Repository owner',\n description: 'GitHub username or organization name.',\n placeholder: 'rawdash',\n }),\n repo: z.string().min(1).meta({\n label: 'Repository',\n description: 'Repository name.',\n placeholder: 'rawdash',\n }),\n token: z.object({ $secret: z.string() }).optional().meta({\n label: 'Personal access token',\n description: 'GitHub PAT with `repo` scope.',\n secret: true,\n }),\n }),\n);\n\nexport interface GitHubActionsSettings {\n owner: string;\n repo: string;\n}\n\ninterface GitHubRunsResponse {\n workflow_runs: Array<{\n id: number;\n name: string;\n conclusion: string | null;\n status: string;\n head_branch: string | null;\n actor: { login: string } | null;\n created_at: string;\n updated_at: string;\n run_attempt: number;\n }>;\n}\n\ninterface GitHubPR {\n number: number;\n title: string;\n state: string;\n draft: boolean;\n user: { login: string };\n created_at: string;\n updated_at: string;\n}\n\ninterface GitHubReview {\n user: { login: string } | null;\n state: string;\n submitted_at: string;\n}\n\ninterface GitHubIssue {\n number: number;\n title: string;\n state: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n user: { login: string };\n created_at: string;\n updated_at: string;\n closed_at: string | null;\n pull_request?: unknown;\n}\n\ninterface GitHubDeployment {\n id: number;\n environment: string;\n ref: string;\n sha: string;\n creator: { login: string } | null;\n created_at: string;\n}\n\ninterface GitHubDeploymentStatus {\n state: string;\n updated_at: string;\n}\n\ninterface GitHubRelease {\n id: number;\n tag_name: string;\n name: string | null;\n draft: boolean;\n prerelease: boolean;\n created_at: string;\n published_at: string | null;\n author: { login: string };\n}\n\ninterface GitHubContributorStats {\n total: number;\n weeks: Array<{ w: number; a: number; d: number; c: number }>;\n author: { login: string };\n}\n\ninterface GitHubRepo {\n stargazers_count: number;\n forks_count: number;\n subscribers_count: number;\n}\n\nconst githubCredentials = {\n token: {\n description: 'GitHub personal access token',\n auth: 'optional' as const,\n },\n} satisfies CredentialsSchema;\n\ntype GitHubCredentials = typeof githubCredentials;\n\nexport class GitHubActionsConnector extends BaseConnector<\n GitHubActionsSettings,\n GitHubCredentials\n> {\n static readonly id = 'github-actions';\n\n static create(input: unknown): GitHubActionsConnector {\n const parsed = configFields.parse(input);\n return new GitHubActionsConnector(\n { owner: parsed.owner, repo: parsed.repo },\n { token: parsed.token },\n );\n }\n\n readonly id = 'github-actions';\n\n override readonly credentials = githubCredentials;\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': 'rawdash/connector-github (+https://rawdash.dev)',\n };\n if (this.creds.token) {\n headers['Authorization'] = `Bearer ${this.creds.token}`;\n }\n return headers;\n }\n\n private async syncWorkflowRuns(\n storage: StorageHandle,\n request: SyncOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n\n if (request.mode === 'latest') {\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const data = (await res.json()) as GitHubRunsResponse;\n const run = data.workflow_runs[0];\n if (run) {\n await storage.event({\n name: 'workflow_run',\n start_ts: new Date(run.created_at).getTime(),\n end_ts: new Date(run.updated_at).getTime(),\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n return;\n }\n\n const cutoff = request.since ? new Date(request.since).getTime() : null;\n const allEvents: Parameters<StorageHandle['events']>[0] = [];\n let page = 1;\n\n while (true) {\n signal?.throwIfAborted();\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100&page=${page}`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const data = (await res.json()) as GitHubRunsResponse;\n const runs = data.workflow_runs;\n if (runs.length === 0) {\n break;\n }\n\n for (const run of runs) {\n const createdMs = new Date(run.created_at).getTime();\n const updatedMs = new Date(run.updated_at).getTime();\n if (cutoff !== null && createdMs < cutoff && updatedMs < cutoff) {\n continue;\n }\n allEvents.push({\n name: 'workflow_run',\n start_ts: createdMs,\n end_ts: updatedMs,\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n\n const lastRun = runs.at(-1)!;\n if (\n cutoff !== null &&\n new Date(lastRun.created_at).getTime() < cutoff &&\n new Date(lastRun.updated_at).getTime() < cutoff\n ) {\n break;\n }\n page++;\n }\n\n await storage.events(allEvents, { names: ['workflow_run'] });\n }\n\n private async syncPullRequests(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n const allPRs: GitHubPR[] = [];\n let page = 1;\n\n while (true) {\n signal?.throwIfAborted();\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100&page=${page}`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const prs = (await res.json()) as GitHubPR[];\n if (prs.length === 0) {\n break;\n }\n allPRs.push(...prs);\n if (prs.length < 100) {\n break;\n }\n page++;\n }\n\n await storage.entities(\n allPRs.map((pr) => ({\n type: 'pull_request',\n id: String(pr.number),\n attributes: {\n title: pr.title,\n state: pr.state,\n draft: pr.draft,\n author: pr.user.login,\n created_at: new Date(pr.created_at).getTime(),\n },\n updated_at: new Date(pr.updated_at).getTime(),\n })),\n { types: ['pull_request'] },\n );\n\n const reviewEdges: Parameters<StorageHandle['edges']>[0] = [];\n for (const pr of allPRs) {\n signal?.throwIfAborted();\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(\n `GitHub API error fetching reviews for PR #${pr.number}: ${res.status} ${res.statusText}`,\n );\n }\n const reviews = (await res.json()) as GitHubReview[];\n for (const review of reviews) {\n if (!review.user) {\n continue;\n }\n reviewEdges.push({\n from_type: 'pull_request',\n from_id: String(pr.number),\n kind: 'reviewed_by',\n to_type: 'user',\n to_id: review.user.login,\n attributes: {\n state: review.state,\n },\n updated_at: new Date(review.submitted_at).getTime(),\n });\n }\n }\n\n await storage.edges(reviewEdges, { kinds: ['reviewed_by'] });\n }\n\n private async syncIssues(\n storage: StorageHandle,\n request: SyncOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n const allIssues: GitHubIssue[] = [];\n let page = 1;\n\n while (true) {\n signal?.throwIfAborted();\n const url = new URL(\n `https://api.github.com/repos/${owner}/${repo}/issues`,\n );\n url.searchParams.set('state', 'all');\n url.searchParams.set('per_page', '100');\n url.searchParams.set('page', String(page));\n if (request.since) {\n url.searchParams.set('since', request.since);\n }\n const res = await fetch(url.toString(), { headers, signal });\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const issues = (await res.json()) as GitHubIssue[];\n if (issues.length === 0) {\n break;\n }\n for (const issue of issues) {\n if (issue.pull_request !== undefined) {\n continue;\n }\n allIssues.push(issue);\n }\n if (issues.length < 100) {\n break;\n }\n page++;\n }\n\n await storage.entities(\n allIssues.map((issue) => ({\n type: 'issue',\n id: String(issue.number),\n attributes: {\n number: issue.number,\n title: issue.title,\n state: issue.state,\n labels: issue.labels.map((l) => l.name),\n assignees: issue.assignees.map((a) => a.login),\n author: issue.user.login,\n created_at: new Date(issue.created_at).getTime(),\n updated_at: new Date(issue.updated_at).getTime(),\n closed_at: issue.closed_at\n ? new Date(issue.closed_at).getTime()\n : null,\n },\n updated_at: new Date(issue.updated_at).getTime(),\n })),\n { types: ['issue'] },\n );\n }\n\n private async syncDeployments(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n const allDeployments: GitHubDeployment[] = [];\n let page = 1;\n\n while (true) {\n signal?.throwIfAborted();\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100&page=${page}`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const deployments = (await res.json()) as GitHubDeployment[];\n if (deployments.length === 0) {\n break;\n }\n allDeployments.push(...deployments);\n if (deployments.length < 100) {\n break;\n }\n page++;\n }\n\n const entities: Parameters<StorageHandle['entities']>[0] = [];\n for (const deployment of allDeployments) {\n signal?.throwIfAborted();\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const statuses = (await res.json()) as GitHubDeploymentStatus[];\n const createdMs = new Date(deployment.created_at).getTime();\n const statusUpdatedMs = statuses[0]?.updated_at\n ? new Date(statuses[0].updated_at).getTime()\n : null;\n entities.push({\n type: 'deployment',\n id: String(deployment.id),\n attributes: {\n environment: deployment.environment,\n ref: deployment.ref,\n sha: deployment.sha,\n creator: deployment.creator?.login ?? '',\n created_at: createdMs,\n latest_status: statuses[0]?.state ?? 'unknown',\n },\n updated_at: Math.max(createdMs, statusUpdatedMs ?? 0),\n });\n }\n\n await storage.entities(entities, { types: ['deployment'] });\n }\n\n private async syncReleases(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n const allReleases: GitHubRelease[] = [];\n let page = 1;\n\n while (true) {\n signal?.throwIfAborted();\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/releases?per_page=100&page=${page}`,\n { headers, signal },\n );\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const releases = (await res.json()) as GitHubRelease[];\n if (releases.length === 0) {\n break;\n }\n allReleases.push(...releases);\n if (releases.length < 100) {\n break;\n }\n page++;\n }\n\n await storage.entities(\n allReleases.map((release) => ({\n type: 'release',\n id: String(release.id),\n attributes: {\n tag_name: release.tag_name,\n name: release.name ?? '',\n draft: release.draft,\n prerelease: release.prerelease,\n created_at: new Date(release.created_at).getTime(),\n published_at: release.published_at\n ? new Date(release.published_at).getTime()\n : null,\n author: release.author.login,\n },\n updated_at: new Date(\n release.published_at ?? release.created_at,\n ).getTime(),\n })),\n { types: ['release'] },\n );\n }\n\n private async syncContributors(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n\n const contributors = await this.withRetry<GitHubContributorStats[]>(\n async (sig) => {\n const res = await fetch(\n `https://api.github.com/repos/${owner}/${repo}/stats/contributors`,\n { headers, signal: sig },\n );\n if (res.status === 202) {\n return { status: 'retry' };\n }\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n return {\n status: 'done',\n value: (await res.json()) as GitHubContributorStats[],\n };\n },\n { maxAttempts: 15, initialDelayMs: 1000, maxDelayMs: 10000, signal },\n );\n\n if (!contributors || contributors.length === 0) {\n if (!contributors) {\n console.warn(\n '[github-actions] Stats endpoint never became ready — skipping contributor sync and keeping previous data.',\n );\n }\n return;\n }\n\n await storage.entities(\n contributors.map((c) => {\n const additions = c.weeks.reduce((sum, w) => sum + w.a, 0);\n const deletions = c.weeks.reduce((sum, w) => sum + w.d, 0);\n const latestWeek = [...c.weeks].reverse().find((w) => w.c > 0);\n return {\n type: 'contributor',\n id: c.author.login,\n attributes: {\n commits: c.total,\n additions,\n deletions,\n latest_commit_at: latestWeek ? latestWeek.w * 1000 : null,\n },\n updated_at: latestWeek ? latestWeek.w * 1000 : 0,\n };\n }),\n { types: ['contributor'] },\n );\n }\n\n private async syncRepoStats(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const headers = this.buildHeaders();\n const res = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {\n headers,\n signal,\n });\n if (!res.ok) {\n throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);\n }\n const data = (await res.json()) as GitHubRepo;\n await storage.entities(\n [\n {\n type: 'repo',\n id: `${owner}/${repo}`,\n attributes: {\n stars: data.stargazers_count,\n forks: data.forks_count,\n watchers: data.subscribers_count,\n },\n updated_at: Date.now(),\n },\n ],\n { types: ['repo'] },\n );\n }\n\n async sync(\n request: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n await this.syncRepoStats(storage, signal);\n await this.syncWorkflowRuns(storage, request, signal);\n await this.syncPullRequests(storage, signal);\n await this.syncIssues(storage, request, signal);\n await this.syncDeployments(storage, signal);\n await this.syncReleases(storage, signal);\n await this.syncContributors(storage, signal);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../connector-shared/src/errors.ts","../../../connector-shared/src/retry.ts","../../../connector-shared/src/version.ts","../../../connector-shared/src/request.ts","../../../connector-shared/src/rate-limit.ts","../../../connector-shared/src/pagination.ts","../src/github-actions.ts"],"sourcesContent":["import type { HttpResponse } from './types';\n\nexport type HttpErrorKind =\n | 'transient'\n | 'rate_limit'\n | 'auth'\n | 'upstream_bug'\n | 'client_bug';\n\nexport abstract class HttpClientError extends Error {\n abstract readonly kind: HttpErrorKind;\n readonly response?: HttpResponse;\n\n constructor(message: string, response?: HttpResponse) {\n super(message);\n this.name = new.target.name;\n this.response = response;\n }\n}\n\nexport class TransientError extends HttpClientError {\n readonly kind = 'transient' as const;\n}\n\nexport class RateLimitError extends HttpClientError {\n readonly kind = 'rate_limit' as const;\n readonly retryAfter?: Date;\n\n constructor(message: string, response?: HttpResponse, retryAfter?: Date) {\n super(message, response);\n this.retryAfter = retryAfter;\n }\n}\n\nexport class AuthError extends HttpClientError {\n readonly kind = 'auth' as const;\n}\n\nexport class UpstreamBugError extends HttpClientError {\n readonly kind = 'upstream_bug' as const;\n}\n\nexport class ClientBugError extends HttpClientError {\n readonly kind = 'client_bug' as const;\n}\n\nexport function classifyStatus(status: number): HttpErrorKind {\n if (status === 429) {\n return 'rate_limit';\n }\n if (status === 401 || status === 403) {\n return 'auth';\n }\n if (status === 408) {\n return 'transient';\n }\n if (status >= 500) {\n return 'upstream_bug';\n }\n if (status >= 400) {\n return 'client_bug';\n }\n return 'client_bug';\n}\n\nexport function errorForStatus(\n message: string,\n response: HttpResponse,\n retryAfter?: Date,\n): HttpClientError {\n const kind = classifyStatus(response.status);\n switch (kind) {\n case 'rate_limit':\n return new RateLimitError(message, response, retryAfter);\n case 'auth':\n return new AuthError(message, response);\n case 'transient':\n return new TransientError(message, response);\n case 'upstream_bug':\n return new UpstreamBugError(message, response);\n case 'client_bug':\n return new ClientBugError(message, response);\n }\n}\n","import { HttpClientError, RateLimitError, TransientError } from './errors';\n\nexport interface RetryPolicy {\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n retryOn?: (status: number | null, err?: Error) => boolean;\n}\n\nexport const defaultRetryOn = (status: number | null, err?: Error): boolean => {\n if (err instanceof RateLimitError) {\n return true;\n }\n if (err instanceof TransientError) {\n return true;\n }\n if (status === null) {\n return err instanceof Error && !(err instanceof HttpClientError);\n }\n if (status === 408 || status === 429) {\n return true;\n }\n if (status >= 500) {\n return true;\n }\n return false;\n};\n\nexport function backoffDelayMs(\n attempt: number,\n policy: Required<Pick<RetryPolicy, 'initialDelayMs' | 'maxDelayMs'>>,\n): number {\n const base = policy.initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, policy.maxDelayMs);\n}\n\nexport function parseRetryAfter(\n headerValue: string | null,\n now: Date = new Date(),\n): Date | undefined {\n if (!headerValue) {\n return undefined;\n }\n const trimmed = headerValue.trim();\n if (/^\\d+$/.test(trimmed)) {\n return new Date(now.getTime() + Number(trimmed) * 1000);\n }\n const parsed = Date.parse(trimmed);\n if (Number.isNaN(parsed)) {\n return undefined;\n }\n return new Date(parsed);\n}\n\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) {\n return Promise.reject(signal.reason ?? new Error('Aborted'));\n }\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal!.reason ?? new Error('Aborted'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","export const HTTP_CLIENT_VERSION = '0.0.0';\n\nexport const DEFAULT_USER_AGENT = `rawdash-connector/${HTTP_CLIENT_VERSION} (+https://rawdash.dev)`;\n","import {\n AuthError,\n ClientBugError,\n HttpClientError,\n RateLimitError,\n TransientError,\n UpstreamBugError,\n errorForStatus,\n} from './errors';\nimport { defaultRetryOn, parseRetryAfter, sleep } from './retry';\nimport type { FetchLike, HttpRequest, HttpResponse } from './types';\nimport { DEFAULT_USER_AGENT } from './version';\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY_MS = 1000;\nconst DEFAULT_MAX_DELAY_MS = 60_000;\n\nexport interface RequestOptions {\n fetch?: FetchLike;\n}\n\nfunction mergeHeaders(\n defaults: Record<string, string>,\n overrides: Record<string, string> | undefined,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(defaults)) {\n merged[k.toLowerCase()] = v;\n }\n if (overrides) {\n for (const [k, v] of Object.entries(overrides)) {\n merged[k.toLowerCase()] = v;\n }\n }\n return merged;\n}\n\nfunction linkTimeoutSignal(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n const controller = new AbortController();\n const onParentAbort = () => {\n controller.abort(parent?.reason);\n };\n if (parent) {\n if (parent.aborted) {\n controller.abort(parent.reason);\n } else {\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n }\n const timer = setTimeout(() => {\n controller.abort(new Error(`Request timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n if (parent) {\n parent.removeEventListener('abort', onParentAbort);\n }\n },\n };\n}\n\nasync function readBody(res: Response, parseJson: boolean): Promise<unknown> {\n if (res.status === 204 || res.status === 205) {\n return null;\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (parseJson && contentType.includes('application/json')) {\n const text = await res.text();\n if (text.length === 0) {\n return null;\n }\n return JSON.parse(text);\n }\n return res.text();\n}\n\nexport async function request<T = unknown>(\n req: HttpRequest,\n options: RequestOptions = {},\n): Promise<HttpResponse<T>> {\n const fetchImpl: FetchLike = options.fetch ?? (globalThis.fetch as FetchLike);\n const retry = req.retry ?? {};\n const maxAttempts = retry.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;\n const initialDelayMs = retry.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;\n const maxDelayMs = retry.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;\n const retryOn = retry.retryOn ?? defaultRetryOn;\n const timeoutMs = req.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const parseJson = req.parseJson ?? true;\n\n const headers = mergeHeaders(\n {\n 'User-Agent': DEFAULT_USER_AGENT,\n Accept: 'application/json',\n },\n req.headers,\n );\n\n let lastErr: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n req.signal?.throwIfAborted();\n\n const { signal, cancel } = linkTimeoutSignal(req.signal, timeoutMs);\n let res: Response;\n try {\n res = await fetchImpl(req.url, {\n method: req.method ?? 'GET',\n headers,\n body: req.body as RequestInit['body'],\n signal,\n });\n } catch (err) {\n cancel();\n if (req.signal?.aborted) {\n throw req.signal.reason ?? err;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n lastErr = error;\n if (attempt < maxAttempts - 1 && retryOn(null, error)) {\n const delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n await sleep(delay, req.signal);\n continue;\n }\n throw new TransientError(error.message);\n }\n cancel();\n\n const body = await readBody(res, parseJson);\n const httpResponse: HttpResponse<T> = {\n status: res.status,\n headers: res.headers,\n body: body as T,\n };\n if (req.rateLimit) {\n const state = req.rateLimit.parse(res.headers);\n if (state) {\n httpResponse.rateLimitState = state;\n }\n }\n\n if (res.ok) {\n return httpResponse;\n }\n\n const retryAfter = parseRetryAfter(res.headers.get('retry-after'));\n const message = `HTTP ${res.status} ${res.statusText} for ${req.method ?? 'GET'} ${req.url}`;\n const err = errorForStatus(message, httpResponse, retryAfter);\n\n if (\n attempt < maxAttempts - 1 &&\n retryOn(res.status, err) &&\n !(err instanceof AuthError) &&\n !(err instanceof ClientBugError)\n ) {\n lastErr = err;\n let delay = computeDelay(attempt, initialDelayMs, maxDelayMs);\n if (err instanceof RateLimitError && retryAfter) {\n const wait = retryAfter.getTime() - Date.now();\n if (wait > 0) {\n delay = Math.min(wait, maxDelayMs);\n }\n }\n await sleep(delay, req.signal);\n continue;\n }\n\n throw err;\n }\n\n throw lastErr ?? new UpstreamBugError('Exhausted retry attempts');\n}\n\nfunction computeDelay(\n attempt: number,\n initialDelayMs: number,\n maxDelayMs: number,\n): number {\n const base = initialDelayMs * 2 ** attempt;\n const jitter = base * 0.25 * Math.random();\n return Math.min(base + jitter, maxDelayMs);\n}\n\nexport { HttpClientError };\n","export interface RateLimitState {\n remaining: number;\n resetAt: Date;\n}\n\nexport interface RateLimitPolicy {\n parse(headers: Headers): RateLimitState | null;\n}\n\nexport const githubRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-remaining');\n const resetRaw = h.get('x-ratelimit-reset');\n if (remainingRaw === null || resetRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n const reset = Number(resetRaw);\n if (!Number.isFinite(remaining) || !Number.isFinite(reset) || reset < 0) {\n return null;\n }\n return { remaining, resetAt: new Date(reset * 1000) };\n },\n};\n\nexport const sentryRateLimit: RateLimitPolicy = {\n parse(h) {\n const concurrent = h.get('x-sentry-rate-limit-remaining');\n const reset = h.get('x-sentry-rate-limit-reset');\n if (concurrent === null || reset === null) {\n return null;\n }\n const remaining = Number(concurrent);\n const resetSec = Number(reset);\n if (\n !Number.isFinite(remaining) ||\n !Number.isFinite(resetSec) ||\n resetSec < 0\n ) {\n return null;\n }\n return { remaining, resetAt: new Date(resetSec * 1000) };\n },\n};\n\nexport const linearRateLimit: RateLimitPolicy = {\n parse(h) {\n const remainingRaw = h.get('x-ratelimit-requests-remaining');\n const resetRaw = h.get('x-ratelimit-requests-reset');\n if (remainingRaw === null) {\n return null;\n }\n const remaining = Number(remainingRaw);\n if (!Number.isFinite(remaining)) {\n return null;\n }\n let resetAt: Date;\n if (resetRaw !== null) {\n const reset = Number(resetRaw);\n if (!Number.isFinite(reset) || reset < 0) {\n return null;\n }\n resetAt = new Date(reset);\n } else {\n resetAt = new Date(Date.now() + 60_000);\n }\n return { remaining, resetAt };\n },\n};\n","import { request } from './request';\nimport type { HttpRequest } from './types';\n\nexport function parseLinkHeader(header: string | null): Record<string, string> {\n if (!header) {\n return {};\n }\n const result: Record<string, string> = {};\n for (const part of header.split(',')) {\n const match = part.match(/<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/);\n if (match) {\n result[match[2]!] = match[1]!;\n }\n }\n return result;\n}\n\nexport async function* paginateLink<T>(\n initial: HttpRequest,\n parse: (body: unknown) => T[],\n): AsyncIterable<T> {\n let next: string | null = initial.url;\n while (next) {\n const res: Awaited<ReturnType<typeof request>> = await request({\n ...initial,\n url: next,\n });\n for (const item of parse(res.body)) {\n yield item;\n }\n const links = parseLinkHeader(res.headers.get('link'));\n next = links['next'] ?? null;\n }\n}\n\nexport async function* paginateCursor<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; nextCursor: string | null },\n buildNext: (req: HttpRequest, cursor: string) => HttpRequest,\n): AsyncIterable<T> {\n let req: HttpRequest = initial;\n while (true) {\n const res = await request(req);\n const { items, nextCursor } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!nextCursor) {\n return;\n }\n req = buildNext(req, nextCursor);\n }\n}\n\nexport async function* paginatePage<T>(\n initial: HttpRequest,\n parse: (body: unknown) => { items: T[]; hasMore: boolean },\n buildPage: (req: HttpRequest, page: number) => HttpRequest,\n): AsyncIterable<T> {\n let page = 1;\n while (true) {\n const req = page === 1 ? initial : buildPage(initial, page);\n const res = await request(req);\n const { items, hasMore } = parse(res.body);\n for (const item of items) {\n yield item;\n }\n if (!hasMore || items.length === 0) {\n return;\n }\n page++;\n }\n}\n","import {\n type HttpRequest,\n type HttpResponse,\n githubRateLimit,\n paginateLink,\n request,\n} from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type CredentialsSchema,\n type StorageHandle,\n type SyncOptions,\n defineConfigFields,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n owner: z.string().min(1).meta({\n label: 'Repository owner',\n description: 'GitHub username or organization name.',\n placeholder: 'rawdash',\n }),\n repo: z.string().min(1).meta({\n label: 'Repository',\n description: 'Repository name.',\n placeholder: 'rawdash',\n }),\n token: z.object({ $secret: z.string() }).optional().meta({\n label: 'Personal access token',\n description: 'GitHub PAT with `repo` scope.',\n secret: true,\n }),\n }),\n);\n\nexport interface GitHubActionsSettings {\n owner: string;\n repo: string;\n}\n\ninterface GitHubRunsResponse {\n workflow_runs: Array<{\n id: number;\n name: string;\n conclusion: string | null;\n status: string;\n head_branch: string | null;\n actor: { login: string } | null;\n created_at: string;\n updated_at: string;\n run_attempt: number;\n }>;\n}\n\ninterface GitHubPR {\n number: number;\n title: string;\n state: string;\n draft: boolean;\n user: { login: string };\n created_at: string;\n updated_at: string;\n}\n\ninterface GitHubReview {\n user: { login: string } | null;\n state: string;\n submitted_at: string;\n}\n\ninterface GitHubIssue {\n number: number;\n title: string;\n state: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n user: { login: string };\n created_at: string;\n updated_at: string;\n closed_at: string | null;\n pull_request?: unknown;\n}\n\ninterface GitHubDeployment {\n id: number;\n environment: string;\n ref: string;\n sha: string;\n creator: { login: string } | null;\n created_at: string;\n}\n\ninterface GitHubDeploymentStatus {\n state: string;\n updated_at: string;\n}\n\ninterface GitHubRelease {\n id: number;\n tag_name: string;\n name: string | null;\n draft: boolean;\n prerelease: boolean;\n created_at: string;\n published_at: string | null;\n author: { login: string };\n}\n\ninterface GitHubContributorStats {\n total: number;\n weeks: Array<{ w: number; a: number; d: number; c: number }>;\n author: { login: string };\n}\n\ninterface GitHubRepo {\n stargazers_count: number;\n forks_count: number;\n subscribers_count: number;\n}\n\nconst githubCredentials = {\n token: {\n description: 'GitHub personal access token',\n auth: 'optional' as const,\n },\n} satisfies CredentialsSchema;\n\ntype GitHubCredentials = typeof githubCredentials;\n\nexport class GitHubActionsConnector extends BaseConnector<\n GitHubActionsSettings,\n GitHubCredentials\n> {\n static readonly id = 'github-actions';\n\n static create(input: unknown): GitHubActionsConnector {\n const parsed = configFields.parse(input);\n return new GitHubActionsConnector(\n { owner: parsed.owner, repo: parsed.repo },\n { token: parsed.token },\n );\n }\n\n readonly id = 'github-actions';\n\n override readonly credentials = githubCredentials;\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n 'User-Agent': 'rawdash/connector-github (+https://rawdash.dev)',\n };\n if (this.creds.token) {\n headers['Authorization'] = `Bearer ${this.creds.token}`;\n }\n return headers;\n }\n\n private get<T>(url: string, signal?: AbortSignal): Promise<HttpResponse<T>> {\n const req: HttpRequest = {\n url,\n headers: this.buildHeaders(),\n signal,\n rateLimit: githubRateLimit,\n };\n return request<T>(req);\n }\n\n private async *paginate<T>(\n url: string,\n signal?: AbortSignal,\n ): AsyncIterable<T> {\n yield* paginateLink<T>(\n {\n url,\n headers: this.buildHeaders(),\n signal,\n rateLimit: githubRateLimit,\n },\n (body) => body as T[],\n );\n }\n\n private async syncWorkflowRuns(\n storage: StorageHandle,\n options: SyncOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n\n if (options.mode === 'latest') {\n const res = await this.get<GitHubRunsResponse>(\n `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,\n signal,\n );\n const run = res.body.workflow_runs[0];\n if (run) {\n await storage.event({\n name: 'workflow_run',\n start_ts: new Date(run.created_at).getTime(),\n end_ts: new Date(run.updated_at).getTime(),\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n return;\n }\n\n const cutoff = options.since ? new Date(options.since).getTime() : null;\n const allEvents: Parameters<StorageHandle['events']>[0] = [];\n\n const iter = paginateLink<GitHubRunsResponse>(\n {\n url: `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100`,\n headers: this.buildHeaders(),\n signal,\n rateLimit: githubRateLimit,\n },\n (body) => [body as GitHubRunsResponse],\n );\n\n let stop = false;\n for await (const page of iter) {\n signal?.throwIfAborted();\n const runs = page.workflow_runs;\n if (runs.length === 0) {\n break;\n }\n\n for (const run of runs) {\n const createdMs = new Date(run.created_at).getTime();\n const updatedMs = new Date(run.updated_at).getTime();\n if (cutoff !== null && createdMs < cutoff && updatedMs < cutoff) {\n continue;\n }\n allEvents.push({\n name: 'workflow_run',\n start_ts: createdMs,\n end_ts: updatedMs,\n attributes: {\n id: run.id,\n workflow_name: run.name,\n conclusion: run.conclusion ?? 'unknown',\n status: run.status,\n branch: run.head_branch ?? '',\n actor: run.actor?.login ?? '',\n run_attempt: run.run_attempt,\n },\n });\n }\n\n const lastRun = runs.at(-1)!;\n if (\n cutoff !== null &&\n new Date(lastRun.created_at).getTime() < cutoff &&\n new Date(lastRun.updated_at).getTime() < cutoff\n ) {\n stop = true;\n }\n if (stop) {\n break;\n }\n }\n\n await storage.events(allEvents, { names: ['workflow_run'] });\n }\n\n private async syncPullRequests(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const allPRs: GitHubPR[] = [];\n\n for await (const pr of this.paginate<GitHubPR>(\n `https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100`,\n signal,\n )) {\n allPRs.push(pr);\n }\n\n await storage.entities(\n allPRs.map((pr) => ({\n type: 'pull_request',\n id: String(pr.number),\n attributes: {\n title: pr.title,\n state: pr.state,\n draft: pr.draft,\n author: pr.user.login,\n created_at: new Date(pr.created_at).getTime(),\n },\n updated_at: new Date(pr.updated_at).getTime(),\n })),\n { types: ['pull_request'] },\n );\n\n const reviewEdges: Parameters<StorageHandle['edges']>[0] = [];\n for (const pr of allPRs) {\n signal?.throwIfAborted();\n const res = await this.get<GitHubReview[]>(\n `https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,\n signal,\n );\n for (const review of res.body) {\n if (!review.user) {\n continue;\n }\n reviewEdges.push({\n from_type: 'pull_request',\n from_id: String(pr.number),\n kind: 'reviewed_by',\n to_type: 'user',\n to_id: review.user.login,\n attributes: { state: review.state },\n updated_at: new Date(review.submitted_at).getTime(),\n });\n }\n }\n\n await storage.edges(reviewEdges, { kinds: ['reviewed_by'] });\n }\n\n private async syncIssues(\n storage: StorageHandle,\n options: SyncOptions,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const url = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);\n url.searchParams.set('state', 'all');\n url.searchParams.set('per_page', '100');\n if (options.since) {\n url.searchParams.set('since', options.since);\n }\n\n const allIssues: GitHubIssue[] = [];\n for await (const issue of this.paginate<GitHubIssue>(\n url.toString(),\n signal,\n )) {\n if (issue.pull_request !== undefined) {\n continue;\n }\n allIssues.push(issue);\n }\n\n await storage.entities(\n allIssues.map((issue) => ({\n type: 'issue',\n id: String(issue.number),\n attributes: {\n number: issue.number,\n title: issue.title,\n state: issue.state,\n labels: issue.labels.map((l) => l.name),\n assignees: issue.assignees.map((a) => a.login),\n author: issue.user.login,\n created_at: new Date(issue.created_at).getTime(),\n updated_at: new Date(issue.updated_at).getTime(),\n closed_at: issue.closed_at\n ? new Date(issue.closed_at).getTime()\n : null,\n },\n updated_at: new Date(issue.updated_at).getTime(),\n })),\n { types: ['issue'] },\n );\n }\n\n private async syncDeployments(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const allDeployments: GitHubDeployment[] = [];\n for await (const d of this.paginate<GitHubDeployment>(\n `https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100`,\n signal,\n )) {\n allDeployments.push(d);\n }\n\n const entities: Parameters<StorageHandle['entities']>[0] = [];\n for (const deployment of allDeployments) {\n signal?.throwIfAborted();\n const res = await this.get<GitHubDeploymentStatus[]>(\n `https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,\n signal,\n );\n const createdMs = new Date(deployment.created_at).getTime();\n const statusUpdatedMs = res.body[0]?.updated_at\n ? new Date(res.body[0].updated_at).getTime()\n : null;\n entities.push({\n type: 'deployment',\n id: String(deployment.id),\n attributes: {\n environment: deployment.environment,\n ref: deployment.ref,\n sha: deployment.sha,\n creator: deployment.creator?.login ?? '',\n created_at: createdMs,\n latest_status: res.body[0]?.state ?? 'unknown',\n },\n updated_at: Math.max(createdMs, statusUpdatedMs ?? 0),\n });\n }\n\n await storage.entities(entities, { types: ['deployment'] });\n }\n\n private async syncReleases(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const allReleases: GitHubRelease[] = [];\n for await (const r of this.paginate<GitHubRelease>(\n `https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`,\n signal,\n )) {\n allReleases.push(r);\n }\n\n await storage.entities(\n allReleases.map((release) => ({\n type: 'release',\n id: String(release.id),\n attributes: {\n tag_name: release.tag_name,\n name: release.name ?? '',\n draft: release.draft,\n prerelease: release.prerelease,\n created_at: new Date(release.created_at).getTime(),\n published_at: release.published_at\n ? new Date(release.published_at).getTime()\n : null,\n author: release.author.login,\n },\n updated_at: new Date(\n release.published_at ?? release.created_at,\n ).getTime(),\n })),\n { types: ['release'] },\n );\n }\n\n private async syncContributors(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n\n const contributors = await this.withRetry<GitHubContributorStats[]>(\n async (sig) => {\n const res = await this.get<GitHubContributorStats[] | null>(\n `https://api.github.com/repos/${owner}/${repo}/stats/contributors`,\n sig,\n );\n if (res.status === 202) {\n return { status: 'retry' };\n }\n return {\n status: 'done',\n value: (res.body ?? []) as GitHubContributorStats[],\n };\n },\n { maxAttempts: 15, initialDelayMs: 1000, maxDelayMs: 10000, signal },\n );\n\n if (!contributors || contributors.length === 0) {\n if (!contributors) {\n console.warn(\n '[github-actions] Stats endpoint never became ready — skipping contributor sync and keeping previous data.',\n );\n }\n return;\n }\n\n await storage.entities(\n contributors.map((c) => {\n const additions = c.weeks.reduce((sum, w) => sum + w.a, 0);\n const deletions = c.weeks.reduce((sum, w) => sum + w.d, 0);\n const latestWeek = [...c.weeks].reverse().find((w) => w.c > 0);\n return {\n type: 'contributor',\n id: c.author.login,\n attributes: {\n commits: c.total,\n additions,\n deletions,\n latest_commit_at: latestWeek ? latestWeek.w * 1000 : null,\n },\n updated_at: latestWeek ? latestWeek.w * 1000 : 0,\n };\n }),\n { types: ['contributor'] },\n );\n }\n\n private async syncRepoStats(\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n const { owner, repo } = this.settings;\n const res = await this.get<GitHubRepo>(\n `https://api.github.com/repos/${owner}/${repo}`,\n signal,\n );\n await storage.entities(\n [\n {\n type: 'repo',\n id: `${owner}/${repo}`,\n attributes: {\n stars: res.body.stargazers_count,\n forks: res.body.forks_count,\n watchers: res.body.subscribers_count,\n },\n updated_at: Date.now(),\n },\n ],\n { types: ['repo'] },\n );\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<void> {\n await this.syncRepoStats(storage, signal);\n await this.syncWorkflowRuns(storage, options, signal);\n await this.syncPullRequests(storage, signal);\n await this.syncIssues(storage, options, signal);\n await this.syncDeployments(storage, signal);\n await this.syncReleases(storage, signal);\n await this.syncContributors(storage, signal);\n }\n}\n"],"mappings":"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","names":["err"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rawdash/connector-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Rawdash connector for GitHub Actions",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -23,11 +23,12 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"zod": "^4.4.3",
|
|
26
|
-
"@rawdash/core": "0.
|
|
26
|
+
"@rawdash/core": "0.7.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"tsup": "^8.0.0",
|
|
30
|
-
"typescript": "^5.7.2"
|
|
30
|
+
"typescript": "^5.7.2",
|
|
31
|
+
"@rawdash/connector-shared": "0.0.0"
|
|
31
32
|
},
|
|
32
33
|
"scripts": {
|
|
33
34
|
"build": "tsup",
|