@rawdash/connector-github 0.6.0 → 0.7.0
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 +97 -156
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
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
|
@@ -3,6 +3,11 @@ import {
|
|
|
3
3
|
BaseConnector,
|
|
4
4
|
defineConfigFields
|
|
5
5
|
} from "@rawdash/core";
|
|
6
|
+
import {
|
|
7
|
+
githubRateLimit,
|
|
8
|
+
paginateLink,
|
|
9
|
+
request
|
|
10
|
+
} from "@rawdash/http-client";
|
|
6
11
|
import { z } from "zod";
|
|
7
12
|
var configFields = defineConfigFields(
|
|
8
13
|
z.object({
|
|
@@ -43,26 +48,42 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
43
48
|
buildHeaders() {
|
|
44
49
|
const headers = {
|
|
45
50
|
Accept: "application/vnd.github+json",
|
|
46
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
51
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
52
|
+
"User-Agent": "rawdash/connector-github (+https://rawdash.dev)"
|
|
47
53
|
};
|
|
48
54
|
if (this.creds.token) {
|
|
49
55
|
headers["Authorization"] = `Bearer ${this.creds.token}`;
|
|
50
56
|
}
|
|
51
57
|
return headers;
|
|
52
58
|
}
|
|
53
|
-
|
|
59
|
+
get(url, signal) {
|
|
60
|
+
const req = {
|
|
61
|
+
url,
|
|
62
|
+
headers: this.buildHeaders(),
|
|
63
|
+
signal,
|
|
64
|
+
rateLimit: githubRateLimit
|
|
65
|
+
};
|
|
66
|
+
return request(req);
|
|
67
|
+
}
|
|
68
|
+
async *paginate(url, signal) {
|
|
69
|
+
yield* paginateLink(
|
|
70
|
+
{
|
|
71
|
+
url,
|
|
72
|
+
headers: this.buildHeaders(),
|
|
73
|
+
signal,
|
|
74
|
+
rateLimit: githubRateLimit
|
|
75
|
+
},
|
|
76
|
+
(body) => body
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
async syncWorkflowRuns(storage, options, signal) {
|
|
54
80
|
const { owner, repo } = this.settings;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const res = await fetch(
|
|
81
|
+
if (options.mode === "latest") {
|
|
82
|
+
const res = await this.get(
|
|
58
83
|
`https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,
|
|
59
|
-
|
|
84
|
+
signal
|
|
60
85
|
);
|
|
61
|
-
|
|
62
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
63
|
-
}
|
|
64
|
-
const data = await res.json();
|
|
65
|
-
const run = data.workflow_runs[0];
|
|
86
|
+
const run = res.body.workflow_runs[0];
|
|
66
87
|
if (run) {
|
|
67
88
|
await storage.event({
|
|
68
89
|
name: "workflow_run",
|
|
@@ -81,20 +102,21 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
81
102
|
}
|
|
82
103
|
return;
|
|
83
104
|
}
|
|
84
|
-
const cutoff =
|
|
105
|
+
const cutoff = options.since ? new Date(options.since).getTime() : null;
|
|
85
106
|
const allEvents = [];
|
|
86
|
-
|
|
87
|
-
|
|
107
|
+
const iter = paginateLink(
|
|
108
|
+
{
|
|
109
|
+
url: `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100`,
|
|
110
|
+
headers: this.buildHeaders(),
|
|
111
|
+
signal,
|
|
112
|
+
rateLimit: githubRateLimit
|
|
113
|
+
},
|
|
114
|
+
(body) => [body]
|
|
115
|
+
);
|
|
116
|
+
let stop = false;
|
|
117
|
+
for await (const page of iter) {
|
|
88
118
|
signal?.throwIfAborted();
|
|
89
|
-
const
|
|
90
|
-
`https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=100&page=${page}`,
|
|
91
|
-
{ headers, signal }
|
|
92
|
-
);
|
|
93
|
-
if (!res.ok) {
|
|
94
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
95
|
-
}
|
|
96
|
-
const data = await res.json();
|
|
97
|
-
const runs = data.workflow_runs;
|
|
119
|
+
const runs = page.workflow_runs;
|
|
98
120
|
if (runs.length === 0) {
|
|
99
121
|
break;
|
|
100
122
|
}
|
|
@@ -121,35 +143,22 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
121
143
|
}
|
|
122
144
|
const lastRun = runs.at(-1);
|
|
123
145
|
if (cutoff !== null && new Date(lastRun.created_at).getTime() < cutoff && new Date(lastRun.updated_at).getTime() < cutoff) {
|
|
146
|
+
stop = true;
|
|
147
|
+
}
|
|
148
|
+
if (stop) {
|
|
124
149
|
break;
|
|
125
150
|
}
|
|
126
|
-
page++;
|
|
127
151
|
}
|
|
128
152
|
await storage.events(allEvents, { names: ["workflow_run"] });
|
|
129
153
|
}
|
|
130
154
|
async syncPullRequests(storage, signal) {
|
|
131
155
|
const { owner, repo } = this.settings;
|
|
132
|
-
const headers = this.buildHeaders();
|
|
133
156
|
const allPRs = [];
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
signal
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{ headers, signal }
|
|
140
|
-
);
|
|
141
|
-
if (!res.ok) {
|
|
142
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
143
|
-
}
|
|
144
|
-
const prs = await res.json();
|
|
145
|
-
if (prs.length === 0) {
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
allPRs.push(...prs);
|
|
149
|
-
if (prs.length < 100) {
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
page++;
|
|
157
|
+
for await (const pr of this.paginate(
|
|
158
|
+
`https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=100`,
|
|
159
|
+
signal
|
|
160
|
+
)) {
|
|
161
|
+
allPRs.push(pr);
|
|
153
162
|
}
|
|
154
163
|
await storage.entities(
|
|
155
164
|
allPRs.map((pr) => ({
|
|
@@ -169,17 +178,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
169
178
|
const reviewEdges = [];
|
|
170
179
|
for (const pr of allPRs) {
|
|
171
180
|
signal?.throwIfAborted();
|
|
172
|
-
const res = await
|
|
181
|
+
const res = await this.get(
|
|
173
182
|
`https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,
|
|
174
|
-
|
|
183
|
+
signal
|
|
175
184
|
);
|
|
176
|
-
|
|
177
|
-
throw new Error(
|
|
178
|
-
`GitHub API error fetching reviews for PR #${pr.number}: ${res.status} ${res.statusText}`
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
const reviews = await res.json();
|
|
182
|
-
for (const review of reviews) {
|
|
185
|
+
for (const review of res.body) {
|
|
183
186
|
if (!review.user) {
|
|
184
187
|
continue;
|
|
185
188
|
}
|
|
@@ -189,49 +192,30 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
189
192
|
kind: "reviewed_by",
|
|
190
193
|
to_type: "user",
|
|
191
194
|
to_id: review.user.login,
|
|
192
|
-
attributes: {
|
|
193
|
-
state: review.state
|
|
194
|
-
},
|
|
195
|
+
attributes: { state: review.state },
|
|
195
196
|
updated_at: new Date(review.submitted_at).getTime()
|
|
196
197
|
});
|
|
197
198
|
}
|
|
198
199
|
}
|
|
199
200
|
await storage.edges(reviewEdges, { kinds: ["reviewed_by"] });
|
|
200
201
|
}
|
|
201
|
-
async syncIssues(storage,
|
|
202
|
+
async syncIssues(storage, options, signal) {
|
|
202
203
|
const { owner, repo } = this.settings;
|
|
203
|
-
const
|
|
204
|
+
const url = new URL(`https://api.github.com/repos/${owner}/${repo}/issues`);
|
|
205
|
+
url.searchParams.set("state", "all");
|
|
206
|
+
url.searchParams.set("per_page", "100");
|
|
207
|
+
if (options.since) {
|
|
208
|
+
url.searchParams.set("since", options.since);
|
|
209
|
+
}
|
|
204
210
|
const allIssues = [];
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
signal
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
url.searchParams.set("state", "all");
|
|
212
|
-
url.searchParams.set("per_page", "100");
|
|
213
|
-
url.searchParams.set("page", String(page));
|
|
214
|
-
if (request.since) {
|
|
215
|
-
url.searchParams.set("since", request.since);
|
|
216
|
-
}
|
|
217
|
-
const res = await fetch(url.toString(), { headers, signal });
|
|
218
|
-
if (!res.ok) {
|
|
219
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
220
|
-
}
|
|
221
|
-
const issues = await res.json();
|
|
222
|
-
if (issues.length === 0) {
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
for (const issue of issues) {
|
|
226
|
-
if (issue.pull_request !== void 0) {
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
allIssues.push(issue);
|
|
230
|
-
}
|
|
231
|
-
if (issues.length < 100) {
|
|
232
|
-
break;
|
|
211
|
+
for await (const issue of this.paginate(
|
|
212
|
+
url.toString(),
|
|
213
|
+
signal
|
|
214
|
+
)) {
|
|
215
|
+
if (issue.pull_request !== void 0) {
|
|
216
|
+
continue;
|
|
233
217
|
}
|
|
234
|
-
|
|
218
|
+
allIssues.push(issue);
|
|
235
219
|
}
|
|
236
220
|
await storage.entities(
|
|
237
221
|
allIssues.map((issue) => ({
|
|
@@ -255,41 +239,22 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
255
239
|
}
|
|
256
240
|
async syncDeployments(storage, signal) {
|
|
257
241
|
const { owner, repo } = this.settings;
|
|
258
|
-
const headers = this.buildHeaders();
|
|
259
242
|
const allDeployments = [];
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
signal
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
{ headers, signal }
|
|
266
|
-
);
|
|
267
|
-
if (!res.ok) {
|
|
268
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
269
|
-
}
|
|
270
|
-
const deployments = await res.json();
|
|
271
|
-
if (deployments.length === 0) {
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
allDeployments.push(...deployments);
|
|
275
|
-
if (deployments.length < 100) {
|
|
276
|
-
break;
|
|
277
|
-
}
|
|
278
|
-
page++;
|
|
243
|
+
for await (const d of this.paginate(
|
|
244
|
+
`https://api.github.com/repos/${owner}/${repo}/deployments?per_page=100`,
|
|
245
|
+
signal
|
|
246
|
+
)) {
|
|
247
|
+
allDeployments.push(d);
|
|
279
248
|
}
|
|
280
249
|
const entities = [];
|
|
281
250
|
for (const deployment of allDeployments) {
|
|
282
251
|
signal?.throwIfAborted();
|
|
283
|
-
const res = await
|
|
252
|
+
const res = await this.get(
|
|
284
253
|
`https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,
|
|
285
|
-
|
|
254
|
+
signal
|
|
286
255
|
);
|
|
287
|
-
if (!res.ok) {
|
|
288
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
289
|
-
}
|
|
290
|
-
const statuses = await res.json();
|
|
291
256
|
const createdMs = new Date(deployment.created_at).getTime();
|
|
292
|
-
const statusUpdatedMs =
|
|
257
|
+
const statusUpdatedMs = res.body[0]?.updated_at ? new Date(res.body[0].updated_at).getTime() : null;
|
|
293
258
|
entities.push({
|
|
294
259
|
type: "deployment",
|
|
295
260
|
id: String(deployment.id),
|
|
@@ -299,7 +264,7 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
299
264
|
sha: deployment.sha,
|
|
300
265
|
creator: deployment.creator?.login ?? "",
|
|
301
266
|
created_at: createdMs,
|
|
302
|
-
latest_status:
|
|
267
|
+
latest_status: res.body[0]?.state ?? "unknown"
|
|
303
268
|
},
|
|
304
269
|
updated_at: Math.max(createdMs, statusUpdatedMs ?? 0)
|
|
305
270
|
});
|
|
@@ -308,27 +273,12 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
308
273
|
}
|
|
309
274
|
async syncReleases(storage, signal) {
|
|
310
275
|
const { owner, repo } = this.settings;
|
|
311
|
-
const headers = this.buildHeaders();
|
|
312
276
|
const allReleases = [];
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
signal
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
{ headers, signal }
|
|
319
|
-
);
|
|
320
|
-
if (!res.ok) {
|
|
321
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
322
|
-
}
|
|
323
|
-
const releases = await res.json();
|
|
324
|
-
if (releases.length === 0) {
|
|
325
|
-
break;
|
|
326
|
-
}
|
|
327
|
-
allReleases.push(...releases);
|
|
328
|
-
if (releases.length < 100) {
|
|
329
|
-
break;
|
|
330
|
-
}
|
|
331
|
-
page++;
|
|
277
|
+
for await (const r of this.paginate(
|
|
278
|
+
`https://api.github.com/repos/${owner}/${repo}/releases?per_page=100`,
|
|
279
|
+
signal
|
|
280
|
+
)) {
|
|
281
|
+
allReleases.push(r);
|
|
332
282
|
}
|
|
333
283
|
await storage.entities(
|
|
334
284
|
allReleases.map((release) => ({
|
|
@@ -352,22 +302,18 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
352
302
|
}
|
|
353
303
|
async syncContributors(storage, signal) {
|
|
354
304
|
const { owner, repo } = this.settings;
|
|
355
|
-
const headers = this.buildHeaders();
|
|
356
305
|
const contributors = await this.withRetry(
|
|
357
306
|
async (sig) => {
|
|
358
|
-
const res = await
|
|
307
|
+
const res = await this.get(
|
|
359
308
|
`https://api.github.com/repos/${owner}/${repo}/stats/contributors`,
|
|
360
|
-
|
|
309
|
+
sig
|
|
361
310
|
);
|
|
362
311
|
if (res.status === 202) {
|
|
363
312
|
return { status: "retry" };
|
|
364
313
|
}
|
|
365
|
-
if (!res.ok) {
|
|
366
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
367
|
-
}
|
|
368
314
|
return {
|
|
369
315
|
status: "done",
|
|
370
|
-
value:
|
|
316
|
+
value: res.body ?? []
|
|
371
317
|
};
|
|
372
318
|
},
|
|
373
319
|
{ maxAttempts: 15, initialDelayMs: 1e3, maxDelayMs: 1e4, signal }
|
|
@@ -402,24 +348,19 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
402
348
|
}
|
|
403
349
|
async syncRepoStats(storage, signal) {
|
|
404
350
|
const { owner, repo } = this.settings;
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
headers,
|
|
351
|
+
const res = await this.get(
|
|
352
|
+
`https://api.github.com/repos/${owner}/${repo}`,
|
|
408
353
|
signal
|
|
409
|
-
|
|
410
|
-
if (!res.ok) {
|
|
411
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
412
|
-
}
|
|
413
|
-
const data = await res.json();
|
|
354
|
+
);
|
|
414
355
|
await storage.entities(
|
|
415
356
|
[
|
|
416
357
|
{
|
|
417
358
|
type: "repo",
|
|
418
359
|
id: `${owner}/${repo}`,
|
|
419
360
|
attributes: {
|
|
420
|
-
stars:
|
|
421
|
-
forks:
|
|
422
|
-
watchers:
|
|
361
|
+
stars: res.body.stargazers_count,
|
|
362
|
+
forks: res.body.forks_count,
|
|
363
|
+
watchers: res.body.subscribers_count
|
|
423
364
|
},
|
|
424
365
|
updated_at: Date.now()
|
|
425
366
|
}
|
|
@@ -427,11 +368,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
427
368
|
{ types: ["repo"] }
|
|
428
369
|
);
|
|
429
370
|
}
|
|
430
|
-
async sync(
|
|
371
|
+
async sync(options, storage, signal) {
|
|
431
372
|
await this.syncRepoStats(storage, signal);
|
|
432
|
-
await this.syncWorkflowRuns(storage,
|
|
373
|
+
await this.syncWorkflowRuns(storage, options, signal);
|
|
433
374
|
await this.syncPullRequests(storage, signal);
|
|
434
|
-
await this.syncIssues(storage,
|
|
375
|
+
await this.syncIssues(storage, options, signal);
|
|
435
376
|
await this.syncDeployments(storage, signal);
|
|
436
377
|
await this.syncReleases(storage, signal);
|
|
437
378
|
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 };\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":["../src/github-actions.ts"],"sourcesContent":["import {\n BaseConnector,\n type CredentialsSchema,\n type StorageHandle,\n type SyncOptions,\n defineConfigFields,\n} from '@rawdash/core';\nimport {\n type HttpRequest,\n type HttpResponse,\n githubRateLimit,\n paginateLink,\n request,\n} from '@rawdash/http-client';\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":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rawdash/connector-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Rawdash connector for GitHub Actions",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"zod": "^4.4.3",
|
|
26
|
-
"@rawdash/core": "0.
|
|
26
|
+
"@rawdash/core": "0.7.0",
|
|
27
|
+
"@rawdash/http-client": "0.0.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"tsup": "^8.0.0",
|