1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as ssm from "@distilled.cloud/gcp/securesourcemanager_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import * as Schedule from "effect/Schedule";
7import {
8 currentProject,
9 logLevel,
10 missingPullRequestOf,
11 runLifecycle,
12} from "./common.ts";
13
14const { test } = Test.make({ providers: GCP.providers() });
15
16const waitUntilGone = (name: string) =>
17 ssm
18 .getProjectsLocationsRepositoriesPullRequestsPullRequestComments({
19 name,
20 })
21 .pipe(
22 Effect.as("found" as const),
23 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
24 Effect.repeat({
25 schedule: Schedule.spaced("2 seconds"),
26 until: (status) => status === "gone",
27 times: 10,
28 }),
29 );
30
31test.provider(
32 "getProjectsLocationsRepositoriesPullRequestsPullRequestComments on a missing comment fails with a typed tag",
33 (stack) =>
34 Effect.gen(function* () {
35 const project = yield* currentProject;
36 const missingPullRequest = missingPullRequestOf(project);
37 yield* stack.destroy();
38
39 const error = yield* Effect.flip(
40 ssm.getProjectsLocationsRepositoriesPullRequestsPullRequestComments({
41 name: `${missingPullRequest}/pullRequestComments/12345`,
42 }),
43 );
44 expect(error._tag).toEqual("NotFound");
45
46 yield* stack.destroy();
47 }).pipe(logLevel),
48 {
49 tags: ["provider:gcp", "provider:gcp:securesourcemanager", "live"],
50 timeout: 90_000,
51 },
52);
53
54test.provider(
55 "create against a missing pull request is rejected with a typed tag",
56 (stack) =>
57 Effect.gen(function* () {
58 const project = yield* currentProject;
59 const missingPullRequest = missingPullRequestOf(project);
60 yield* stack.destroy();
61
62 const error = yield* Effect.flip(
63 stack.deploy(
64 Effect.gen(function* () {
65 return yield* GCP.SecureSourceManager.RepositoriesPullRequestsPullRequestComment(
66 "Note",
67 {
68 pullRequest: missingPullRequest,
69 comment: { body: "looks good" },
70 },
71 );
72 }),
73 ),
74 );
75 expect(error._tag).toEqual("NotFound");
76
77 yield* stack.destroy();
78 }).pipe(logLevel),
79 {
80 tags: ["provider:gcp", "provider:gcp:securesourcemanager", "live"],
81 timeout: 90_000,
82 },
83);
84
85test.provider.skipIf(!runLifecycle)(
86 "create, update, and delete a pull request comment",
87 (stack) =>
88 Effect.gen(function* () {
89 const project = yield* currentProject;
90 const missingPullRequest = missingPullRequestOf(project);
91 yield* stack.destroy();
92
93 const created = yield* stack.deploy(
94 Effect.gen(function* () {
95 return yield* GCP.SecureSourceManager.RepositoriesPullRequestsPullRequestComment(
96 "Note",
97 {
98 pullRequest:
99 process.env.GCP_TEST_SECURE_SOURCE_MANAGER_PULL_REQUEST ??
100 missingPullRequest,
101 comment: { body: "looks good" },
102 },
103 );
104 }),
105 );
106
107 expect(created.name).toContain("/pullRequestComments/");
108 expect(created.comment?.body).toEqual("looks good");
109
110 const fetched =
111 yield* ssm.getProjectsLocationsRepositoriesPullRequestsPullRequestComments(
112 { name: created.name },
113 );
114 expect(fetched.name).toEqual(created.name);
115 expect(fetched.comment?.body).toEqual("looks good");
116
117 const updated = yield* stack.deploy(
118 Effect.gen(function* () {
119 return yield* GCP.SecureSourceManager.RepositoriesPullRequestsPullRequestComment(
120 "Note",
121 {
122 pullRequest: created.pullRequest,
123 commentId: created.commentId,
124 comment: { body: "looks good after the rebase" },
125 },
126 );
127 }),
128 );
129
130 expect(updated.commentId).toEqual(created.commentId);
131 expect(updated.comment?.body).toEqual("looks good after the rebase");
132
133 yield* stack.destroy();
134
135 const gone = yield* waitUntilGone(created.name);
136 expect(gone).toEqual("gone");
137 }).pipe(logLevel),
138 {
139 tags: ["provider:gcp", "provider:gcp:securesourcemanager", "live"],
140 timeout: 120_000,
141 },
142);