Skip to content
Source
Sign inSign up
Open History to see the last commit

AzureDevOpsSourceControlProvider.test.ts

107 lines4.2 KB

1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { SourceControlProviderKind } from "@t3tools/contracts";
3import type * as SourceControlHost from "@t3tools/source-control-core/server/SourceControlHost";
4import * as TestSourceControlHost from "@t3tools/source-control-testing/TestSourceControlHost";
5import { processOutput } from "@t3tools/source-control-testing/TestSourceControlHost";
6import { assert, it, vi } from "@effect/vitest";
7import * as Effect from "effect/Effect";
8import * as Layer from "effect/Layer";
9import * as Option from "effect/Option";
10import { ChildProcessSpawner } from "effect/process";
11​
12import * as AzureDevOpsCli from "./AzureDevOpsCli.ts";
13import * as AzureDevOpsSourceControlProvider from "./AzureDevOpsSourceControlProvider.ts";
14​
15const { parseAuth } = AzureDevOpsSourceControlProvider.discovery;
16​
17it("reads the signed-in Azure account and says when az is signed out", () => {
18 assert.deepStrictEqual(parseAuth(processOutput("azure-user@example.com\n")), {
19 status: "authenticated",
20 account: Option.some("azure-user@example.com"),
21 host: Option.some("dev.azure.com"),
22 detail: Option.none(),
23 });
24 assert.strictEqual(
25 parseAuth(
26 processOutput("", {
27 stderr: "Please run 'az login' to setup account.\n",
28 exitCode: ChildProcessSpawner.ExitCode(1),
29 }),
30 ).status,
31 "unauthenticated",
32 );
33 assert.strictEqual(parseAuth(processOutput("\n")).status, "unknown");
34});
35​
36it.effect("names the remote's repository when reading the default branch", () => {
37 const run = vi.fn<SourceControlHost.SourceControlHost["Service"]["process"]["run"]>(() =>
38 Effect.succeed(
39 processOutput(
40 JSON.stringify({
41 name: "My Repo",
42 webUrl: "https://dev.azure.com/acme/project/_git/My%20Repo",
43 remoteUrl: "https://dev.azure.com/acme/project/_git/My%20Repo",
44 sshUrl: "git@ssh.dev.azure.com:v3/acme/project/My%20Repo",
45 defaultBranch: "refs/heads/master",
46 }),
47 ),
48 ),
49 );
50 const support = Layer.mergeAll(
51 TestSourceControlHost.layer({ process: { run } }),
52 NodeServices.layer,
53 );
54 return Effect.gen(function* () {
55 const provider = yield* AzureDevOpsSourceControlProvider.make;
56 for (const [remoteUrl, repository] of [
57 ["https://acme@dev.azure.com/acme/project/_git/My%20Repo", "My Repo"],
58 ["https://dev.azure.com/acme/project/_git/My%20Repo?view=x#readme", "My Repo"],
59 ["https://acme.visualstudio.com/DefaultCollection/project/_git/My%20Repo/", "My Repo"],
60 ["git@ssh.dev.azure.com:v3/acme/project/My%20Repo", "My Repo"],
61 ["ssh://git@ssh.dev.azure.com/v3/acme/project/My%20Repo", "My Repo"],
62 ["https://dev.azure.com/acme/project/_git/service.git", "service.git"],
63 ["https://dev.azure.com/acme/project/_git/-repo", "-repo"],
64 ["https://dev.azure.com/acme/project/_git/%40.env", null],
65 ] as const) {
66 run.mockClear();
67 const branch = yield* provider.getDefaultBranch({
68 cwd: "/repo",
69 context: {
70 provider: {
71 kind: SourceControlProviderKind.make("azure-devops"),
72 name: "Azure DevOps",
73 baseUrl: "https://dev.azure.com",
74 },
75 remoteName: "origin",
76 remoteUrl,
77 },
78 });
79 if (repository === null) {
80 assert.strictEqual(branch, null, remoteUrl);
81 assert.strictEqual(run.mock.calls.length, 0, remoteUrl);
82 continue;
83 }
84 assert.strictEqual(branch, "master", remoteUrl);
85 assert.include(
86 [...(run.mock.calls[0]?.[0].args ?? [])],
87 `--repository=${repository}`,
88 remoteUrl,
89 );
90 }
91 }).pipe(Effect.provide(AzureDevOpsCli.layer.pipe(Layer.provide(support))));
92});
93​
94it.effect(
95 "looks up a branch's pull requests a full page at a time, past forks' same-named branches",
96 () =>
97 Effect.gen(function* () {
98 const provider = yield* AzureDevOpsSourceControlProvider.make;
99 assert.deepStrictEqual(
100 provider.headBranchProbe?.({
101 headSelectors: ["octocat:feature", "feature"],
102 state: "open",
103 }),
104 { headSelectors: ["feature"], limit: 100 },
105 );
106 }).pipe(Effect.provide(Layer.mock(AzureDevOpsCli.AzureDevOpsCli)({}))),
107);