@rawdash/connector-github 0.6.1 → 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 +95 -155
- 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({
|
|
@@ -51,19 +56,34 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
51
56
|
}
|
|
52
57
|
return headers;
|
|
53
58
|
}
|
|
54
|
-
|
|
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) {
|
|
55
80
|
const { owner, repo } = this.settings;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const res = await fetch(
|
|
81
|
+
if (options.mode === "latest") {
|
|
82
|
+
const res = await this.get(
|
|
59
83
|
`https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=1`,
|
|
60
|
-
|
|
84
|
+
signal
|
|
61
85
|
);
|
|
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];
|
|
86
|
+
const run = res.body.workflow_runs[0];
|
|
67
87
|
if (run) {
|
|
68
88
|
await storage.event({
|
|
69
89
|
name: "workflow_run",
|
|
@@ -82,20 +102,21 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
82
102
|
}
|
|
83
103
|
return;
|
|
84
104
|
}
|
|
85
|
-
const cutoff =
|
|
105
|
+
const cutoff = options.since ? new Date(options.since).getTime() : null;
|
|
86
106
|
const allEvents = [];
|
|
87
|
-
|
|
88
|
-
|
|
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) {
|
|
89
118
|
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;
|
|
119
|
+
const runs = page.workflow_runs;
|
|
99
120
|
if (runs.length === 0) {
|
|
100
121
|
break;
|
|
101
122
|
}
|
|
@@ -122,35 +143,22 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
122
143
|
}
|
|
123
144
|
const lastRun = runs.at(-1);
|
|
124
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) {
|
|
125
149
|
break;
|
|
126
150
|
}
|
|
127
|
-
page++;
|
|
128
151
|
}
|
|
129
152
|
await storage.events(allEvents, { names: ["workflow_run"] });
|
|
130
153
|
}
|
|
131
154
|
async syncPullRequests(storage, signal) {
|
|
132
155
|
const { owner, repo } = this.settings;
|
|
133
|
-
const headers = this.buildHeaders();
|
|
134
156
|
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++;
|
|
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);
|
|
154
162
|
}
|
|
155
163
|
await storage.entities(
|
|
156
164
|
allPRs.map((pr) => ({
|
|
@@ -170,17 +178,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
170
178
|
const reviewEdges = [];
|
|
171
179
|
for (const pr of allPRs) {
|
|
172
180
|
signal?.throwIfAborted();
|
|
173
|
-
const res = await
|
|
181
|
+
const res = await this.get(
|
|
174
182
|
`https://api.github.com/repos/${owner}/${repo}/pulls/${pr.number}/reviews`,
|
|
175
|
-
|
|
183
|
+
signal
|
|
176
184
|
);
|
|
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) {
|
|
185
|
+
for (const review of res.body) {
|
|
184
186
|
if (!review.user) {
|
|
185
187
|
continue;
|
|
186
188
|
}
|
|
@@ -190,49 +192,30 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
190
192
|
kind: "reviewed_by",
|
|
191
193
|
to_type: "user",
|
|
192
194
|
to_id: review.user.login,
|
|
193
|
-
attributes: {
|
|
194
|
-
state: review.state
|
|
195
|
-
},
|
|
195
|
+
attributes: { state: review.state },
|
|
196
196
|
updated_at: new Date(review.submitted_at).getTime()
|
|
197
197
|
});
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
await storage.edges(reviewEdges, { kinds: ["reviewed_by"] });
|
|
201
201
|
}
|
|
202
|
-
async syncIssues(storage,
|
|
202
|
+
async syncIssues(storage, options, signal) {
|
|
203
203
|
const { owner, repo } = this.settings;
|
|
204
|
-
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
|
+
}
|
|
205
210
|
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;
|
|
211
|
+
for await (const issue of this.paginate(
|
|
212
|
+
url.toString(),
|
|
213
|
+
signal
|
|
214
|
+
)) {
|
|
215
|
+
if (issue.pull_request !== void 0) {
|
|
216
|
+
continue;
|
|
234
217
|
}
|
|
235
|
-
|
|
218
|
+
allIssues.push(issue);
|
|
236
219
|
}
|
|
237
220
|
await storage.entities(
|
|
238
221
|
allIssues.map((issue) => ({
|
|
@@ -256,41 +239,22 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
256
239
|
}
|
|
257
240
|
async syncDeployments(storage, signal) {
|
|
258
241
|
const { owner, repo } = this.settings;
|
|
259
|
-
const headers = this.buildHeaders();
|
|
260
242
|
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++;
|
|
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);
|
|
280
248
|
}
|
|
281
249
|
const entities = [];
|
|
282
250
|
for (const deployment of allDeployments) {
|
|
283
251
|
signal?.throwIfAborted();
|
|
284
|
-
const res = await
|
|
252
|
+
const res = await this.get(
|
|
285
253
|
`https://api.github.com/repos/${owner}/${repo}/deployments/${deployment.id}/statuses?per_page=1`,
|
|
286
|
-
|
|
254
|
+
signal
|
|
287
255
|
);
|
|
288
|
-
if (!res.ok) {
|
|
289
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
290
|
-
}
|
|
291
|
-
const statuses = await res.json();
|
|
292
256
|
const createdMs = new Date(deployment.created_at).getTime();
|
|
293
|
-
const statusUpdatedMs =
|
|
257
|
+
const statusUpdatedMs = res.body[0]?.updated_at ? new Date(res.body[0].updated_at).getTime() : null;
|
|
294
258
|
entities.push({
|
|
295
259
|
type: "deployment",
|
|
296
260
|
id: String(deployment.id),
|
|
@@ -300,7 +264,7 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
300
264
|
sha: deployment.sha,
|
|
301
265
|
creator: deployment.creator?.login ?? "",
|
|
302
266
|
created_at: createdMs,
|
|
303
|
-
latest_status:
|
|
267
|
+
latest_status: res.body[0]?.state ?? "unknown"
|
|
304
268
|
},
|
|
305
269
|
updated_at: Math.max(createdMs, statusUpdatedMs ?? 0)
|
|
306
270
|
});
|
|
@@ -309,27 +273,12 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
309
273
|
}
|
|
310
274
|
async syncReleases(storage, signal) {
|
|
311
275
|
const { owner, repo } = this.settings;
|
|
312
|
-
const headers = this.buildHeaders();
|
|
313
276
|
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++;
|
|
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);
|
|
333
282
|
}
|
|
334
283
|
await storage.entities(
|
|
335
284
|
allReleases.map((release) => ({
|
|
@@ -353,22 +302,18 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
353
302
|
}
|
|
354
303
|
async syncContributors(storage, signal) {
|
|
355
304
|
const { owner, repo } = this.settings;
|
|
356
|
-
const headers = this.buildHeaders();
|
|
357
305
|
const contributors = await this.withRetry(
|
|
358
306
|
async (sig) => {
|
|
359
|
-
const res = await
|
|
307
|
+
const res = await this.get(
|
|
360
308
|
`https://api.github.com/repos/${owner}/${repo}/stats/contributors`,
|
|
361
|
-
|
|
309
|
+
sig
|
|
362
310
|
);
|
|
363
311
|
if (res.status === 202) {
|
|
364
312
|
return { status: "retry" };
|
|
365
313
|
}
|
|
366
|
-
if (!res.ok) {
|
|
367
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
368
|
-
}
|
|
369
314
|
return {
|
|
370
315
|
status: "done",
|
|
371
|
-
value:
|
|
316
|
+
value: res.body ?? []
|
|
372
317
|
};
|
|
373
318
|
},
|
|
374
319
|
{ maxAttempts: 15, initialDelayMs: 1e3, maxDelayMs: 1e4, signal }
|
|
@@ -403,24 +348,19 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
403
348
|
}
|
|
404
349
|
async syncRepoStats(storage, signal) {
|
|
405
350
|
const { owner, repo } = this.settings;
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
headers,
|
|
351
|
+
const res = await this.get(
|
|
352
|
+
`https://api.github.com/repos/${owner}/${repo}`,
|
|
409
353
|
signal
|
|
410
|
-
|
|
411
|
-
if (!res.ok) {
|
|
412
|
-
throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
|
|
413
|
-
}
|
|
414
|
-
const data = await res.json();
|
|
354
|
+
);
|
|
415
355
|
await storage.entities(
|
|
416
356
|
[
|
|
417
357
|
{
|
|
418
358
|
type: "repo",
|
|
419
359
|
id: `${owner}/${repo}`,
|
|
420
360
|
attributes: {
|
|
421
|
-
stars:
|
|
422
|
-
forks:
|
|
423
|
-
watchers:
|
|
361
|
+
stars: res.body.stargazers_count,
|
|
362
|
+
forks: res.body.forks_count,
|
|
363
|
+
watchers: res.body.subscribers_count
|
|
424
364
|
},
|
|
425
365
|
updated_at: Date.now()
|
|
426
366
|
}
|
|
@@ -428,11 +368,11 @@ var GitHubActionsConnector = class _GitHubActionsConnector extends BaseConnector
|
|
|
428
368
|
{ types: ["repo"] }
|
|
429
369
|
);
|
|
430
370
|
}
|
|
431
|
-
async sync(
|
|
371
|
+
async sync(options, storage, signal) {
|
|
432
372
|
await this.syncRepoStats(storage, signal);
|
|
433
|
-
await this.syncWorkflowRuns(storage,
|
|
373
|
+
await this.syncWorkflowRuns(storage, options, signal);
|
|
434
374
|
await this.syncPullRequests(storage, signal);
|
|
435
|
-
await this.syncIssues(storage,
|
|
375
|
+
await this.syncIssues(storage, options, signal);
|
|
436
376
|
await this.syncDeployments(storage, signal);
|
|
437
377
|
await this.syncReleases(storage, signal);
|
|
438
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 '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":["../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":";AAAA;AAAA,EACE;AAAA,EAIA;AAAA,OACK;AACP;AAAA,EAGE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS;AAEX,IAAM,eAAe;AAAA,EAC1B,EAAE,OAAO;AAAA,IACP,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK;AAAA,MAC5B,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,IACf,CAAC;AAAA,IACD,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK;AAAA,MAC3B,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,IACf,CAAC;AAAA,IACD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK;AAAA,MACvD,OAAO;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;AAuFA,IAAM,oBAAoB;AAAA,EACxB,OAAO;AAAA,IACL,aAAa;AAAA,IACb,MAAM;AAAA,EACR;AACF;AAIO,IAAM,yBAAN,MAAM,gCAA+B,cAG1C;AAAA,EACA,OAAgB,KAAK;AAAA,EAErB,OAAO,OAAO,OAAwC;AACpD,UAAM,SAAS,aAAa,MAAM,KAAK;AACvC,WAAO,IAAI;AAAA,MACT,EAAE,OAAO,OAAO,OAAO,MAAM,OAAO,KAAK;AAAA,MACzC,EAAE,OAAO,OAAO,MAAM;AAAA,IACxB;AAAA,EACF;AAAA,EAES,KAAK;AAAA,EAEI,cAAc;AAAA,EAExB,eAAuC;AAC7C,UAAM,UAAkC;AAAA,MACtC,QAAQ;AAAA,MACR,wBAAwB;AAAA,MACxB,cAAc;AAAA,IAChB;AACA,QAAI,KAAK,MAAM,OAAO;AACpB,cAAQ,eAAe,IAAI,UAAU,KAAK,MAAM,KAAK;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,IAAO,KAAa,QAAgD;AAC1E,UAAM,MAAmB;AAAA,MACvB;AAAA,MACA,SAAS,KAAK,aAAa;AAAA,MAC3B;AAAA,MACA,WAAW;AAAA,IACb;AACA,WAAO,QAAW,GAAG;AAAA,EACvB;AAAA,EAEA,OAAe,SACb,KACA,QACkB;AAClB,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,SAAS,KAAK,aAAa;AAAA,QAC3B;AAAA,QACA,WAAW;AAAA,MACb;AAAA,MACA,CAAC,SAAS;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,SACA,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAE7B,QAAI,QAAQ,SAAS,UAAU;AAC7B,YAAM,MAAM,MAAM,KAAK;AAAA,QACrB,gCAAgC,KAAK,IAAI,IAAI;AAAA,QAC7C;AAAA,MACF;AACA,YAAM,MAAM,IAAI,KAAK,cAAc,CAAC;AACpC,UAAI,KAAK;AACP,cAAM,QAAQ,MAAM;AAAA,UAClB,MAAM;AAAA,UACN,UAAU,IAAI,KAAK,IAAI,UAAU,EAAE,QAAQ;AAAA,UAC3C,QAAQ,IAAI,KAAK,IAAI,UAAU,EAAE,QAAQ;AAAA,UACzC,YAAY;AAAA,YACV,IAAI,IAAI;AAAA,YACR,eAAe,IAAI;AAAA,YACnB,YAAY,IAAI,cAAc;AAAA,YAC9B,QAAQ,IAAI;AAAA,YACZ,QAAQ,IAAI,eAAe;AAAA,YAC3B,OAAO,IAAI,OAAO,SAAS;AAAA,YAC3B,aAAa,IAAI;AAAA,UACnB;AAAA,QACF,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAEA,UAAM,SAAS,QAAQ,QAAQ,IAAI,KAAK,QAAQ,KAAK,EAAE,QAAQ,IAAI;AACnE,UAAM,YAAoD,CAAC;AAE3D,UAAM,OAAO;AAAA,MACX;AAAA,QACE,KAAK,gCAAgC,KAAK,IAAI,IAAI;AAAA,QAClD,SAAS,KAAK,aAAa;AAAA,QAC3B;AAAA,QACA,WAAW;AAAA,MACb;AAAA,MACA,CAAC,SAAS,CAAC,IAA0B;AAAA,IACvC;AAEA,QAAI,OAAO;AACX,qBAAiB,QAAQ,MAAM;AAC7B,cAAQ,eAAe;AACvB,YAAM,OAAO,KAAK;AAClB,UAAI,KAAK,WAAW,GAAG;AACrB;AAAA,MACF;AAEA,iBAAW,OAAO,MAAM;AACtB,cAAM,YAAY,IAAI,KAAK,IAAI,UAAU,EAAE,QAAQ;AACnD,cAAM,YAAY,IAAI,KAAK,IAAI,UAAU,EAAE,QAAQ;AACnD,YAAI,WAAW,QAAQ,YAAY,UAAU,YAAY,QAAQ;AAC/D;AAAA,QACF;AACA,kBAAU,KAAK;AAAA,UACb,MAAM;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,YAAY;AAAA,YACV,IAAI,IAAI;AAAA,YACR,eAAe,IAAI;AAAA,YACnB,YAAY,IAAI,cAAc;AAAA,YAC9B,QAAQ,IAAI;AAAA,YACZ,QAAQ,IAAI,eAAe;AAAA,YAC3B,OAAO,IAAI,OAAO,SAAS;AAAA,YAC3B,aAAa,IAAI;AAAA,UACnB;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,UAAU,KAAK,GAAG,EAAE;AAC1B,UACE,WAAW,QACX,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ,IAAI,UACzC,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ,IAAI,QACzC;AACA,eAAO;AAAA,MACT;AACA,UAAI,MAAM;AACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,OAAO,WAAW,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC;AAAA,EAC7D;AAAA,EAEA,MAAc,iBACZ,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAC7B,UAAM,SAAqB,CAAC;AAE5B,qBAAiB,MAAM,KAAK;AAAA,MAC1B,gCAAgC,KAAK,IAAI,IAAI;AAAA,MAC7C;AAAA,IACF,GAAG;AACD,aAAO,KAAK,EAAE;AAAA,IAChB;AAEA,UAAM,QAAQ;AAAA,MACZ,OAAO,IAAI,CAAC,QAAQ;AAAA,QAClB,MAAM;AAAA,QACN,IAAI,OAAO,GAAG,MAAM;AAAA,QACpB,YAAY;AAAA,UACV,OAAO,GAAG;AAAA,UACV,OAAO,GAAG;AAAA,UACV,OAAO,GAAG;AAAA,UACV,QAAQ,GAAG,KAAK;AAAA,UAChB,YAAY,IAAI,KAAK,GAAG,UAAU,EAAE,QAAQ;AAAA,QAC9C;AAAA,QACA,YAAY,IAAI,KAAK,GAAG,UAAU,EAAE,QAAQ;AAAA,MAC9C,EAAE;AAAA,MACF,EAAE,OAAO,CAAC,cAAc,EAAE;AAAA,IAC5B;AAEA,UAAM,cAAqD,CAAC;AAC5D,eAAW,MAAM,QAAQ;AACvB,cAAQ,eAAe;AACvB,YAAM,MAAM,MAAM,KAAK;AAAA,QACrB,gCAAgC,KAAK,IAAI,IAAI,UAAU,GAAG,MAAM;AAAA,QAChE;AAAA,MACF;AACA,iBAAW,UAAU,IAAI,MAAM;AAC7B,YAAI,CAAC,OAAO,MAAM;AAChB;AAAA,QACF;AACA,oBAAY,KAAK;AAAA,UACf,WAAW;AAAA,UACX,SAAS,OAAO,GAAG,MAAM;AAAA,UACzB,MAAM;AAAA,UACN,SAAS;AAAA,UACT,OAAO,OAAO,KAAK;AAAA,UACnB,YAAY,EAAE,OAAO,OAAO,MAAM;AAAA,UAClC,YAAY,IAAI,KAAK,OAAO,YAAY,EAAE,QAAQ;AAAA,QACpD,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC;AAAA,EAC7D;AAAA,EAEA,MAAc,WACZ,SACA,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAC7B,UAAM,MAAM,IAAI,IAAI,gCAAgC,KAAK,IAAI,IAAI,SAAS;AAC1E,QAAI,aAAa,IAAI,SAAS,KAAK;AACnC,QAAI,aAAa,IAAI,YAAY,KAAK;AACtC,QAAI,QAAQ,OAAO;AACjB,UAAI,aAAa,IAAI,SAAS,QAAQ,KAAK;AAAA,IAC7C;AAEA,UAAM,YAA2B,CAAC;AAClC,qBAAiB,SAAS,KAAK;AAAA,MAC7B,IAAI,SAAS;AAAA,MACb;AAAA,IACF,GAAG;AACD,UAAI,MAAM,iBAAiB,QAAW;AACpC;AAAA,MACF;AACA,gBAAU,KAAK,KAAK;AAAA,IACtB;AAEA,UAAM,QAAQ;AAAA,MACZ,UAAU,IAAI,CAAC,WAAW;AAAA,QACxB,MAAM;AAAA,QACN,IAAI,OAAO,MAAM,MAAM;AAAA,QACvB,YAAY;AAAA,UACV,QAAQ,MAAM;AAAA,UACd,OAAO,MAAM;AAAA,UACb,OAAO,MAAM;AAAA,UACb,QAAQ,MAAM,OAAO,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,UACtC,WAAW,MAAM,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK;AAAA,UAC7C,QAAQ,MAAM,KAAK;AAAA,UACnB,YAAY,IAAI,KAAK,MAAM,UAAU,EAAE,QAAQ;AAAA,UAC/C,YAAY,IAAI,KAAK,MAAM,UAAU,EAAE,QAAQ;AAAA,UAC/C,WAAW,MAAM,YACb,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ,IAClC;AAAA,QACN;AAAA,QACA,YAAY,IAAI,KAAK,MAAM,UAAU,EAAE,QAAQ;AAAA,MACjD,EAAE;AAAA,MACF,EAAE,OAAO,CAAC,OAAO,EAAE;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAc,gBACZ,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAC7B,UAAM,iBAAqC,CAAC;AAC5C,qBAAiB,KAAK,KAAK;AAAA,MACzB,gCAAgC,KAAK,IAAI,IAAI;AAAA,MAC7C;AAAA,IACF,GAAG;AACD,qBAAe,KAAK,CAAC;AAAA,IACvB;AAEA,UAAM,WAAqD,CAAC;AAC5D,eAAW,cAAc,gBAAgB;AACvC,cAAQ,eAAe;AACvB,YAAM,MAAM,MAAM,KAAK;AAAA,QACrB,gCAAgC,KAAK,IAAI,IAAI,gBAAgB,WAAW,EAAE;AAAA,QAC1E;AAAA,MACF;AACA,YAAM,YAAY,IAAI,KAAK,WAAW,UAAU,EAAE,QAAQ;AAC1D,YAAM,kBAAkB,IAAI,KAAK,CAAC,GAAG,aACjC,IAAI,KAAK,IAAI,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ,IACzC;AACJ,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,IAAI,OAAO,WAAW,EAAE;AAAA,QACxB,YAAY;AAAA,UACV,aAAa,WAAW;AAAA,UACxB,KAAK,WAAW;AAAA,UAChB,KAAK,WAAW;AAAA,UAChB,SAAS,WAAW,SAAS,SAAS;AAAA,UACtC,YAAY;AAAA,UACZ,eAAe,IAAI,KAAK,CAAC,GAAG,SAAS;AAAA,QACvC;AAAA,QACA,YAAY,KAAK,IAAI,WAAW,mBAAmB,CAAC;AAAA,MACtD,CAAC;AAAA,IACH;AAEA,UAAM,QAAQ,SAAS,UAAU,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;AAAA,EAC5D;AAAA,EAEA,MAAc,aACZ,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAC7B,UAAM,cAA+B,CAAC;AACtC,qBAAiB,KAAK,KAAK;AAAA,MACzB,gCAAgC,KAAK,IAAI,IAAI;AAAA,MAC7C;AAAA,IACF,GAAG;AACD,kBAAY,KAAK,CAAC;AAAA,IACpB;AAEA,UAAM,QAAQ;AAAA,MACZ,YAAY,IAAI,CAAC,aAAa;AAAA,QAC5B,MAAM;AAAA,QACN,IAAI,OAAO,QAAQ,EAAE;AAAA,QACrB,YAAY;AAAA,UACV,UAAU,QAAQ;AAAA,UAClB,MAAM,QAAQ,QAAQ;AAAA,UACtB,OAAO,QAAQ;AAAA,UACf,YAAY,QAAQ;AAAA,UACpB,YAAY,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ;AAAA,UACjD,cAAc,QAAQ,eAClB,IAAI,KAAK,QAAQ,YAAY,EAAE,QAAQ,IACvC;AAAA,UACJ,QAAQ,QAAQ,OAAO;AAAA,QACzB;AAAA,QACA,YAAY,IAAI;AAAA,UACd,QAAQ,gBAAgB,QAAQ;AAAA,QAClC,EAAE,QAAQ;AAAA,MACZ,EAAE;AAAA,MACF,EAAE,OAAO,CAAC,SAAS,EAAE;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAE7B,UAAM,eAAe,MAAM,KAAK;AAAA,MAC9B,OAAO,QAAQ;AACb,cAAM,MAAM,MAAM,KAAK;AAAA,UACrB,gCAAgC,KAAK,IAAI,IAAI;AAAA,UAC7C;AAAA,QACF;AACA,YAAI,IAAI,WAAW,KAAK;AACtB,iBAAO,EAAE,QAAQ,QAAQ;AAAA,QAC3B;AACA,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,OAAQ,IAAI,QAAQ,CAAC;AAAA,QACvB;AAAA,MACF;AAAA,MACA,EAAE,aAAa,IAAI,gBAAgB,KAAM,YAAY,KAAO,OAAO;AAAA,IACrE;AAEA,QAAI,CAAC,gBAAgB,aAAa,WAAW,GAAG;AAC9C,UAAI,CAAC,cAAc;AACjB,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,MACZ,aAAa,IAAI,CAAC,MAAM;AACtB,cAAM,YAAY,EAAE,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,GAAG,CAAC;AACzD,cAAM,YAAY,EAAE,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,GAAG,CAAC;AACzD,cAAM,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;AAC7D,eAAO;AAAA,UACL,MAAM;AAAA,UACN,IAAI,EAAE,OAAO;AAAA,UACb,YAAY;AAAA,YACV,SAAS,EAAE;AAAA,YACX;AAAA,YACA;AAAA,YACA,kBAAkB,aAAa,WAAW,IAAI,MAAO;AAAA,UACvD;AAAA,UACA,YAAY,aAAa,WAAW,IAAI,MAAO;AAAA,QACjD;AAAA,MACF,CAAC;AAAA,MACD,EAAE,OAAO,CAAC,aAAa,EAAE;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAc,cACZ,SACA,QACe;AACf,UAAM,EAAE,OAAO,KAAK,IAAI,KAAK;AAC7B,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB,gCAAgC,KAAK,IAAI,IAAI;AAAA,MAC7C;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,MACZ;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,IAAI,GAAG,KAAK,IAAI,IAAI;AAAA,UACpB,YAAY;AAAA,YACV,OAAO,IAAI,KAAK;AAAA,YAChB,OAAO,IAAI,KAAK;AAAA,YAChB,UAAU,IAAI,KAAK;AAAA,UACrB;AAAA,UACA,YAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF;AAAA,MACA,EAAE,OAAO,CAAC,MAAM,EAAE;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,KACJ,SACA,SACA,QACe;AACf,UAAM,KAAK,cAAc,SAAS,MAAM;AACxC,UAAM,KAAK,iBAAiB,SAAS,SAAS,MAAM;AACpD,UAAM,KAAK,iBAAiB,SAAS,MAAM;AAC3C,UAAM,KAAK,WAAW,SAAS,SAAS,MAAM;AAC9C,UAAM,KAAK,gBAAgB,SAAS,MAAM;AAC1C,UAAM,KAAK,aAAa,SAAS,MAAM;AACvC,UAAM,KAAK,iBAAiB,SAAS,MAAM;AAAA,EAC7C;AACF;","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",
|