@useairfoil/producer-github 0.0.1 → 0.0.2
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/README.md +116 -0
- package/dist/index.d.mts +1939 -0
- package/dist/index.mjs +3 -0
- package/dist/main.d.mts +1 -0
- package/dist/main.mjs +698 -0
- package/dist/main.mjs.map +1 -0
- package/dist/manifest.d.mts +56 -0
- package/dist/manifest.mjs +137 -0
- package/dist/manifest.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/src-D6cTmVtF.mjs +1566 -0
- package/dist/src-D6cTmVtF.mjs.map +1 -0
- package/package.json +45 -7
- package/src/client/auth.ts +113 -0
- package/src/client/client.ts +192 -0
- package/src/client/constants.ts +4 -0
- package/src/connector.ts +97 -0
- package/src/create-table.ts +5 -0
- package/src/demo/changes.ts +420 -0
- package/src/demo/index.ts +59 -0
- package/src/demo/setup.ts +34 -0
- package/src/demo/shared.ts +101 -0
- package/src/index.ts +13 -0
- package/src/main.ts +22 -0
- package/src/manifest.ts +45 -0
- package/src/resources/check-runs.ts +72 -0
- package/src/resources/commit-statuses.ts +84 -0
- package/src/resources/commits.ts +101 -0
- package/src/resources/issue-comments.ts +75 -0
- package/src/resources/issues.ts +78 -0
- package/src/resources/pull-request-commits.ts +91 -0
- package/src/resources/pull-request-review-comments.ts +78 -0
- package/src/resources/pull-request-reviews.ts +76 -0
- package/src/resources/pull-requests.ts +79 -0
- package/src/resources/releases.ts +74 -0
- package/src/resources/repositories.ts +101 -0
- package/src/resources/shared.ts +480 -0
- package/src/resources/workflow-jobs.ts +73 -0
- package/src/resources/workflow-runs.ts +70 -0
- package/src/sandbox.ts +35 -0
- package/src/schemas/check-runs.ts +48 -0
- package/src/schemas/commit-statuses.ts +31 -0
- package/src/schemas/commits.ts +64 -0
- package/src/schemas/events.ts +139 -0
- package/src/schemas/issue-comments.ts +38 -0
- package/src/schemas/issues.ts +62 -0
- package/src/schemas/pull-request-commits.ts +28 -0
- package/src/schemas/pull-request-review-comments.ts +67 -0
- package/src/schemas/pull-request-reviews.ts +37 -0
- package/src/schemas/pull-requests.ts +75 -0
- package/src/schemas/releases.ts +53 -0
- package/src/schemas/repositories.ts +53 -0
- package/src/schemas/shared.ts +86 -0
- package/src/schemas/workflow-jobs.ts +54 -0
- package/src/schemas/workflow-runs.ts +55 -0
- package/src/start.ts +47 -0
- package/src/tables.ts +31 -0
- package/src/webhook/route.ts +46 -0
- package/src/webhook/signature.ts +20 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import type { Demo } from "@useairfoil/connector-kit";
|
|
2
|
+
|
|
3
|
+
import type { IssueComment } from "../schemas/issue-comments";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
type Account,
|
|
7
|
+
actionsBot,
|
|
8
|
+
clock,
|
|
9
|
+
day,
|
|
10
|
+
labels,
|
|
11
|
+
minute,
|
|
12
|
+
nodeId,
|
|
13
|
+
org,
|
|
14
|
+
paths,
|
|
15
|
+
people,
|
|
16
|
+
repositories,
|
|
17
|
+
repositoryId,
|
|
18
|
+
type Rows,
|
|
19
|
+
urlOf,
|
|
20
|
+
verbs,
|
|
21
|
+
} from "./shared";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* One group is one change in a repository: an issue, the pull request that
|
|
25
|
+
* fixes it, and its CI.
|
|
26
|
+
*/
|
|
27
|
+
export const changeRows = (index: number, context: Demo.DemoContext): Rows => {
|
|
28
|
+
const { faker, now } = context;
|
|
29
|
+
const { at, later } = clock(context);
|
|
30
|
+
|
|
31
|
+
const rows: Rows = {
|
|
32
|
+
issues: [],
|
|
33
|
+
pull_requests: [],
|
|
34
|
+
issue_comments: [],
|
|
35
|
+
pull_request_reviews: [],
|
|
36
|
+
pull_request_review_comments: [],
|
|
37
|
+
pull_request_commits: [],
|
|
38
|
+
commits: [],
|
|
39
|
+
check_runs: [],
|
|
40
|
+
commit_statuses: [],
|
|
41
|
+
workflow_runs: [],
|
|
42
|
+
workflow_jobs: [],
|
|
43
|
+
releases: [],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const r = index % repositories.length;
|
|
47
|
+
const repo = repositories[r] ?? repositories[0];
|
|
48
|
+
const repoId = repositoryId(r);
|
|
49
|
+
const round = Math.floor(index / repositories.length);
|
|
50
|
+
|
|
51
|
+
// Issues and pull requests share one number sequence per repository.
|
|
52
|
+
const issueNumber = BigInt(round * 2 + 1);
|
|
53
|
+
const prNumber = BigInt(round * 2 + 2);
|
|
54
|
+
const id = BigInt(index);
|
|
55
|
+
|
|
56
|
+
const author = faker.helpers.arrayElement(people);
|
|
57
|
+
const reviewer = faker.helpers.arrayElement(people.filter((person) => person !== author));
|
|
58
|
+
const association = (account: Account) => (account.type === "Bot" ? "NONE" : "MEMBER");
|
|
59
|
+
const title = `${faker.helpers.arrayElement(verbs)} ${faker.hacker.adjective()} ${faker.hacker.noun()} handling`;
|
|
60
|
+
const label = faker.helpers.arrayElement(labels);
|
|
61
|
+
const opened = at(now.getTime() - faker.number.int({ min: day, max: 600 * day }));
|
|
62
|
+
|
|
63
|
+
const comment = (issueNumber: bigint, n: number, created: Date): IssueComment => {
|
|
64
|
+
const commentId = 1_800_000_000n + id * 10n + BigInt(n);
|
|
65
|
+
const user = faker.helpers.arrayElement(people);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
id: commentId,
|
|
69
|
+
version: created,
|
|
70
|
+
node_id: nodeId("IC", commentId),
|
|
71
|
+
repository_id: repoId,
|
|
72
|
+
issue_number: issueNumber,
|
|
73
|
+
user,
|
|
74
|
+
author_association: association(user),
|
|
75
|
+
body: faker.helpers.arrayElement([
|
|
76
|
+
"I can reproduce this on the latest release.",
|
|
77
|
+
"Thanks for the report. Looking into it.",
|
|
78
|
+
"This should be fixed once the pull request lands.",
|
|
79
|
+
"Can we add a test for this case?",
|
|
80
|
+
"LGTM, thanks!",
|
|
81
|
+
]),
|
|
82
|
+
created_at: created,
|
|
83
|
+
html_url: `${urlOf(repo)}/issues/${issueNumber}#issuecomment-${commentId}`,
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const fixed = faker.datatype.boolean({ probability: 0.75 });
|
|
88
|
+
|
|
89
|
+
const issueComments = Array.from({ length: faker.number.int({ max: 3 }) }, (_, n) =>
|
|
90
|
+
comment(issueNumber, n, later(opened, minute, 5 * day)),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
rows.issue_comments.push(...issueComments);
|
|
94
|
+
|
|
95
|
+
// The pull request, from a branch, with one to four commits.
|
|
96
|
+
const branch = `${author.login.split("-")[0]}/${title.toLowerCase().split(" ").slice(1, 3).join("-")}`;
|
|
97
|
+
const prOpened = later(opened, 60 * minute, 7 * day);
|
|
98
|
+
|
|
99
|
+
const prState = faker.helpers.weightedArrayElement([
|
|
100
|
+
{ weight: 70, value: "merged" },
|
|
101
|
+
{ weight: 10, value: "closed" },
|
|
102
|
+
{ weight: 20, value: "open" },
|
|
103
|
+
] as const);
|
|
104
|
+
|
|
105
|
+
const baseSha = faker.git.commitSha();
|
|
106
|
+
let committed = prOpened;
|
|
107
|
+
|
|
108
|
+
const shas = Array.from({ length: faker.number.int({ min: 1, max: 4 }) }, (_, n) => {
|
|
109
|
+
committed = later(committed, 10 * minute, day);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
sha: faker.git.commitSha(),
|
|
113
|
+
message: n === 0 ? title : faker.git.commitMessage(),
|
|
114
|
+
at: committed,
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const headSha = shas.at(-1)?.sha ?? baseSha;
|
|
119
|
+
const reviewed = later(committed, 30 * minute, 2 * day);
|
|
120
|
+
const closedAt = prState === "open" ? null : later(reviewed, 10 * minute, day);
|
|
121
|
+
const mergedAt = prState === "merged" ? closedAt : null;
|
|
122
|
+
|
|
123
|
+
const prComments = Array.from({ length: faker.number.int({ max: 2 }) }, (_, n) =>
|
|
124
|
+
comment(prNumber, 5 + n, later(prOpened, minute, 2 * day)),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
rows.issue_comments.push(...prComments);
|
|
128
|
+
|
|
129
|
+
const prUpdated = new Date(
|
|
130
|
+
Math.max(
|
|
131
|
+
closedAt?.getTime() ?? 0,
|
|
132
|
+
reviewed.getTime(),
|
|
133
|
+
...prComments.map((row) => row.created_at.getTime()),
|
|
134
|
+
),
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const prId = 1_500_000_000n + id;
|
|
138
|
+
|
|
139
|
+
rows.pull_requests.push({
|
|
140
|
+
id: prId,
|
|
141
|
+
version: prUpdated,
|
|
142
|
+
node_id: nodeId("PR", prId),
|
|
143
|
+
repository_id: repoId,
|
|
144
|
+
number: prNumber,
|
|
145
|
+
title,
|
|
146
|
+
body: `Fixes #${issueNumber}.\n\n${faker.hacker.phrase()}`,
|
|
147
|
+
state: prState === "open" ? "open" : "closed",
|
|
148
|
+
draft: prState === "open" && faker.datatype.boolean({ probability: 0.2 }),
|
|
149
|
+
locked: false,
|
|
150
|
+
user: author,
|
|
151
|
+
author_association: "MEMBER",
|
|
152
|
+
labels: [label],
|
|
153
|
+
assignees: [author],
|
|
154
|
+
requested_reviewers: prState === "open" ? [reviewer] : [],
|
|
155
|
+
milestone: null,
|
|
156
|
+
head: { ref: branch, sha: headSha, label: `${org}:${branch}` },
|
|
157
|
+
base: { ref: "main", sha: baseSha, label: `${org}:main` },
|
|
158
|
+
created_at: prOpened,
|
|
159
|
+
closed_at: closedAt,
|
|
160
|
+
merged_at: mergedAt,
|
|
161
|
+
html_url: `${urlOf(repo)}/pull/${prNumber}`,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
for (const commit of shas) {
|
|
165
|
+
rows.pull_request_commits.push({
|
|
166
|
+
key: `${repoId}:${prNumber}:${commit.sha}`,
|
|
167
|
+
// Pull request commits take the pull request's version.
|
|
168
|
+
version: prUpdated,
|
|
169
|
+
repository_id: repoId,
|
|
170
|
+
pull_request_number: prNumber,
|
|
171
|
+
sha: commit.sha,
|
|
172
|
+
message: commit.message,
|
|
173
|
+
author: { name: author.login, date: commit.at },
|
|
174
|
+
committer: { name: author.login, date: commit.at },
|
|
175
|
+
author_user: author,
|
|
176
|
+
committer_user: author,
|
|
177
|
+
html_url: `${urlOf(repo)}/commit/${commit.sha}`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Reviews have no update time, so their version is the read time.
|
|
182
|
+
const reviewState = faker.helpers.weightedArrayElement([
|
|
183
|
+
{ weight: 70, value: "APPROVED" },
|
|
184
|
+
{ weight: 20, value: "CHANGES_REQUESTED" },
|
|
185
|
+
{ weight: 10, value: "COMMENTED" },
|
|
186
|
+
] as const);
|
|
187
|
+
|
|
188
|
+
if (prState !== "open" || faker.datatype.boolean({ probability: 0.5 })) {
|
|
189
|
+
const reviewId = 2_400_000_000n + id;
|
|
190
|
+
|
|
191
|
+
rows.pull_request_reviews.push({
|
|
192
|
+
id: reviewId,
|
|
193
|
+
version: now,
|
|
194
|
+
node_id: nodeId("PRR", reviewId),
|
|
195
|
+
repository_id: repoId,
|
|
196
|
+
pull_request_number: prNumber,
|
|
197
|
+
user: reviewer,
|
|
198
|
+
author_association: "MEMBER",
|
|
199
|
+
state: reviewState,
|
|
200
|
+
body: reviewState === "APPROVED" ? "" : "A few small things before this lands.",
|
|
201
|
+
commit_id: headSha,
|
|
202
|
+
submitted_at: reviewed,
|
|
203
|
+
html_url: `${urlOf(repo)}/pull/${prNumber}#pullrequestreview-${reviewId}`,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
if (reviewState !== "APPROVED") {
|
|
207
|
+
const line = BigInt(faker.number.int({ min: 5, max: 200 }));
|
|
208
|
+
const reviewCommentId = 2_900_000_000n + id;
|
|
209
|
+
|
|
210
|
+
rows.pull_request_review_comments.push({
|
|
211
|
+
id: reviewCommentId,
|
|
212
|
+
version: reviewed,
|
|
213
|
+
node_id: nodeId("PRRC", reviewCommentId),
|
|
214
|
+
repository_id: repoId,
|
|
215
|
+
pull_request_number: prNumber,
|
|
216
|
+
pull_request_review_id: reviewId,
|
|
217
|
+
user: reviewer,
|
|
218
|
+
author_association: "MEMBER",
|
|
219
|
+
body: faker.helpers.arrayElement([
|
|
220
|
+
"Could this return early instead?",
|
|
221
|
+
"Nit: this name is a bit unclear.",
|
|
222
|
+
"We should handle the error here.",
|
|
223
|
+
]),
|
|
224
|
+
path: faker.helpers.arrayElement(paths),
|
|
225
|
+
commit_id: headSha,
|
|
226
|
+
original_commit_id: headSha,
|
|
227
|
+
diff_hunk: `@@ -${line},6 +${line},8 @@`,
|
|
228
|
+
line,
|
|
229
|
+
original_line: line,
|
|
230
|
+
start_line: null,
|
|
231
|
+
side: "RIGHT",
|
|
232
|
+
subject_type: "line",
|
|
233
|
+
created_at: reviewed,
|
|
234
|
+
html_url: `${urlOf(repo)}/pull/${prNumber}#discussion_r${reviewCommentId}`,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// CI runs on the head commit: one workflow run with two jobs, and their check runs.
|
|
240
|
+
const ciPassed = faker.datatype.boolean({ probability: 0.85 });
|
|
241
|
+
const runId = 9_000_000_000n + id;
|
|
242
|
+
const runStarted = later(committed, 10_000, minute);
|
|
243
|
+
const workflowId = 60_000_000n + BigInt(r);
|
|
244
|
+
|
|
245
|
+
rows.workflow_runs.push({
|
|
246
|
+
id: runId,
|
|
247
|
+
version: later(runStarted, 2 * minute, 15 * minute),
|
|
248
|
+
node_id: nodeId("WFR", runId),
|
|
249
|
+
repository_id: repoId,
|
|
250
|
+
workflow_id: workflowId,
|
|
251
|
+
name: "CI",
|
|
252
|
+
display_title: title,
|
|
253
|
+
path: ".github/workflows/ci.yml",
|
|
254
|
+
event: "pull_request",
|
|
255
|
+
status: "completed",
|
|
256
|
+
conclusion: ciPassed ? "success" : "failure",
|
|
257
|
+
head_branch: branch,
|
|
258
|
+
head_sha: headSha,
|
|
259
|
+
run_number: BigInt(round + 1),
|
|
260
|
+
run_attempt: 1n,
|
|
261
|
+
check_suite_id: 30_000_000_000n + id,
|
|
262
|
+
actor: author,
|
|
263
|
+
triggering_actor: author,
|
|
264
|
+
pull_requests: [{ id: prId, number: prNumber }],
|
|
265
|
+
created_at: runStarted,
|
|
266
|
+
run_started_at: runStarted,
|
|
267
|
+
html_url: `${urlOf(repo)}/actions/runs/${runId}`,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
["build", "test"].forEach((name, j) => {
|
|
271
|
+
const jobId = 25_000_000_000n + id * 2n + BigInt(j);
|
|
272
|
+
const started = later(runStarted, 5_000, minute);
|
|
273
|
+
const completed = later(started, minute, 10 * minute);
|
|
274
|
+
const conclusion = ciPassed || name === "build" ? "success" : "failure";
|
|
275
|
+
|
|
276
|
+
rows.workflow_jobs.push({
|
|
277
|
+
id: jobId,
|
|
278
|
+
version: now,
|
|
279
|
+
node_id: nodeId("CR", jobId),
|
|
280
|
+
repository_id: repoId,
|
|
281
|
+
run_id: runId,
|
|
282
|
+
run_attempt: 1n,
|
|
283
|
+
workflow_name: "CI",
|
|
284
|
+
name,
|
|
285
|
+
head_sha: headSha,
|
|
286
|
+
head_branch: branch,
|
|
287
|
+
status: "completed",
|
|
288
|
+
conclusion,
|
|
289
|
+
created_at: runStarted,
|
|
290
|
+
started_at: started,
|
|
291
|
+
completed_at: completed,
|
|
292
|
+
runner_name: `GitHub Actions ${faker.number.int({ min: 1, max: 99 })}`,
|
|
293
|
+
labels: ["ubuntu-latest"],
|
|
294
|
+
steps: ["Set up job", "Checkout", `Run ${name}`, "Complete job"].map((step, s) => ({
|
|
295
|
+
number: BigInt(s + 1),
|
|
296
|
+
name: step,
|
|
297
|
+
status: "completed",
|
|
298
|
+
conclusion: s === 2 ? conclusion : "success",
|
|
299
|
+
started_at: started,
|
|
300
|
+
completed_at: completed,
|
|
301
|
+
})),
|
|
302
|
+
html_url: `${urlOf(repo)}/actions/runs/${runId}/job/${jobId}`,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
rows.check_runs.push({
|
|
306
|
+
id: jobId,
|
|
307
|
+
version: now,
|
|
308
|
+
node_id: nodeId("CR", jobId),
|
|
309
|
+
repository_id: repoId,
|
|
310
|
+
head_sha: headSha,
|
|
311
|
+
name,
|
|
312
|
+
status: "completed",
|
|
313
|
+
conclusion,
|
|
314
|
+
started_at: started,
|
|
315
|
+
completed_at: completed,
|
|
316
|
+
app: { id: 15_368n, name: "GitHub Actions" },
|
|
317
|
+
check_suite: { id: 30_000_000_000n + id },
|
|
318
|
+
output: { title: null, summary: null },
|
|
319
|
+
external_id: null,
|
|
320
|
+
details_url: `${urlOf(repo)}/actions/runs/${runId}/job/${jobId}`,
|
|
321
|
+
html_url: `${urlOf(repo)}/actions/runs/${runId}/job/${jobId}`,
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// A merged pull request lands as one squashed commit on main, with a deploy status.
|
|
326
|
+
if (mergedAt) {
|
|
327
|
+
const sha = faker.git.commitSha();
|
|
328
|
+
|
|
329
|
+
rows.commits.push({
|
|
330
|
+
key: `${repoId}:${sha}`,
|
|
331
|
+
// Commits never change, so the version is the commit time.
|
|
332
|
+
version: mergedAt,
|
|
333
|
+
repository_id: repoId,
|
|
334
|
+
sha,
|
|
335
|
+
node_id: nodeId("C", 3_000_000_000n + id),
|
|
336
|
+
message: `${title} (#${prNumber})`,
|
|
337
|
+
author: { name: author.login, date: mergedAt },
|
|
338
|
+
committer: { name: "GitHub", date: mergedAt },
|
|
339
|
+
author_user: author,
|
|
340
|
+
committer_user: { id: 19_864_447n, login: "web-flow", type: "User" },
|
|
341
|
+
parents: [baseSha],
|
|
342
|
+
verified: true,
|
|
343
|
+
html_url: `${urlOf(repo)}/commit/${sha}`,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const statusId = 3_500_000_000n + id;
|
|
347
|
+
const deployed = faker.datatype.boolean({ probability: 0.95 });
|
|
348
|
+
|
|
349
|
+
rows.commit_statuses.push({
|
|
350
|
+
id: statusId,
|
|
351
|
+
version: later(mergedAt, minute, 10 * minute),
|
|
352
|
+
node_id: nodeId("SC", statusId),
|
|
353
|
+
repository_id: repoId,
|
|
354
|
+
sha,
|
|
355
|
+
state: deployed ? "success" : "failure",
|
|
356
|
+
context: "deploy/production",
|
|
357
|
+
description: deployed ? "Deployed to production" : "Deploy failed",
|
|
358
|
+
target_url: `https://deploy.example.com/${repo.name}/${sha.slice(0, 7)}`,
|
|
359
|
+
creator: actionsBot,
|
|
360
|
+
created_at: later(mergedAt, minute, 10 * minute),
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const issueClosed = fixed && mergedAt ? mergedAt : null;
|
|
365
|
+
const issueId = 1_200_000_000n + id;
|
|
366
|
+
|
|
367
|
+
rows.issues.push({
|
|
368
|
+
id: issueId,
|
|
369
|
+
version: new Date(
|
|
370
|
+
Math.max(
|
|
371
|
+
opened.getTime(),
|
|
372
|
+
issueClosed?.getTime() ?? 0,
|
|
373
|
+
...issueComments.map((row) => row.created_at.getTime()),
|
|
374
|
+
),
|
|
375
|
+
),
|
|
376
|
+
node_id: nodeId("I", issueId),
|
|
377
|
+
repository_id: repoId,
|
|
378
|
+
number: issueNumber,
|
|
379
|
+
title,
|
|
380
|
+
body: `${faker.hacker.phrase()}\n\nSteps to reproduce are in the thread.`,
|
|
381
|
+
state: issueClosed ? "closed" : "open",
|
|
382
|
+
state_reason: issueClosed ? "completed" : null,
|
|
383
|
+
locked: false,
|
|
384
|
+
user: faker.helpers.arrayElement(people),
|
|
385
|
+
author_association: "MEMBER",
|
|
386
|
+
labels: [label],
|
|
387
|
+
assignees: [author],
|
|
388
|
+
milestone: null,
|
|
389
|
+
comments: BigInt(issueComments.length),
|
|
390
|
+
created_at: opened,
|
|
391
|
+
closed_at: issueClosed,
|
|
392
|
+
html_url: `${urlOf(repo)}/issues/${issueNumber}`,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Every fifth round a repository ships a release.
|
|
396
|
+
if (round % 5 === 4 && mergedAt) {
|
|
397
|
+
const releaseId = 4_000_000_000n + id;
|
|
398
|
+
const tag = `v1.${Math.floor(round / 5)}.0`;
|
|
399
|
+
|
|
400
|
+
rows.releases.push({
|
|
401
|
+
id: releaseId,
|
|
402
|
+
version: mergedAt,
|
|
403
|
+
node_id: nodeId("RE", releaseId),
|
|
404
|
+
repository_id: repoId,
|
|
405
|
+
tag_name: tag,
|
|
406
|
+
target_commitish: "main",
|
|
407
|
+
name: tag,
|
|
408
|
+
body: `## What's changed\n\n- ${title} (#${prNumber})`,
|
|
409
|
+
draft: false,
|
|
410
|
+
prerelease: false,
|
|
411
|
+
author,
|
|
412
|
+
assets: [],
|
|
413
|
+
created_at: mergedAt,
|
|
414
|
+
published_at: mergedAt,
|
|
415
|
+
html_url: `${urlOf(repo)}/releases/tag/${tag}`,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return rows;
|
|
420
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ConnectorApp, Demo, RuntimeConfig } from "@useairfoil/connector-kit";
|
|
2
|
+
import { Command } from "effect/cli";
|
|
3
|
+
|
|
4
|
+
import { CheckRunSchema } from "../schemas/check-runs";
|
|
5
|
+
import { CommitStatusSchema } from "../schemas/commit-statuses";
|
|
6
|
+
import { CommitSchema } from "../schemas/commits";
|
|
7
|
+
import { IssueCommentSchema } from "../schemas/issue-comments";
|
|
8
|
+
import { IssueSchema } from "../schemas/issues";
|
|
9
|
+
import { PullRequestCommitSchema } from "../schemas/pull-request-commits";
|
|
10
|
+
import { PullRequestReviewCommentSchema } from "../schemas/pull-request-review-comments";
|
|
11
|
+
import { PullRequestReviewSchema } from "../schemas/pull-request-reviews";
|
|
12
|
+
import { PullRequestSchema } from "../schemas/pull-requests";
|
|
13
|
+
import { ReleaseSchema } from "../schemas/releases";
|
|
14
|
+
import { RepositorySchema } from "../schemas/repositories";
|
|
15
|
+
import { WorkflowJobSchema } from "../schemas/workflow-jobs";
|
|
16
|
+
import { WorkflowRunSchema } from "../schemas/workflow-runs";
|
|
17
|
+
import { changeRows } from "./changes";
|
|
18
|
+
import { setupRows } from "./setup";
|
|
19
|
+
|
|
20
|
+
export const demo = Demo.define({
|
|
21
|
+
name: "producer-github",
|
|
22
|
+
setup: {
|
|
23
|
+
tables: [Demo.table({ name: "repositories", rowSchema: RepositorySchema, version: "version" })],
|
|
24
|
+
rows: setupRows,
|
|
25
|
+
},
|
|
26
|
+
group: {
|
|
27
|
+
tables: [
|
|
28
|
+
Demo.table({ name: "issues", rowSchema: IssueSchema, version: "version" }),
|
|
29
|
+
Demo.table({ name: "pull_requests", rowSchema: PullRequestSchema, version: "version" }),
|
|
30
|
+
Demo.table({ name: "issue_comments", rowSchema: IssueCommentSchema, version: "version" }),
|
|
31
|
+
Demo.table({
|
|
32
|
+
name: "pull_request_reviews",
|
|
33
|
+
rowSchema: PullRequestReviewSchema,
|
|
34
|
+
version: "version",
|
|
35
|
+
}),
|
|
36
|
+
Demo.table({
|
|
37
|
+
name: "pull_request_review_comments",
|
|
38
|
+
rowSchema: PullRequestReviewCommentSchema,
|
|
39
|
+
version: "version",
|
|
40
|
+
}),
|
|
41
|
+
Demo.table({
|
|
42
|
+
name: "pull_request_commits",
|
|
43
|
+
rowSchema: PullRequestCommitSchema,
|
|
44
|
+
version: "version",
|
|
45
|
+
}),
|
|
46
|
+
Demo.table({ name: "commits", rowSchema: CommitSchema, version: "version" }),
|
|
47
|
+
Demo.table({ name: "check_runs", rowSchema: CheckRunSchema, version: "version" }),
|
|
48
|
+
Demo.table({ name: "commit_statuses", rowSchema: CommitStatusSchema, version: "version" }),
|
|
49
|
+
Demo.table({ name: "workflow_runs", rowSchema: WorkflowRunSchema, version: "version" }),
|
|
50
|
+
Demo.table({ name: "workflow_jobs", rowSchema: WorkflowJobSchema, version: "version" }),
|
|
51
|
+
Demo.table({ name: "releases", rowSchema: ReleaseSchema, version: "version" }),
|
|
52
|
+
],
|
|
53
|
+
rows: changeRows,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export const demoCommand = ConnectorApp.makeDemoCommand(demo).pipe(
|
|
58
|
+
Command.provide(RuntimeConfig.layerHosted()),
|
|
59
|
+
);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Demo } from "@useairfoil/connector-kit";
|
|
2
|
+
|
|
3
|
+
import type { Repository } from "../schemas/repositories";
|
|
4
|
+
|
|
5
|
+
import { day, nodeId, org, owner, repositories, repositoryId, urlOf } from "./shared";
|
|
6
|
+
|
|
7
|
+
/** The repositories, written once before any change. */
|
|
8
|
+
export const setupRows = ({ now }: Demo.DemoContext) => {
|
|
9
|
+
const created = new Date(now.getTime() - 900 * day);
|
|
10
|
+
|
|
11
|
+
const rows: Array<Repository> = repositories.map((repo, r) => ({
|
|
12
|
+
id: repositoryId(r),
|
|
13
|
+
version: now,
|
|
14
|
+
node_id: nodeId("R", repositoryId(r)),
|
|
15
|
+
name: repo.name,
|
|
16
|
+
full_name: `${org}/${repo.name}`,
|
|
17
|
+
owner,
|
|
18
|
+
private: repo.name !== "sdk-js" && repo.name !== "docs",
|
|
19
|
+
visibility: repo.name === "sdk-js" || repo.name === "docs" ? "public" : "private",
|
|
20
|
+
description: repo.description,
|
|
21
|
+
fork: false,
|
|
22
|
+
archived: false,
|
|
23
|
+
disabled: false,
|
|
24
|
+
default_branch: "main",
|
|
25
|
+
language: repo.language,
|
|
26
|
+
topics: [...repo.topics],
|
|
27
|
+
html_url: urlOf(repo),
|
|
28
|
+
created_at: new Date(created.getTime() + r * 30 * day),
|
|
29
|
+
// Deleted repositories can be restored, so live rows say they aren't deleted.
|
|
30
|
+
_deleted: false,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
return { repositories: rows };
|
|
34
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Demo } from "@useairfoil/connector-kit";
|
|
2
|
+
|
|
3
|
+
import { Duration } from "effect";
|
|
4
|
+
|
|
5
|
+
import type { CheckRun } from "../schemas/check-runs";
|
|
6
|
+
import type { CommitStatus } from "../schemas/commit-statuses";
|
|
7
|
+
import type { Commit } from "../schemas/commits";
|
|
8
|
+
import type { IssueComment } from "../schemas/issue-comments";
|
|
9
|
+
import type { Issue } from "../schemas/issues";
|
|
10
|
+
import type { PullRequestCommit } from "../schemas/pull-request-commits";
|
|
11
|
+
import type { PullRequestReviewComment } from "../schemas/pull-request-review-comments";
|
|
12
|
+
import type { PullRequestReview } from "../schemas/pull-request-reviews";
|
|
13
|
+
import type { PullRequest } from "../schemas/pull-requests";
|
|
14
|
+
import type { Release } from "../schemas/releases";
|
|
15
|
+
import type { WorkflowJob } from "../schemas/workflow-jobs";
|
|
16
|
+
import type { WorkflowRun } from "../schemas/workflow-runs";
|
|
17
|
+
|
|
18
|
+
export const day = Duration.toMillis(Duration.days(1));
|
|
19
|
+
export const minute = Duration.toMillis(Duration.minutes(1));
|
|
20
|
+
export const org = "acme-labs";
|
|
21
|
+
|
|
22
|
+
export type Account = { readonly id: bigint; readonly login: string; readonly type: string };
|
|
23
|
+
|
|
24
|
+
export const owner: Account = { id: 91_000_000n, login: org, type: "Organization" };
|
|
25
|
+
|
|
26
|
+
export const people: ReadonlyArray<Account> = [
|
|
27
|
+
"mara-ellis",
|
|
28
|
+
"dkowalski",
|
|
29
|
+
"jin-park",
|
|
30
|
+
"sofia-rojas",
|
|
31
|
+
"tbrennan",
|
|
32
|
+
"amir-haddad",
|
|
33
|
+
"lucy-chen",
|
|
34
|
+
"oscar-mendez",
|
|
35
|
+
"priya-nair",
|
|
36
|
+
"felix-weber",
|
|
37
|
+
"nadia-kova",
|
|
38
|
+
"ben-ortiz",
|
|
39
|
+
].map((login, k) => ({ id: BigInt(50_000_000 + k), login, type: "User" }));
|
|
40
|
+
|
|
41
|
+
export const actionsBot: Account = { id: 41_898_282n, login: "github-actions[bot]", type: "Bot" };
|
|
42
|
+
|
|
43
|
+
export const repositories = [
|
|
44
|
+
{ name: "api", language: "Go", topics: ["api", "backend"], description: "Public REST API" },
|
|
45
|
+
{ name: "web", language: "TypeScript", topics: ["frontend", "react"], description: "Web app" },
|
|
46
|
+
{ name: "mobile", language: "Kotlin", topics: ["android"], description: "Android app" },
|
|
47
|
+
{ name: "infra", language: "HCL", topics: ["terraform"], description: "Cloud infrastructure" },
|
|
48
|
+
{ name: "docs", language: "MDX", topics: ["documentation"], description: "Product docs" },
|
|
49
|
+
{ name: "sdk-js", language: "TypeScript", topics: ["sdk"], description: "JavaScript SDK" },
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
type RepositoryItem = (typeof repositories)[number];
|
|
53
|
+
|
|
54
|
+
export const repositoryId = (r: number) => BigInt(700_000_000 + r);
|
|
55
|
+
|
|
56
|
+
export const labels = [
|
|
57
|
+
{ id: 6_100_000_001n, name: "bug" },
|
|
58
|
+
{ id: 6_100_000_002n, name: "enhancement" },
|
|
59
|
+
{ id: 6_100_000_003n, name: "documentation" },
|
|
60
|
+
{ id: 6_100_000_004n, name: "good first issue" },
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
export const verbs = ["Fix", "Add", "Improve", "Update", "Remove", "Refactor", "Support"] as const;
|
|
64
|
+
|
|
65
|
+
export const paths = [
|
|
66
|
+
"src/server.ts",
|
|
67
|
+
"src/client.ts",
|
|
68
|
+
"src/routes/users.ts",
|
|
69
|
+
"src/lib/cache.ts",
|
|
70
|
+
"README.md",
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
// GitHub node IDs are base64 data. A hex form is close enough for demo rows.
|
|
74
|
+
export const nodeId = (prefix: string, id: bigint) =>
|
|
75
|
+
`${prefix}_kwDO${id.toString(16).toUpperCase()}`;
|
|
76
|
+
export const urlOf = (repo: RepositoryItem) => `https://github.com/${org}/${repo.name}`;
|
|
77
|
+
|
|
78
|
+
/** Date helpers for one run. `at` keeps a time from going past now. */
|
|
79
|
+
export const clock = ({ faker, now }: Demo.DemoContext) => {
|
|
80
|
+
const at = (time: number) => new Date(Math.min(time, now.getTime()));
|
|
81
|
+
|
|
82
|
+
const later = (from: Date, min: number, max: number) =>
|
|
83
|
+
at(from.getTime() + faker.number.int({ min, max }));
|
|
84
|
+
|
|
85
|
+
return { at, later };
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export type Rows = {
|
|
89
|
+
readonly issues: Array<Issue>;
|
|
90
|
+
readonly pull_requests: Array<PullRequest>;
|
|
91
|
+
readonly issue_comments: Array<IssueComment>;
|
|
92
|
+
readonly pull_request_reviews: Array<PullRequestReview>;
|
|
93
|
+
readonly pull_request_review_comments: Array<PullRequestReviewComment>;
|
|
94
|
+
readonly pull_request_commits: Array<PullRequestCommit>;
|
|
95
|
+
readonly commits: Array<Commit>;
|
|
96
|
+
readonly check_runs: Array<CheckRun>;
|
|
97
|
+
readonly commit_statuses: Array<CommitStatus>;
|
|
98
|
+
readonly workflow_runs: Array<WorkflowRun>;
|
|
99
|
+
readonly workflow_jobs: Array<WorkflowJob>;
|
|
100
|
+
readonly releases: Array<Release>;
|
|
101
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * as GitHubAuth from "./client/auth";
|
|
2
|
+
export * as GitHubClient from "./client/client";
|
|
3
|
+
export * as GitHubConnector from "./connector";
|
|
4
|
+
export { manifest } from "./manifest";
|
|
5
|
+
export type { IssueComment } from "./schemas/issue-comments";
|
|
6
|
+
export { IssueCommentObjectSchema, IssueCommentSchema } from "./schemas/issue-comments";
|
|
7
|
+
export type { Issue } from "./schemas/issues";
|
|
8
|
+
export { IssueObjectSchema, IssueSchema } from "./schemas/issues";
|
|
9
|
+
export type { PullRequest } from "./schemas/pull-requests";
|
|
10
|
+
export { PullRequestObjectSchema, PullRequestSchema } from "./schemas/pull-requests";
|
|
11
|
+
export type { Repository } from "./schemas/repositories";
|
|
12
|
+
export { RepositoryObjectSchema, RepositorySchema } from "./schemas/repositories";
|
|
13
|
+
export { webhookPath } from "./webhook/route";
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
4
|
+
import { Effect, Layer } from "effect";
|
|
5
|
+
import { Command } from "effect/cli";
|
|
6
|
+
import { FetchHttpClient } from "effect/http";
|
|
7
|
+
|
|
8
|
+
import packageJson from "../package.json";
|
|
9
|
+
import { createTableCommand } from "./create-table";
|
|
10
|
+
import { demoCommand } from "./demo";
|
|
11
|
+
import { sandboxCommand } from "./sandbox";
|
|
12
|
+
import { startCommand } from "./start";
|
|
13
|
+
|
|
14
|
+
const BootstrapLayer = Layer.mergeAll(FetchHttpClient.layer, NodeServices.layer);
|
|
15
|
+
|
|
16
|
+
const program = Command.make("producer-github", {}, () => Effect.void).pipe(
|
|
17
|
+
Command.withSubcommands([startCommand, sandboxCommand, createTableCommand, demoCommand]),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const cli = Command.run(program, { version: packageJson.version });
|
|
21
|
+
|
|
22
|
+
NodeRuntime.runMain(cli.pipe(Effect.provide(BootstrapLayer), Effect.scoped));
|