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 missingIssueOf,
11 runLifecycle,
12} from "./common.ts";
13
14const { test } = Test.make({ providers: GCP.providers() });
15
16const waitUntilGone = (name: string) =>
17 ssm.getProjectsLocationsRepositoriesIssuesIssueComments({ name }).pipe(
18 Effect.as("found" as const),
19 Effect.catchTag("NotFound", () => Effect.succeed("gone" as const)),
20 Effect.repeat({
21 schedule: Schedule.spaced("2 seconds"),
22 until: (status) => status === "gone",
23 times: 10,
24 }),
25 );
26
27test.provider(
28 "getProjectsLocationsRepositoriesIssuesIssueComments on a missing comment fails with a typed tag",
29 (stack) =>
30 Effect.gen(function* () {
31 const project = yield* currentProject;
32 const missingIssue = missingIssueOf(project);
33 yield* stack.destroy();
34
35 const error = yield* Effect.flip(
36 ssm.getProjectsLocationsRepositoriesIssuesIssueComments({
37 name: `${missingIssue}/issueComments/12345`,
38 }),
39 );
40 expect(error._tag).toEqual("NotFound");
41
42 yield* stack.destroy();
43 }).pipe(logLevel),
44 {
45 tags: ["provider:gcp", "provider:gcp:securesourcemanager", "live"],
46 timeout: 90_000,
47 },
48);
49
50test.provider(
51 "create against a missing issue is rejected with a typed tag",
52 (stack) =>
53 Effect.gen(function* () {
54 const project = yield* currentProject;
55 const missingIssue = missingIssueOf(project);
56 yield* stack.destroy();
57
58 const error = yield* Effect.flip(
59 stack.deploy(
60 Effect.gen(function* () {
61 return yield* GCP.SecureSourceManager.RepositoriesIssuesIssueComment(
62 "Note",
63 {
64 issue: missingIssue,
65 body: "reproduced on main",
66 },
67 );
68 }),
69 ),
70 );
71 expect(error._tag).toEqual("NotFound");
72
73 yield* stack.destroy();
74 }).pipe(logLevel),
75 {
76 tags: ["provider:gcp", "provider:gcp:securesourcemanager", "live"],
77 timeout: 90_000,
78 },
79);
80
81test.provider.skipIf(!runLifecycle)(
82 "create, update, and delete an issue comment",
83 (stack) =>
84 Effect.gen(function* () {
85 const project = yield* currentProject;
86 const missingIssue = missingIssueOf(project);
87 yield* stack.destroy();
88
89 const created = yield* stack.deploy(
90 Effect.gen(function* () {
91 const issue = yield* GCP.SecureSourceManager.RepositoriesIssue(
92 "Bug",
93 {
94 repository:
95 process.env.GCP_TEST_SECURE_SOURCE_MANAGER_REPO ??
96 missingIssue.split("/issues/")[0]!,
97 title: "comment parent",
98 body: "parent issue",
99 },
100 );
101 const comment =
102 yield* GCP.SecureSourceManager.RepositoriesIssuesIssueComment(
103 "Note",
104 {
105 issue: issue.name,
106 body: "reproduced on main",
107 },
108 );
109 return { issue, comment };
110 }),
111 );
112
113 expect(created.comment.name).toContain("/issueComments/");
114 expect(created.comment.body).toEqual("reproduced on main");
115 expect(created.comment.issue).toEqual(created.issue.name);
116
117 const fetched =
118 yield* ssm.getProjectsLocationsRepositoriesIssuesIssueComments({
119 name: created.comment.name,
120 });
121 expect(fetched.name).toEqual(created.comment.name);
122 expect(fetched.body).toEqual("reproduced on main");
123
124 const updated = yield* stack.deploy(
125 Effect.gen(function* () {
126 const issue = yield* GCP.SecureSourceManager.RepositoriesIssue(
127 "Bug",
128 {
129 repository: created.issue.repository,
130 issueId: created.issue.issueId,
131 title: "comment parent",
132 body: "parent issue",
133 },
134 );
135 const comment =
136 yield* GCP.SecureSourceManager.RepositoriesIssuesIssueComment(
137 "Note",
138 {
139 issue: issue.name,
140 commentId: created.comment.commentId,
141 body: "reproduced on release",
142 },
143 );
144 return { issue, comment };
145 }),
146 );
147
148 expect(updated.comment.commentId).toEqual(created.comment.commentId);
149 expect(updated.comment.body).toEqual("reproduced on release");
150
151 yield* stack.destroy();
152
153 const gone = yield* waitUntilGone(created.comment.name);
154 expect(gone).toEqual("gone");
155 }).pipe(logLevel),
156 {
157 tags: ["provider:gcp", "provider:gcp:securesourcemanager", "live"],
158 timeout: 120_000,
159 },
160);