1import * as GCP from "@/GCP";
2import * as Test from "@/Test/Alchemy";
3import * as dataform from "@distilled.cloud/gcp/dataform_v1";
4import { expect } from "alchemy-test";
5import * as Effect from "effect/Effect";
6import { logLevel, currentProject, waitUntilGone } from "./common.ts";
7
8const { test } = Test.make({ providers: GCP.providers() });
9
10const runLifecycle = !process.env.FAST;
11
12test.provider(
13 "getProjectsLocationsRepositoriesWorkflowInvocations on a missing invocation fails with a typed tag",
14 (stack) =>
15 Effect.gen(function* () {
16 const project = yield* currentProject;
17 yield* stack.destroy();
18
19 const error = yield* Effect.flip(
20 dataform.getProjectsLocationsRepositoriesWorkflowInvocations({
21 name: `projects/${project}/locations/us-central1/repositories/missing/workflowInvocations/alchemy-missing`,
22 }),
23 );
24 expect(error._tag).toEqual("NotFound");
25
26 yield* stack.destroy();
27 }).pipe(logLevel),
28 { tags: ["provider:gcp", "provider:gcp:dataform", "live"], timeout: 90_000 },
29);
30
31const writeWorkspaceFile = (workspace: string, path: string, text: string) =>
32 Effect.gen(function* () {
33 const contents = yield* Effect.sync(() =>
34 Buffer.from(text, "utf8").toString("base64"),
35 );
36 return yield* dataform.writeFileProjectsLocationsRepositoriesWorkspaces({
37 workspace,
38 body: { path, contents },
39 });
40 });
41
42test.provider.skipIf(!runLifecycle)(
43 "create and delete a dataform workflow invocation",
44 (stack) =>
45 Effect.gen(function* () {
46 const project = yield* currentProject;
47 yield* stack.destroy();
48
49 const created = yield* stack.deploy(
50 Effect.gen(function* () {
51 const repo = yield* GCP.Dataform.Repository("InvocationRepo", {
52 location: "us-central1",
53 displayName: "invocation-repo",
54 labels: { env: "test" },
55 serviceAccount:
56 "alchemy-testing@alchemy-gcp-testing-83661.iam.gserviceaccount.com",
57 });
58 const workspace = yield* GCP.Dataform.RepositoriesWorkspace("Dev", {
59 repository: repo.name,
60 });
61 return { repo, workspace };
62 }),
63 );
64
65 yield* writeWorkspaceFile(
66 created.workspace.name,
67 "package.json",
68 JSON.stringify({
69 name: "dataform",
70 dependencies: { "@dataform/core": "3.0.0" },
71 }),
72 );
73 yield* writeWorkspaceFile(
74 created.workspace.name,
75 "workflow_settings.yaml",
76 [
77 `defaultProject: ${project}`,
78 "defaultLocation: US",
79 "defaultDataset: dataform",
80 "defaultAssertionDataset: dataform_assertions",
81 ].join("\n"),
82 );
83 yield* dataform
84 .makeDirectoryProjectsLocationsRepositoriesWorkspaces({
85 workspace: created.workspace.name,
86 body: { path: "definitions" },
87 })
88 .pipe(Effect.catchTag("Conflict", () => Effect.void));
89 yield* writeWorkspaceFile(
90 created.workspace.name,
91 "definitions/example.sqlx",
92 'config { type: "view" }\nSELECT 1 AS x\n',
93 );
94
95 const compilation =
96 yield* dataform.createProjectsLocationsRepositoriesCompilationResults({
97 parent: created.repo.name,
98 body: { workspace: created.workspace.name },
99 });
100 expect(compilation.name).toEqual(expect.any(String));
101
102 const invoked = yield* stack.deploy(
103 Effect.gen(function* () {
104 const repo = yield* GCP.Dataform.Repository("InvocationRepo", {
105 repositoryId: created.repo.repositoryId,
106 location: "us-central1",
107 displayName: "invocation-repo",
108 labels: { env: "test" },
109 serviceAccount:
110 "alchemy-testing@alchemy-gcp-testing-83661.iam.gserviceaccount.com",
111 });
112 const workspace = yield* GCP.Dataform.RepositoriesWorkspace("Dev", {
113 repository: repo.name,
114 workspaceId: created.workspace.workspaceId,
115 });
116 const invocation = yield* GCP.Dataform.RepositoriesWorkflowInvocation(
117 "Run",
118 {
119 repository: repo.name,
120 compilationResult: compilation.name,
121 },
122 );
123 return { repo, workspace, invocation };
124 }),
125 );
126
127 expect(invoked.invocation.name).toContain("/workflowInvocations/");
128 expect(invoked.invocation.compilationResult).toContain(
129 "/compilationResults/",
130 );
131 expect(invoked.invocation.compilationResult).toContain(
132 compilation.name?.split("/").pop() ?? "compilationResults",
133 );
134
135 const fetched =
136 yield* dataform.getProjectsLocationsRepositoriesWorkflowInvocations({
137 name: invoked.invocation.name,
138 });
139 expect(fetched.name).toEqual(invoked.invocation.name);
140
141 yield* stack.destroy();
142 const gone = yield* waitUntilGone(
143 dataform.getProjectsLocationsRepositoriesWorkflowInvocations({
144 name: invoked.invocation.name,
145 }),
146 );
147 expect(gone).toEqual("gone");
148 }).pipe(logLevel),
149 { tags: ["provider:gcp", "provider:gcp:dataform", "live"], timeout: 180_000 },
150);