@pepys/source-github 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/package.json +6 -5
- package/src/api/serve-api.ts +2 -1
- package/src/generated/github-deploy-boundary.ts +18 -2
- package/src/generated/github-pull-request-boundary.ts +17 -1
- package/src/generated/github-ref-boundary.ts +17 -1
- package/src/generated/github-release-boundary.ts +17 -1
- package/src/generated/github-release.sql +2 -1
- package/src/github-release-consumer.ts +3 -1
- package/src/ingest/recovery/pull-failed-deliveries.ts +1 -1
- package/src/ingest/resync/collect-resync-targets.ts +2 -2
- package/src/ingest/resync/pull-marked-objects.ts +1 -1
- package/src/queries/pull-request-delivery-query.ts +6 -5
- package/src/queries/select-pull-request-delivery.ts +11 -9
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="../../docs/README.md">Documentation</a> •
|
|
11
|
-
<a href="../../docs/
|
|
11
|
+
<a href="../../docs/architecture/plug-ins/github.md">The GitHub plug-in</a>
|
|
12
12
|
</p>
|
|
13
13
|
</div>
|
|
14
14
|
|
|
@@ -20,7 +20,23 @@ with its consumer.
|
|
|
20
20
|
## Install
|
|
21
21
|
|
|
22
22
|
```sh
|
|
23
|
-
bun add @pepys/source-github
|
|
23
|
+
bun add @pepys/source-github @pepys/kit
|
|
24
|
+
bun add -d @pepys/cli
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Add the plug-in to a deployment, then build its consumers. The build compiles each consumer, which
|
|
28
|
+
needs zig and wasm-tools, as the [CLI README](../cli/README.md) says.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// deployment.ts
|
|
32
|
+
import { defineDeployment } from '@pepys/kit';
|
|
33
|
+
import { githubPlugin } from '@pepys/source-github';
|
|
34
|
+
|
|
35
|
+
export const deployment = defineDeployment({ name: 'home', plugins: [githubPlugin] });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
bunx pepys build deployment.ts --out build
|
|
24
40
|
```
|
|
25
41
|
|
|
26
42
|
## Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pepys/source-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "The pepys GitHub plug-in: pull requests, releases, commits and deploys",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@pepys/api": "0.
|
|
23
|
-
"@pepys/ingest": "0.
|
|
24
|
-
"@pepys/kit": "0.
|
|
22
|
+
"@pepys/api": "0.3.1",
|
|
23
|
+
"@pepys/ingest": "0.3.1",
|
|
24
|
+
"@pepys/kit": "0.3.1",
|
|
25
25
|
"@zgeoff/std": "0.4.3",
|
|
26
26
|
"kysely": "0.29.8",
|
|
27
27
|
"ts-pattern": "5.9.2",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@msw/data": "1.1.8",
|
|
32
|
-
"@
|
|
32
|
+
"@orpc/client": "2.0.0-beta.50",
|
|
33
|
+
"@pepys/testing": "0.3.1",
|
|
33
34
|
"msw": "3.0.3",
|
|
34
35
|
"tiny-invariant": "1.3.3"
|
|
35
36
|
}
|
package/src/api/serve-api.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { serveAPI } from '@pepys/api';
|
|
|
2
2
|
import { defineDeployment } from '@pepys/kit';
|
|
3
3
|
import { githubPlugin } from '../github-plugin.ts';
|
|
4
4
|
|
|
5
|
-
serveAPI({
|
|
5
|
+
await serveAPI({
|
|
6
6
|
deployment: defineDeployment({ name: 'github', plugins: [githubPlugin] }),
|
|
7
7
|
environment: process.env,
|
|
8
|
+
argv: process.argv.slice(2),
|
|
8
9
|
});
|
|
@@ -85,6 +85,10 @@ export function updateGithubDeployModel(model: GithubDeployModel, message: Githu
|
|
|
85
85
|
return message.kind === 'reset' ? initGithubDeployModel() : { ...model, input: message.input };
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
declare const factTag: unique symbol;
|
|
89
|
+
|
|
90
|
+
export type FactID = string & { readonly [factTag]: 'FactID' };
|
|
91
|
+
|
|
88
92
|
export interface GithubRefPushedPayload {
|
|
89
93
|
ref: string;
|
|
90
94
|
repository: GithubRefPushedPayloadRepository;
|
|
@@ -103,8 +107,8 @@ export interface GithubDeploymentPayloadDeployment {
|
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
export type GithubDeployFact =
|
|
106
|
-
| { id:
|
|
107
|
-
| { id:
|
|
110
|
+
| { id: FactID; type: 'github.ref.pushed'; entity: EntityID; at: string; payload: GithubRefPushedPayload }
|
|
111
|
+
| { id: FactID; type: 'github.deployment.created' | 'github.deployment.status_created'; entity: EntityID; at: string; payload: GithubDeploymentPayload };
|
|
108
112
|
|
|
109
113
|
export function parseGithubDeployFact(factJSON: string): GithubDeployFact | undefined {
|
|
110
114
|
const parsed: unknown = JSON.parse(factJSON);
|
|
@@ -127,6 +131,10 @@ function decodeGithubDeployFact(value: unknown): GithubDeployFact | undefined {
|
|
|
127
131
|
return undefined;
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
if (!isFactID(id) || !isFactEntityID(entity)) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
130
138
|
if (type === 'github.ref.pushed') {
|
|
131
139
|
const decoded = decodeGithubRefPushedPayload(payload);
|
|
132
140
|
|
|
@@ -150,6 +158,14 @@ function decodeGithubDeployFact(value: unknown): GithubDeployFact | undefined {
|
|
|
150
158
|
return undefined;
|
|
151
159
|
}
|
|
152
160
|
|
|
161
|
+
function isFactID(text: string): text is FactID {
|
|
162
|
+
return text.length > 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function isFactEntityID(text: string): text is EntityID {
|
|
166
|
+
return text.length > 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
153
169
|
function decodeGithubRefPushedPayload(value: unknown): GithubRefPushedPayload | undefined {
|
|
154
170
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
155
171
|
return undefined;
|
|
@@ -45,6 +45,10 @@ export function updateGithubPullRequestModel(model: GithubPullRequestModel, mess
|
|
|
45
45
|
return message.kind === 'reset' ? initGithubPullRequestModel() : { ...model, input: message.input };
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
declare const factTag: unique symbol;
|
|
49
|
+
|
|
50
|
+
export type FactID = string & { readonly [factTag]: 'FactID' };
|
|
51
|
+
|
|
48
52
|
export interface GithubPullRequestPayload {
|
|
49
53
|
action: string;
|
|
50
54
|
pull_request: GithubPullRequestPayloadPullRequest;
|
|
@@ -56,7 +60,7 @@ export interface GithubPullRequestPayloadPullRequest {
|
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
export type GithubPullRequestFact =
|
|
59
|
-
| { id:
|
|
63
|
+
| { id: FactID; type: 'github.pull_request.assigned' | 'github.pull_request.auto_merge_disabled' | 'github.pull_request.auto_merge_enabled' | 'github.pull_request.closed' | 'github.pull_request.converted_to_draft' | 'github.pull_request.demilestoned' | 'github.pull_request.dequeued' | 'github.pull_request.edited' | 'github.pull_request.enqueued' | 'github.pull_request.labeled' | 'github.pull_request.locked' | 'github.pull_request.milestoned' | 'github.pull_request.opened' | 'github.pull_request.ready_for_review' | 'github.pull_request.reopened' | 'github.pull_request.resynced' | 'github.pull_request.review_request_removed' | 'github.pull_request.review_requested' | 'github.pull_request.synchronize' | 'github.pull_request.unassigned' | 'github.pull_request.unlabeled' | 'github.pull_request.unlocked'; entity: EntityID; at: string; payload: GithubPullRequestPayload };
|
|
60
64
|
|
|
61
65
|
export function parseGithubPullRequestFact(factJSON: string): GithubPullRequestFact | undefined {
|
|
62
66
|
const parsed: unknown = JSON.parse(factJSON);
|
|
@@ -79,6 +83,10 @@ function decodeGithubPullRequestFact(value: unknown): GithubPullRequestFact | un
|
|
|
79
83
|
return undefined;
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
if (!isFactID(id) || !isFactEntityID(entity)) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
82
90
|
if (type === 'github.pull_request.assigned' || type === 'github.pull_request.auto_merge_disabled' || type === 'github.pull_request.auto_merge_enabled' || type === 'github.pull_request.closed' || type === 'github.pull_request.converted_to_draft' || type === 'github.pull_request.demilestoned' || type === 'github.pull_request.dequeued' || type === 'github.pull_request.edited' || type === 'github.pull_request.enqueued' || type === 'github.pull_request.labeled' || type === 'github.pull_request.locked' || type === 'github.pull_request.milestoned' || type === 'github.pull_request.opened' || type === 'github.pull_request.ready_for_review' || type === 'github.pull_request.reopened' || type === 'github.pull_request.resynced' || type === 'github.pull_request.review_request_removed' || type === 'github.pull_request.review_requested' || type === 'github.pull_request.synchronize' || type === 'github.pull_request.unassigned' || type === 'github.pull_request.unlabeled' || type === 'github.pull_request.unlocked') {
|
|
83
91
|
const decoded = decodeGithubPullRequestPayload(payload);
|
|
84
92
|
|
|
@@ -92,6 +100,14 @@ function decodeGithubPullRequestFact(value: unknown): GithubPullRequestFact | un
|
|
|
92
100
|
return undefined;
|
|
93
101
|
}
|
|
94
102
|
|
|
103
|
+
function isFactID(text: string): text is FactID {
|
|
104
|
+
return text.length > 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isFactEntityID(text: string): text is EntityID {
|
|
108
|
+
return text.length > 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
95
111
|
function decodeGithubPullRequestPayload(value: unknown): GithubPullRequestPayload | undefined {
|
|
96
112
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
97
113
|
return undefined;
|
|
@@ -45,6 +45,10 @@ export function updateGithubRefModel(model: GithubRefModel, message: GithubRefMe
|
|
|
45
45
|
return message.kind === 'reset' ? initGithubRefModel() : { ...model, input: message.input };
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
declare const factTag: unique symbol;
|
|
49
|
+
|
|
50
|
+
export type FactID = string & { readonly [factTag]: 'FactID' };
|
|
51
|
+
|
|
48
52
|
export interface GithubRefPushedPayload {
|
|
49
53
|
ref: string;
|
|
50
54
|
repository: GithubRefPushedPayloadRepository;
|
|
@@ -55,7 +59,7 @@ export interface GithubRefPushedPayloadRepository {
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export type GithubRefFact =
|
|
58
|
-
| { id:
|
|
62
|
+
| { id: FactID; type: 'github.ref.pushed'; entity: EntityID; at: string; payload: GithubRefPushedPayload };
|
|
59
63
|
|
|
60
64
|
export function parseGithubRefFact(factJSON: string): GithubRefFact | undefined {
|
|
61
65
|
const parsed: unknown = JSON.parse(factJSON);
|
|
@@ -78,6 +82,10 @@ function decodeGithubRefFact(value: unknown): GithubRefFact | undefined {
|
|
|
78
82
|
return undefined;
|
|
79
83
|
}
|
|
80
84
|
|
|
85
|
+
if (!isFactID(id) || !isFactEntityID(entity)) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
81
89
|
if (type === 'github.ref.pushed') {
|
|
82
90
|
const decoded = decodeGithubRefPushedPayload(payload);
|
|
83
91
|
|
|
@@ -91,6 +99,14 @@ function decodeGithubRefFact(value: unknown): GithubRefFact | undefined {
|
|
|
91
99
|
return undefined;
|
|
92
100
|
}
|
|
93
101
|
|
|
102
|
+
function isFactID(text: string): text is FactID {
|
|
103
|
+
return text.length > 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isFactEntityID(text: string): text is EntityID {
|
|
107
|
+
return text.length > 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
94
110
|
function decodeGithubRefPushedPayload(value: unknown): GithubRefPushedPayload | undefined {
|
|
95
111
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
96
112
|
return undefined;
|
|
@@ -45,6 +45,10 @@ export function updateGithubReleaseModel(model: GithubReleaseModel, message: Git
|
|
|
45
45
|
return message.kind === 'reset' ? initGithubReleaseModel() : { ...model, input: message.input };
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
declare const factTag: unique symbol;
|
|
49
|
+
|
|
50
|
+
export type FactID = string & { readonly [factTag]: 'FactID' };
|
|
51
|
+
|
|
48
52
|
export interface GithubReleasePayload {
|
|
49
53
|
action: string;
|
|
50
54
|
release: GithubReleasePayloadRelease;
|
|
@@ -55,7 +59,7 @@ export interface GithubReleasePayloadRelease {
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export type GithubReleaseFact =
|
|
58
|
-
| { id:
|
|
62
|
+
| { id: FactID; type: 'github.release.created' | 'github.release.deleted' | 'github.release.edited' | 'github.release.prereleased' | 'github.release.published' | 'github.release.released' | 'github.release.resynced' | 'github.release.unpublished'; entity: EntityID; at: string; payload: GithubReleasePayload };
|
|
59
63
|
|
|
60
64
|
export function parseGithubReleaseFact(factJSON: string): GithubReleaseFact | undefined {
|
|
61
65
|
const parsed: unknown = JSON.parse(factJSON);
|
|
@@ -78,6 +82,10 @@ function decodeGithubReleaseFact(value: unknown): GithubReleaseFact | undefined
|
|
|
78
82
|
return undefined;
|
|
79
83
|
}
|
|
80
84
|
|
|
85
|
+
if (!isFactID(id) || !isFactEntityID(entity)) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
81
89
|
if (type === 'github.release.created' || type === 'github.release.deleted' || type === 'github.release.edited' || type === 'github.release.prereleased' || type === 'github.release.published' || type === 'github.release.released' || type === 'github.release.resynced' || type === 'github.release.unpublished') {
|
|
82
90
|
const decoded = decodeGithubReleasePayload(payload);
|
|
83
91
|
|
|
@@ -91,6 +99,14 @@ function decodeGithubReleaseFact(value: unknown): GithubReleaseFact | undefined
|
|
|
91
99
|
return undefined;
|
|
92
100
|
}
|
|
93
101
|
|
|
102
|
+
function isFactID(text: string): text is FactID {
|
|
103
|
+
return text.length > 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isFactEntityID(text: string): text is EntityID {
|
|
107
|
+
return text.length > 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
94
110
|
function decodeGithubReleasePayload(value: unknown): GithubReleasePayload | undefined {
|
|
95
111
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
96
112
|
return undefined;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { defineConsumer, defineTable } from '@pepys/kit';
|
|
2
2
|
import { releaseFamily } from './families/release-family.ts';
|
|
3
3
|
|
|
4
|
-
// One row per release, never deleted: a release GitHub deleted keeps its row with `deleted_at
|
|
4
|
+
// One row per release, never deleted: a release GitHub deleted keeps its row with `deleted_at`,
|
|
5
|
+
// which leaves it out of the `entity` view.
|
|
5
6
|
export const githubReleaseConsumer = defineConsumer({
|
|
6
7
|
name: 'github_release',
|
|
7
8
|
entry: new URL('consumers/github-release.ts', import.meta.url),
|
|
@@ -36,6 +37,7 @@ export const githubReleaseConsumer = defineConsumer({
|
|
|
36
37
|
url: 'url',
|
|
37
38
|
actor: null,
|
|
38
39
|
updatedAt: 'updated_at',
|
|
40
|
+
deletedAt: 'deleted_at',
|
|
39
41
|
},
|
|
40
42
|
],
|
|
41
43
|
reads: ['github_release'],
|
|
@@ -19,7 +19,7 @@ export async function pullFailedDeliveries(
|
|
|
19
19
|
cursor: string | null,
|
|
20
20
|
context: PullContext,
|
|
21
21
|
): Promise<Pulled> {
|
|
22
|
-
const appJWT = findAppJWT(context.env,
|
|
22
|
+
const appJWT = findAppJWT(context.env, context.now());
|
|
23
23
|
|
|
24
24
|
if (appJWT === undefined) {
|
|
25
25
|
return { kind: 'rejected', reason: 'the GitHub App private key cannot sign a token' };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { ResyncMark } from '@pepys/kit';
|
|
1
|
+
import type { EntityID, ResyncMark } from '@pepys/kit';
|
|
2
2
|
|
|
3
3
|
// One marked object that the resync pull reads again: its repository, `owner/name`, its API path,
|
|
4
4
|
// and the digest of the last body ingest stored for it.
|
|
5
5
|
export interface ResyncTarget {
|
|
6
6
|
kind: 'pull_request' | 'release';
|
|
7
|
-
entity:
|
|
7
|
+
entity: EntityID;
|
|
8
8
|
repository: string;
|
|
9
9
|
path: string;
|
|
10
10
|
lastBodyDigest: string | undefined;
|
|
@@ -23,7 +23,7 @@ export async function pullMarkedObjects(
|
|
|
23
23
|
return { kind: 'batch', batch: { facts: [] }, cursor: 'resynced', isDone: true };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const appJWT = findAppJWT(context.env,
|
|
26
|
+
const appJWT = findAppJWT(context.env, context.now());
|
|
27
27
|
|
|
28
28
|
if (appJWT === undefined) {
|
|
29
29
|
return { kind: 'rejected', reason: 'the GitHub App private key cannot sign a token' };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineQuery } from '@pepys/kit';
|
|
1
|
+
import { defineQuery, entityIDSchema, isEntityID } from '@pepys/kit';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { deploySignals } from '../utils/deploy-signals.ts';
|
|
4
4
|
import { githubDeliveryConsumers } from './github-delivery-consumers.ts';
|
|
@@ -9,12 +9,12 @@ import {
|
|
|
9
9
|
|
|
10
10
|
const pullRequestsSchema = z.array(z.string()).max(200);
|
|
11
11
|
const nameSchema = z.string().min(1);
|
|
12
|
-
const releaseSchema = z.object({ id:
|
|
12
|
+
const releaseSchema = z.object({ id: entityIDSchema, tag: z.string(), at: z.string() });
|
|
13
13
|
const signalSchema = z.enum(deploySignals);
|
|
14
|
-
const deploySchema = z.object({ id:
|
|
14
|
+
const deploySchema = z.object({ id: entityIDSchema, at: z.string(), signal: signalSchema });
|
|
15
15
|
|
|
16
16
|
const deliverySchema = z.object({
|
|
17
|
-
pullRequest:
|
|
17
|
+
pullRequest: entityIDSchema,
|
|
18
18
|
mergedAt: z.string().nullable(),
|
|
19
19
|
release: releaseSchema.nullable(),
|
|
20
20
|
deploy: deploySchema.nullable(),
|
|
@@ -32,7 +32,8 @@ export const pullRequestDeliveryQuery = defineQuery({
|
|
|
32
32
|
output: z.array(deliverySchema),
|
|
33
33
|
reads: githubDeliveryConsumers,
|
|
34
34
|
handler: async (call) => {
|
|
35
|
-
|
|
35
|
+
// text that is no entity ID names no stored pull request, so it has no row either way
|
|
36
|
+
const [first, ...rest] = call.input.pullRequests.filter((id) => isEntityID(id));
|
|
36
37
|
|
|
37
38
|
if (first === undefined) {
|
|
38
39
|
return [];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { entityIDSchema } from '@pepys/kit';
|
|
2
|
+
import type { EntityID } from '@pepys/kit';
|
|
1
3
|
import { sql } from 'kysely';
|
|
2
4
|
import type { RawBuilder } from 'kysely';
|
|
3
5
|
import { z } from 'zod';
|
|
@@ -6,7 +8,7 @@ import type { DeploySignal } from '../utils/deploy-signals.ts';
|
|
|
6
8
|
|
|
7
9
|
interface DeliveryOptions {
|
|
8
10
|
// at least one
|
|
9
|
-
pullRequests: readonly [
|
|
11
|
+
pullRequests: readonly [EntityID, ...EntityID[]];
|
|
10
12
|
environment: string;
|
|
11
13
|
|
|
12
14
|
// Absent: a deploy of any target, and of none, counts. Given: only a deploy of that target.
|
|
@@ -14,8 +16,8 @@ interface DeliveryOptions {
|
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
// The statement that ties pull requests to releases and deploys. The rules it holds are in the
|
|
17
|
-
// "
|
|
18
|
-
// into deliveries with the parse function below.
|
|
19
|
+
// "The delivery query" section of docs/architecture/plug-ins/github.md. Run it with `.execute(db)`,
|
|
20
|
+
// and turn its rows into deliveries with the parse function below.
|
|
19
21
|
export function selectPullRequestDelivery(options: DeliveryOptions): RawBuilder<unknown> {
|
|
20
22
|
return sql`select
|
|
21
23
|
pull_request.id as "pullRequest",
|
|
@@ -115,22 +117,22 @@ function selectFirstDeployID(options: DeliveryOptions): RawBuilder<unknown> {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
export interface PullRequestDelivery {
|
|
118
|
-
pullRequest:
|
|
120
|
+
pullRequest: EntityID;
|
|
119
121
|
mergedAt: string | null;
|
|
120
|
-
release: { id:
|
|
121
|
-
deploy: { id:
|
|
122
|
+
release: { id: EntityID; tag: string; at: string } | null;
|
|
123
|
+
deploy: { id: EntityID; at: string; signal: DeploySignal } | null;
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
const textSchema = z.string().nullable();
|
|
125
127
|
|
|
126
128
|
// One row per pull request, as the statement selects it.
|
|
127
129
|
const deliveryRowSchema = z.object({
|
|
128
|
-
pullRequest:
|
|
130
|
+
pullRequest: entityIDSchema,
|
|
129
131
|
mergedAt: textSchema,
|
|
130
|
-
releaseID:
|
|
132
|
+
releaseID: entityIDSchema.nullable(),
|
|
131
133
|
releaseTag: textSchema,
|
|
132
134
|
releaseAt: textSchema,
|
|
133
|
-
deployID:
|
|
135
|
+
deployID: entityIDSchema.nullable(),
|
|
134
136
|
deployAt: textSchema,
|
|
135
137
|
deploySignal: z.enum(deploySignals).nullable(),
|
|
136
138
|
});
|