@sentry/junior-github 0.129.0 → 0.130.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/README.md +5 -5
- package/SETUP.md +9 -2
- package/dist/{chunk-25NTEYYB.js → chunk-6XR7J3LQ.js} +161 -59
- package/dist/index.js +428 -257
- package/dist/resource-events/release.d.ts +13 -0
- package/dist/testing.js +1 -1
- package/dist/tools/get-release.d.ts +62 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @sentry/junior-github
|
|
2
2
|
|
|
3
|
-
`@sentry/junior-github` adds GitHub deployment, issue, pull request,
|
|
3
|
+
`@sentry/junior-github` adds GitHub deployment, issue, pull request, release,
|
|
4
4
|
repository, and user-attachment workflows to Junior using a GitHub App.
|
|
5
5
|
|
|
6
6
|
Install it alongside `@sentry/junior`:
|
|
@@ -25,7 +25,7 @@ export const plugins = defineJuniorPlugins([
|
|
|
25
25
|
|
|
26
26
|
Full setup guide: https://junior.sentry.dev/extend/github-plugin/
|
|
27
27
|
|
|
28
|
-
The plugin owns its signed webhook route, deployment
|
|
29
|
-
events, normalized pull request and issue outcome projections, and
|
|
30
|
-
operational report. Core only owns delivery from plugin-published
|
|
31
|
-
events into matching conversation subscriptions.
|
|
28
|
+
The plugin owns its signed webhook route, deployment, pull request, and release
|
|
29
|
+
resource events, normalized pull request and issue outcome projections, and
|
|
30
|
+
dashboard operational report. Core only owns delivery from plugin-published
|
|
31
|
+
resource events into matching conversation subscriptions.
|
package/SETUP.md
CHANGED
|
@@ -79,8 +79,8 @@ the App bot login from that email. Set the GitHub App webhook URL to
|
|
|
79
79
|
and Issues events. The secret in GitHub must match the deployment environment.
|
|
80
80
|
|
|
81
81
|
Conversation watches additionally use Check suite, Deployment, Deployment
|
|
82
|
-
status, Issue comment, Pull request review,
|
|
83
|
-
events.
|
|
82
|
+
status, Issue comment, Pull request review, Pull request review comment, and
|
|
83
|
+
Release events.
|
|
84
84
|
|
|
85
85
|
`github_getDeployment` reads the latest deployment and status for an exact
|
|
86
86
|
repository and commit SHA, optionally limited to one environment. When
|
|
@@ -91,6 +91,13 @@ subscription remains available when GitHub has not created the deployment yet.
|
|
|
91
91
|
Commit-wide watches remain active across terminal outcomes so later
|
|
92
92
|
environments for the same commit can also notify the conversation.
|
|
93
93
|
|
|
94
|
+
`github_getRelease` reads a release for an exact repository, optionally limited
|
|
95
|
+
to one tag. When webhooks are configured, its result can subscribe the current
|
|
96
|
+
conversation to `release.published`. Omitting the tag watches every published
|
|
97
|
+
release in the repository. The subscription remains available when GitHub has
|
|
98
|
+
not published the release yet. Tag-specific watches complete after publish;
|
|
99
|
+
repository-wide release watches remain active across later tags.
|
|
100
|
+
|
|
94
101
|
```bash
|
|
95
102
|
vercel env add GITHUB_WEBHOOK_SECRET production
|
|
96
103
|
```
|
|
@@ -103,6 +103,28 @@ function gitHubPullRequestSubscribable(input) {
|
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
// src/resource-events/release.ts
|
|
107
|
+
var GITHUB_RELEASE_EVENTS = ["release.published"];
|
|
108
|
+
var GITHUB_RELEASE_SUGGESTED_EVENTS = ["release.published"];
|
|
109
|
+
function gitHubReleaseSourceResource(input) {
|
|
110
|
+
const repo = input.repo.toLowerCase();
|
|
111
|
+
const tag = input.tag?.trim();
|
|
112
|
+
return {
|
|
113
|
+
label: `GitHub release for ${repo}`,
|
|
114
|
+
namespace: "github",
|
|
115
|
+
identifier: tag ? `release-source:${repo}:${encodeURIComponent(tag)}` : `release-source:${repo}`
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function gitHubReleaseSourceSubscribable(input) {
|
|
119
|
+
if (!process.env.GITHUB_WEBHOOK_SECRET?.trim()) return void 0;
|
|
120
|
+
return {
|
|
121
|
+
...gitHubReleaseSourceResource(input),
|
|
122
|
+
suggestedEvents: GITHUB_RELEASE_SUGGESTED_EVENTS,
|
|
123
|
+
supportedEvents: [...GITHUB_RELEASE_EVENTS],
|
|
124
|
+
type: "release_source"
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
106
128
|
// src/resource-events/repository.ts
|
|
107
129
|
function gitHubRepositoryResource(input) {
|
|
108
130
|
return {
|
|
@@ -115,8 +137,12 @@ function gitHubRepositorySubscribable(input) {
|
|
|
115
137
|
if (!process.env.GITHUB_WEBHOOK_SECRET?.trim()) return void 0;
|
|
116
138
|
return {
|
|
117
139
|
...gitHubRepositoryResource(input),
|
|
118
|
-
suggestedEvents: [
|
|
119
|
-
|
|
140
|
+
suggestedEvents: [
|
|
141
|
+
"issue.opened",
|
|
142
|
+
...GITHUB_ISSUE_SUGGESTED_EVENTS,
|
|
143
|
+
...GITHUB_PULL_REQUEST_SUGGESTED_EVENTS
|
|
144
|
+
],
|
|
145
|
+
supportedEvents: [...GITHUB_ISSUE_EVENTS, ...GITHUB_PULL_REQUEST_EVENTS],
|
|
120
146
|
type: "repository"
|
|
121
147
|
};
|
|
122
148
|
}
|
|
@@ -125,6 +151,16 @@ function gitHubRepositorySubscribable(input) {
|
|
|
125
151
|
function gitHubEventKey(deliveryId, eventType) {
|
|
126
152
|
return `github:${deliveryId}:${eventType}`;
|
|
127
153
|
}
|
|
154
|
+
function pullRequestTargets(event, repo) {
|
|
155
|
+
const { terminal: _terminal, ...repositoryEvent } = event;
|
|
156
|
+
return [
|
|
157
|
+
event,
|
|
158
|
+
{
|
|
159
|
+
...repositoryEvent,
|
|
160
|
+
identifier: gitHubRepositoryResource({ repo }).identifier
|
|
161
|
+
}
|
|
162
|
+
];
|
|
163
|
+
}
|
|
128
164
|
var repositorySchema = z.object({ full_name: z.string().min(1) }).passthrough();
|
|
129
165
|
var deploymentSchema = z.object({
|
|
130
166
|
created_at: z.string().optional(),
|
|
@@ -265,21 +301,25 @@ function normalizeCheckSuiteEvents(deliveryId, body) {
|
|
|
265
301
|
const eventType = conclusion === "failure" || conclusion === "timed_out" ? "pull_request.checks.failed" : conclusion === "success" ? "pull_request.checks.recovered" : void 0;
|
|
266
302
|
if (!eventType) return [];
|
|
267
303
|
const sha = parsed.data.check_suite.head_sha?.slice(0, 12);
|
|
268
|
-
return parsed.data.check_suite.pull_requests.
|
|
304
|
+
return parsed.data.check_suite.pull_requests.flatMap((pullRequest) => {
|
|
305
|
+
const repo = parsed.data.repository.full_name;
|
|
269
306
|
const resource = gitHubPullRequestResource({
|
|
270
307
|
number: pullRequest.number,
|
|
271
|
-
repo
|
|
308
|
+
repo
|
|
272
309
|
});
|
|
273
|
-
return
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
310
|
+
return pullRequestTargets(
|
|
311
|
+
{
|
|
312
|
+
eventKey: gitHubEventKey(
|
|
313
|
+
deliveryId,
|
|
314
|
+
`${eventType}:${pullRequest.number}`
|
|
315
|
+
),
|
|
316
|
+
eventType,
|
|
317
|
+
occurredAtMs: Date.now(),
|
|
318
|
+
identifier: resource.identifier,
|
|
319
|
+
trustedSummary: eventType === "pull_request.checks.failed" ? `${resource.label} checks failed${sha ? ` for ${sha}` : ""}.` : `${resource.label} checks recovered${sha ? ` for ${sha}` : ""}.`
|
|
320
|
+
},
|
|
321
|
+
repo
|
|
322
|
+
);
|
|
283
323
|
});
|
|
284
324
|
}
|
|
285
325
|
var issueCommentWebhookSchema = z.object({
|
|
@@ -305,7 +345,7 @@ function normalizeIssueCommentEvents(deliveryId, body) {
|
|
|
305
345
|
if (parsed.data.issue.pull_request) {
|
|
306
346
|
const eventType = "pull_request.comment.created";
|
|
307
347
|
const resource = gitHubPullRequestResource(input);
|
|
308
|
-
return
|
|
348
|
+
return pullRequestTargets(
|
|
309
349
|
{
|
|
310
350
|
eventKey: gitHubEventKey(deliveryId, eventType),
|
|
311
351
|
eventType,
|
|
@@ -313,8 +353,9 @@ function normalizeIssueCommentEvents(deliveryId, body) {
|
|
|
313
353
|
identifier: resource.identifier,
|
|
314
354
|
trustedSummary: `${resource.label} received a comment${author ? ` from ${author}` : ""}.`,
|
|
315
355
|
untrustedText: parsed.data.comment.body
|
|
316
|
-
}
|
|
317
|
-
|
|
356
|
+
},
|
|
357
|
+
input.repo
|
|
358
|
+
);
|
|
318
359
|
}
|
|
319
360
|
const issue = gitHubIssueResource(input);
|
|
320
361
|
const repository = gitHubRepositoryResource(input);
|
|
@@ -401,21 +442,25 @@ var pullRequestReviewCommentWebhookSchema = z.object({
|
|
|
401
442
|
});
|
|
402
443
|
function normalizePullRequestReviewCommentEvent(deliveryId, body) {
|
|
403
444
|
const parsed = pullRequestReviewCommentWebhookSchema.safeParse(body);
|
|
404
|
-
if (!parsed.success || parsed.data.action !== "created") return
|
|
445
|
+
if (!parsed.success || parsed.data.action !== "created") return [];
|
|
405
446
|
const eventType = "pull_request.review_comment.created";
|
|
447
|
+
const repo = parsed.data.repository.full_name;
|
|
406
448
|
const resource = gitHubPullRequestResource({
|
|
407
449
|
number: parsed.data.pull_request.number,
|
|
408
|
-
repo
|
|
450
|
+
repo
|
|
409
451
|
});
|
|
410
452
|
const author = parsed.data.comment.user?.login;
|
|
411
|
-
return
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
453
|
+
return pullRequestTargets(
|
|
454
|
+
{
|
|
455
|
+
eventKey: gitHubEventKey(deliveryId, eventType),
|
|
456
|
+
eventType,
|
|
457
|
+
occurredAtMs: Date.now(),
|
|
458
|
+
identifier: resource.identifier,
|
|
459
|
+
trustedSummary: `${resource.label} received an inline review comment${author ? ` from ${author}` : ""}.`,
|
|
460
|
+
untrustedText: parsed.data.comment.body
|
|
461
|
+
},
|
|
462
|
+
repo
|
|
463
|
+
);
|
|
419
464
|
}
|
|
420
465
|
var pullRequestReviewWebhookSchema = z.object({
|
|
421
466
|
action: z.string(),
|
|
@@ -429,23 +474,27 @@ var pullRequestReviewWebhookSchema = z.object({
|
|
|
429
474
|
});
|
|
430
475
|
function normalizePullRequestReviewEvent(deliveryId, body) {
|
|
431
476
|
const parsed = pullRequestReviewWebhookSchema.safeParse(body);
|
|
432
|
-
if (!parsed.success || parsed.data.action !== "submitted") return
|
|
477
|
+
if (!parsed.success || parsed.data.action !== "submitted") return [];
|
|
433
478
|
const reviewState = parsed.data.review.state.toUpperCase();
|
|
434
479
|
const eventType = reviewState === "APPROVED" ? "pull_request.review.approved" : reviewState === "CHANGES_REQUESTED" ? "pull_request.review.changes_requested" : reviewState === "COMMENTED" ? "pull_request.review.commented" : void 0;
|
|
435
|
-
if (!eventType) return
|
|
480
|
+
if (!eventType) return [];
|
|
481
|
+
const repo = parsed.data.repository.full_name;
|
|
436
482
|
const resource = gitHubPullRequestResource({
|
|
437
483
|
number: parsed.data.pull_request.number,
|
|
438
|
-
repo
|
|
484
|
+
repo
|
|
439
485
|
});
|
|
440
486
|
const reviewer = parsed.data.review.user?.login;
|
|
441
|
-
return
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
487
|
+
return pullRequestTargets(
|
|
488
|
+
{
|
|
489
|
+
eventKey: gitHubEventKey(deliveryId, eventType),
|
|
490
|
+
eventType,
|
|
491
|
+
occurredAtMs: Date.now(),
|
|
492
|
+
identifier: resource.identifier,
|
|
493
|
+
trustedSummary: eventType === "pull_request.review.approved" ? `${resource.label} was approved${reviewer ? ` by ${reviewer}` : ""}.` : eventType === "pull_request.review.changes_requested" ? `${resource.label} received requested changes${reviewer ? ` from ${reviewer}` : ""}.` : `${resource.label} received a review comment${reviewer ? ` from ${reviewer}` : ""}.`,
|
|
494
|
+
untrustedText: parsed.data.review.body ?? void 0
|
|
495
|
+
},
|
|
496
|
+
repo
|
|
497
|
+
);
|
|
449
498
|
}
|
|
450
499
|
var pullRequestWebhookSchema = z.object({
|
|
451
500
|
action: z.string(),
|
|
@@ -464,22 +513,76 @@ function providerTime(value) {
|
|
|
464
513
|
}
|
|
465
514
|
function normalizePullRequestEvent(deliveryId, body) {
|
|
466
515
|
const parsed = pullRequestWebhookSchema.safeParse(body);
|
|
467
|
-
if (!parsed.success || parsed.data.action !== "closed") return
|
|
516
|
+
if (!parsed.success || parsed.data.action !== "closed") return [];
|
|
468
517
|
const eventType = parsed.data.pull_request.merged ? "pull_request.merged" : "pull_request.closed_unmerged";
|
|
518
|
+
const repo = parsed.data.repository.full_name;
|
|
469
519
|
const resource = gitHubPullRequestResource({
|
|
470
520
|
number: parsed.data.pull_request.number,
|
|
471
|
-
repo
|
|
521
|
+
repo
|
|
472
522
|
});
|
|
473
|
-
return
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
523
|
+
return pullRequestTargets(
|
|
524
|
+
{
|
|
525
|
+
eventKey: gitHubEventKey(deliveryId, eventType),
|
|
526
|
+
eventType,
|
|
527
|
+
occurredAtMs: providerTime(
|
|
528
|
+
parsed.data.pull_request.merged ? parsed.data.pull_request.merged_at : parsed.data.pull_request.closed_at
|
|
529
|
+
) ?? Date.now(),
|
|
530
|
+
identifier: resource.identifier,
|
|
531
|
+
terminal: true,
|
|
532
|
+
trustedSummary: eventType === "pull_request.merged" ? `${resource.label} was merged.` : `${resource.label} was closed without being merged.`
|
|
533
|
+
},
|
|
534
|
+
repo
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
var releaseWebhookSchema = z.object({
|
|
538
|
+
action: z.string(),
|
|
539
|
+
release: z.object({
|
|
540
|
+
body: z.string().optional().nullable(),
|
|
541
|
+
draft: z.boolean().optional(),
|
|
542
|
+
id: z.number(),
|
|
543
|
+
name: z.string().optional().nullable(),
|
|
544
|
+
prerelease: z.boolean().optional(),
|
|
545
|
+
published_at: z.string().optional().nullable(),
|
|
546
|
+
tag_name: z.string().min(1)
|
|
547
|
+
}).passthrough(),
|
|
548
|
+
repository: repositorySchema
|
|
549
|
+
}).passthrough();
|
|
550
|
+
function releaseSourceTargets(input) {
|
|
551
|
+
return [
|
|
552
|
+
{
|
|
553
|
+
completeOnTerminalEvent: true,
|
|
554
|
+
resource: gitHubReleaseSourceResource(input)
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
completeOnTerminalEvent: false,
|
|
558
|
+
resource: gitHubReleaseSourceResource({ repo: input.repo })
|
|
559
|
+
}
|
|
560
|
+
];
|
|
561
|
+
}
|
|
562
|
+
function normalizeReleaseEvent(deliveryId, body) {
|
|
563
|
+
const parsed = releaseWebhookSchema.safeParse(body);
|
|
564
|
+
if (!parsed.success || parsed.data.action !== "published") return [];
|
|
565
|
+
if (parsed.data.release.draft) return [];
|
|
566
|
+
const eventType = "release.published";
|
|
567
|
+
const repo = parsed.data.repository.full_name;
|
|
568
|
+
const tag = parsed.data.release.tag_name;
|
|
569
|
+
const untrustedParts = [
|
|
570
|
+
tag ? `Tag: ${tag}` : void 0,
|
|
571
|
+
parsed.data.release.name?.trim() ? `Name: ${parsed.data.release.name.trim()}` : void 0,
|
|
572
|
+
parsed.data.release.body?.trim() || void 0
|
|
573
|
+
].filter((part) => part !== void 0);
|
|
574
|
+
const untrustedText = untrustedParts.length > 0 ? untrustedParts.join("\n\n") : void 0;
|
|
575
|
+
return releaseSourceTargets({ repo, tag }).map(
|
|
576
|
+
({ completeOnTerminalEvent, resource }) => ({
|
|
577
|
+
eventKey: gitHubEventKey(deliveryId, eventType),
|
|
578
|
+
eventType,
|
|
579
|
+
occurredAtMs: providerTime(parsed.data.release.published_at) ?? Date.now(),
|
|
580
|
+
identifier: resource.identifier,
|
|
581
|
+
...completeOnTerminalEvent ? { terminal: true } : {},
|
|
582
|
+
trustedSummary: `${resource.label} was published (release ${parsed.data.release.id}).`,
|
|
583
|
+
...untrustedText ? { untrustedText } : {}
|
|
584
|
+
})
|
|
585
|
+
);
|
|
483
586
|
}
|
|
484
587
|
function normalizeGitHubResourceEvents(args) {
|
|
485
588
|
switch (args.eventName) {
|
|
@@ -490,28 +593,24 @@ function normalizeGitHubResourceEvents(args) {
|
|
|
490
593
|
return normalizeDeploymentStatusEvent(args.deliveryId, args.body);
|
|
491
594
|
}
|
|
492
595
|
case "pull_request": {
|
|
493
|
-
|
|
494
|
-
return event ? [event] : [];
|
|
596
|
+
return normalizePullRequestEvent(args.deliveryId, args.body);
|
|
495
597
|
}
|
|
496
598
|
case "issues": {
|
|
497
599
|
return normalizeIssueEvents(args.deliveryId, args.body);
|
|
498
600
|
}
|
|
499
601
|
case "pull_request_review": {
|
|
500
|
-
|
|
501
|
-
return event ? [event] : [];
|
|
602
|
+
return normalizePullRequestReviewEvent(args.deliveryId, args.body);
|
|
502
603
|
}
|
|
503
604
|
case "issue_comment": {
|
|
504
605
|
return normalizeIssueCommentEvents(args.deliveryId, args.body);
|
|
505
606
|
}
|
|
506
607
|
case "pull_request_review_comment": {
|
|
507
|
-
|
|
508
|
-
args.deliveryId,
|
|
509
|
-
args.body
|
|
510
|
-
);
|
|
511
|
-
return event ? [event] : [];
|
|
608
|
+
return normalizePullRequestReviewCommentEvent(args.deliveryId, args.body);
|
|
512
609
|
}
|
|
513
610
|
case "check_suite":
|
|
514
611
|
return normalizeCheckSuiteEvents(args.deliveryId, args.body);
|
|
612
|
+
case "release":
|
|
613
|
+
return normalizeReleaseEvent(args.deliveryId, args.body);
|
|
515
614
|
default:
|
|
516
615
|
return [];
|
|
517
616
|
}
|
|
@@ -527,6 +626,9 @@ export {
|
|
|
527
626
|
GITHUB_PULL_REQUEST_EVENTS,
|
|
528
627
|
GITHUB_PULL_REQUEST_SUGGESTED_EVENTS,
|
|
529
628
|
gitHubPullRequestSubscribable,
|
|
629
|
+
GITHUB_RELEASE_EVENTS,
|
|
630
|
+
GITHUB_RELEASE_SUGGESTED_EVENTS,
|
|
631
|
+
gitHubReleaseSourceSubscribable,
|
|
530
632
|
gitHubRepositorySubscribable,
|
|
531
633
|
normalizeGitHubResourceEvents
|
|
532
634
|
};
|