Skip to content
Open
1 change: 1 addition & 0 deletions apps/server/src/git/GitManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ function makeManager(input?: {
get: () => Effect.succeed(provider),
resolveHandle: () => Effect.succeed({ provider, context: null }),
resolve: () => Effect.succeed(provider),
discover: Effect.succeed([]),
}),
),
Effect.provide(Layer.succeed(GitHubCli, gitHubCli)),
Expand Down
14 changes: 8 additions & 6 deletions apps/server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ProviderSessionReaperLive } from "./provider/Layers/ProviderSessionReap
import { OpenCodeRuntimeLive } from "./provider/opencodeRuntime.ts";
import { CheckpointDiffQueryLive } from "./checkpointing/Layers/CheckpointDiffQuery.ts";
import { CheckpointStoreLive } from "./checkpointing/Layers/CheckpointStore.ts";
import * as BitbucketApi from "./sourceControl/BitbucketApi.ts";
import * as GitHubCli from "./sourceControl/GitHubCli.ts";
import * as GitLabCli from "./sourceControl/GitLabCli.ts";
import * as TextGeneration from "./textGeneration/TextGeneration.ts";
Expand Down Expand Up @@ -161,15 +162,15 @@ const VcsDriverRegistryLayerLive = VcsDriverRegistry.layer.pipe(
Layer.provide(VcsProjectConfig.layer),
);

const SourceControlProviderRegistryLayerLive = SourceControlProviderRegistry.layer.pipe(
Layer.provide(Layer.mergeAll(BitbucketApi.layer, GitHubCli.layer, GitLabCli.layer)),
Layer.provideMerge(VcsDriverRegistryLayerLive),
);

const GitManagerLayerLive = GitManager.layer.pipe(
Layer.provideMerge(ProjectSetupScriptRunnerLive),
Layer.provideMerge(GitVcsDriver.layer),
Layer.provideMerge(
SourceControlProviderRegistry.layer.pipe(
Layer.provide(Layer.mergeAll(GitHubCli.layer, GitLabCli.layer)),
Layer.provideMerge(VcsDriverRegistryLayerLive),
),
),
Layer.provideMerge(SourceControlProviderRegistryLayerLive),
Layer.provideMerge(TextGeneration.layer),
);

Expand Down Expand Up @@ -227,6 +228,7 @@ const ProviderRuntimeLayerLive = ProviderSessionReaperLive.pipe(
const RuntimeCoreDependenciesLive = ReactorLayerLive.pipe(
// Core Services
Layer.provideMerge(CheckpointingLayerLive),
Layer.provideMerge(SourceControlProviderRegistryLayerLive),
Layer.provideMerge(GitLayerLive),
Layer.provideMerge(VcsLayerLive),
Layer.provideMerge(ProviderRuntimeLayerLive),
Expand Down
42 changes: 42 additions & 0 deletions apps/server/src/sourceControl/AzureDevOpsSourceControlProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
combinedAuthOutput,
firstSafeAuthLine,
providerAuth,
type SourceControlAuthProbeInput,
type SourceControlCliDiscoverySpec,
} from "./SourceControlProviderDiscovery.ts";

function parseAzureAuth(input: SourceControlAuthProbeInput) {
const account = input.stdout.trim().split(/\r?\n/)[0]?.trim();

if (input.exitCode !== 0) {
return providerAuth({
status: "unauthenticated",
detail:
firstSafeAuthLine(combinedAuthOutput(input)) ?? "Run `az login` to authenticate Azure CLI.",
});
}

if (account && account.length > 0) {
return providerAuth({ status: "authenticated", account, host: "dev.azure.com" });
}

return providerAuth({
status: "unknown",
host: "dev.azure.com",
detail: "Azure CLI account status could not be parsed.",
});
}

export const discovery = {
type: "cli",
kind: "azure-devops",
label: "Azure DevOps",
executable: "az",
versionArgs: ["--version"],
authArgs: ["account", "show", "--query", "user.name", "-o", "tsv"],
parseAuth: parseAzureAuth,
implemented: false,
installHint:
"Install Azure CLI with `brew install azure-cli`, then add Azure DevOps support with `az extension add --name azure-devops`.",
} satisfies SourceControlCliDiscoverySpec;
Loading
Loading