Skip to content

Commit a1bb72e

Browse files
committed
fix(contracts): older clients still load PRs from newer servers
A server that offers a PR action an older client does not know, such as delete-branch, failed the client's whole pull request decode. Lists of actions, verdicts, merge methods, and update methods the server sends now decode with ForwardCompatibleArray, so unknown members are dropped.
1 parent a9c9c7c commit a1bb72e

2 files changed

Lines changed: 24 additions & 8 deletions

File tree

‎packages/contracts/src/pullRequest.test.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,17 @@ describe("PullRequestCapabilities", () => {
274274
expect(decodeCapabilities(base).deleteBranch).toBeUndefined();
275275
expect(decodeCapabilities({ ...base, deleteBranch: true }).deleteBranch).toBe(true);
276276
});
277+
278+
it("drops actions and verdicts from a newer server instead of failing", () => {
279+
const decoded = decodeCapabilities({
280+
...base,
281+
actions: ["merge", "archive", "close"],
282+
review: { ...base.review, verdicts: ["approve", "block"] },
283+
});
284+
285+
expect(decoded.actions).toEqual(["merge", "close"]);
286+
expect(decoded.review.verdicts).toEqual(["approve"]);
287+
});
277288
});
278289

279290
describe("naming the reader as the author to narrow by", () => {

‎packages/contracts/src/pullRequest.ts‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as HttpServerRespondable from "effect/http/HttpServerRespondable";
33
import * as HttpServerResponse from "effect/http/HttpServerResponse";
44

55
import {
6+
ForwardCompatibleArray,
67
IsoDateTime,
78
NonNegativeInt,
89
PositiveInt,
@@ -59,6 +60,10 @@ export type PullRequestMergeability = typeof PullRequestMergeability.Type;
5960
export const PullRequestMergeMethod = Schema.Literals(["merge", "squash", "rebase"]);
6061
export type PullRequestMergeMethod = typeof PullRequestMergeMethod.Type;
6162

63+
/**
64+
* Grows as hosts gain actions, so lists a server sends decode with `ForwardCompatibleArray`: an
65+
* older client drops an action it does not know instead of failing the whole pull request.
66+
*/
6267
export const PullRequestAction = Schema.Literals([
6368
"merge",
6469
"ready",
@@ -240,7 +245,7 @@ export const PullRequestReviewCapabilities = Schema.Struct({
240245
inlineComment: Schema.Boolean,
241246
reply: Schema.Boolean,
242247
resolve: Schema.Boolean,
243-
verdicts: Schema.Array(PullRequestReviewVerdict),
248+
verdicts: ForwardCompatibleArray(PullRequestReviewVerdict),
244249
});
245250
export type PullRequestReviewCapabilities = typeof PullRequestReviewCapabilities.Type;
246251

@@ -262,14 +267,14 @@ export type PullRequestViewedFilesStore = typeof PullRequestViewedFilesStore.Typ
262267
export const PullRequestCapabilities = Schema.Struct({
263268
diff: Schema.Boolean,
264269
comment: Schema.Boolean,
265-
actions: Schema.Array(PullRequestAction),
266-
mergeMethods: Schema.Array(PullRequestMergeMethod),
270+
actions: ForwardCompatibleArray(PullRequestAction),
271+
mergeMethods: ForwardCompatibleArray(PullRequestMergeMethod),
267272
deleteBranch: Schema.optional(Schema.Boolean),
268273
/**
269274
* Absent where it cannot at all, which is every host that has not said otherwise — so a
270275
* provider that says nothing offers nothing.
271276
*/
272-
updateMethods: Schema.optional(Schema.Array(PullRequestUpdateMethod)),
277+
updateMethods: Schema.optional(ForwardCompatibleArray(PullRequestUpdateMethod)),
273278
search: Schema.Boolean,
274279
reactions: Schema.optional(Schema.Boolean),
275280
viewedFiles: Schema.optional(PullRequestViewedFilesStore),
@@ -287,12 +292,12 @@ export type PullRequestCapabilities = typeof PullRequestCapabilities.Type;
287292
*/
288293
export const PullRequestViewerPermissions = Schema.Struct({
289294
stackRebase: Schema.optional(Schema.Boolean),
290-
actions: Schema.Array(PullRequestAction),
295+
actions: ForwardCompatibleArray(PullRequestAction),
291296
comment: Schema.Boolean,
292297
resolve: Schema.Boolean,
293-
verdicts: Schema.Array(PullRequestReviewVerdict),
298+
verdicts: ForwardCompatibleArray(PullRequestReviewVerdict),
294299
requestReviewers: Schema.Boolean,
295-
updateMethods: Schema.optional(Schema.Array(PullRequestUpdateMethod)),
300+
updateMethods: Schema.optional(ForwardCompatibleArray(PullRequestUpdateMethod)),
296301
labels: Schema.optional(Schema.Boolean),
297302
editChangeRequest: Schema.optional(Schema.Boolean),
298303
});
@@ -368,7 +373,7 @@ export const PullRequestProviderSummary = Schema.Struct({
368373
host: TrimmedNonEmptyString,
369374
kind: SourceControlProviderKind,
370375
searchesOnHost: Schema.Boolean,
371-
actions: Schema.optional(Schema.Array(PullRequestAction)),
376+
actions: Schema.optional(ForwardCompatibleArray(PullRequestAction)),
372377
projectCount: PositiveInt,
373378
configured: Schema.Boolean,
374379
detail: Schema.NullOr(TrimmedNonEmptyString),

0 commit comments

Comments
 (0)