Allow overriding the API base url (#11440)

* Allow overriding the base url

* Override the mcpbaseurl

* update the api base url

* Fix tests
This commit is contained in:
Tomás Barreiro
2026-06-11 22:29:17 +02:00
committed by GitHub
parent a3a31da37d
commit ec75291d5b
2 changed files with 108 additions and 59 deletions
@@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
CLINE_ENVIRONMENT_ENV,
CLINE_ENVIRONMENT_OVERRIDE_ENV,
@@ -8,58 +8,75 @@ import {
resolveClineEnvironment,
} from "./cline-environment";
const ENV_KEYS = [
CLINE_ENVIRONMENT_ENV,
CLINE_ENVIRONMENT_OVERRIDE_ENV,
"CLINE_API_BASE_URL",
] as const;
const originalEnvValues = Object.fromEntries(
ENV_KEYS.map((key) => [key, process.env[key]]),
);
beforeEach(() => {
vi.unstubAllGlobals();
for (const key of ENV_KEYS) {
delete process.env[key];
}
});
afterEach(() => {
vi.unstubAllGlobals();
for (const key of ENV_KEYS) {
const value = originalEnvValues[key];
if (typeof value === "string") {
process.env[key] = value;
} else {
delete process.env[key];
}
}
});
describe("resolveClineEnvironment", () => {
it("defaults to production when no env var is set", () => {
expect(resolveClineEnvironment({ env: {} })).toBe("production");
expect(resolveClineEnvironment()).toBe(DEFAULT_CLINE_ENVIRONMENT);
});
it("reads CLINE_ENVIRONMENT", () => {
expect(
resolveClineEnvironment({
env: { [CLINE_ENVIRONMENT_ENV]: "staging" },
}),
).toBe("staging");
expect(
resolveClineEnvironment({
env: { [CLINE_ENVIRONMENT_ENV]: "local" },
}),
).toBe("local");
it("reads CLINE_ENVIRONMENT from process.env", () => {
process.env[CLINE_ENVIRONMENT_ENV] = "staging";
expect(resolveClineEnvironment()).toBe("staging");
process.env[CLINE_ENVIRONMENT_ENV] = "local";
expect(resolveClineEnvironment()).toBe("local");
});
it("prefers CLINE_ENVIRONMENT_OVERRIDE over CLINE_ENVIRONMENT", () => {
expect(
resolveClineEnvironment({
env: {
[CLINE_ENVIRONMENT_OVERRIDE_ENV]: "local",
[CLINE_ENVIRONMENT_ENV]: "staging",
},
}),
).toBe("local");
process.env[CLINE_ENVIRONMENT_OVERRIDE_ENV] = "local";
process.env[CLINE_ENVIRONMENT_ENV] = "staging";
expect(resolveClineEnvironment()).toBe("local");
});
it("normalizes case and surrounding whitespace", () => {
expect(
resolveClineEnvironment({
env: { [CLINE_ENVIRONMENT_ENV]: " STAGING " },
}),
).toBe("staging");
process.env[CLINE_ENVIRONMENT_ENV] = " STAGING ";
expect(resolveClineEnvironment()).toBe("staging");
});
it("ignores unknown values and falls through to the next source", () => {
expect(
resolveClineEnvironment({
env: {
[CLINE_ENVIRONMENT_OVERRIDE_ENV]: "qa",
[CLINE_ENVIRONMENT_ENV]: "staging",
},
}),
).toBe("staging");
process.env[CLINE_ENVIRONMENT_OVERRIDE_ENV] = "qa";
process.env[CLINE_ENVIRONMENT_ENV] = "staging";
expect(resolveClineEnvironment()).toBe("staging");
expect(
resolveClineEnvironment({
env: { [CLINE_ENVIRONMENT_ENV]: "qa" },
}),
).toBe(DEFAULT_CLINE_ENVIRONMENT);
delete process.env[CLINE_ENVIRONMENT_OVERRIDE_ENV];
process.env[CLINE_ENVIRONMENT_ENV] = "qa";
expect(resolveClineEnvironment()).toBe(DEFAULT_CLINE_ENVIRONMENT);
});
it("defaults to production when process is unavailable", () => {
vi.stubGlobal("process", undefined);
expect(resolveClineEnvironment()).toBe(DEFAULT_CLINE_ENVIRONMENT);
});
});
@@ -74,18 +91,31 @@ describe("getClineEnvironmentConfig", () => {
);
});
it("resolves from env when no explicit environment is passed", () => {
expect(
getClineEnvironmentConfig({
env: { [CLINE_ENVIRONMENT_ENV]: "staging" },
}),
).toBe(CLINE_ENVIRONMENTS.staging);
it("falls back to production by default", () => {
expect(getClineEnvironmentConfig()).toBe(CLINE_ENVIRONMENTS.production);
});
it("falls back to production by default", () => {
expect(getClineEnvironmentConfig({ env: {} })).toBe(
CLINE_ENVIRONMENTS.production,
);
it("uses the resolved process.env environment when no explicit environment is provided", () => {
process.env[CLINE_ENVIRONMENT_ENV] = "staging";
expect(getClineEnvironmentConfig()).toBe(CLINE_ENVIRONMENTS.staging);
});
it("applies CLINE_API_BASE_URL without mutating the catalog config", () => {
process.env.CLINE_API_BASE_URL = "http://127.0.0.1:3000";
expect(getClineEnvironmentConfig("local")).toEqual({
...CLINE_ENVIRONMENTS.local,
apiBaseUrl: "http://127.0.0.1:3000",
mcpBaseUrl: "http://127.0.0.1:3000/v1/mcp",
});
expect(CLINE_ENVIRONMENTS.local.apiBaseUrl).toBe("http://localhost:7777");
});
it("defaults to production when process is unavailable", () => {
vi.stubGlobal("process", undefined);
expect(getClineEnvironmentConfig()).toBe(CLINE_ENVIRONMENTS.production);
});
});
@@ -67,10 +67,8 @@ function readProcessEnv(): NodeJS.ProcessEnv {
return process.env;
}
export function resolveClineEnvironment(
options: ResolveClineEnvironmentOptions = {},
): ClineEnvironment {
const env = options.env ?? readProcessEnv();
export function resolveClineEnvironment(): ClineEnvironment {
const env = readProcessEnv();
return (
normalizeClineEnvironment(env[CLINE_ENVIRONMENT_OVERRIDE_ENV]) ??
normalizeClineEnvironment(env[CLINE_ENVIRONMENT_ENV]) ??
@@ -78,11 +76,32 @@ export function resolveClineEnvironment(
);
}
export function getClineEnvironmentConfig(
environmentOrOptions?: ClineEnvironment | ResolveClineEnvironmentOptions,
): ClineEnvironmentConfig {
if (typeof environmentOrOptions === "string") {
return CLINE_ENVIRONMENTS[environmentOrOptions];
function getEnvConfig(env?: ClineEnvironment) {
if (typeof env === "string") {
return CLINE_ENVIRONMENTS[env];
}
return CLINE_ENVIRONMENTS[resolveClineEnvironment(environmentOrOptions)];
return CLINE_ENVIRONMENTS[resolveClineEnvironment()];
}
function applyConfigOverrides(
config: ClineEnvironmentConfig,
env: NodeJS.ProcessEnv,
): ClineEnvironmentConfig {
if (env.CLINE_API_BASE_URL) {
config = {
...config,
apiBaseUrl: env.CLINE_API_BASE_URL,
mcpBaseUrl: `${env.CLINE_API_BASE_URL}/v1/mcp`,
};
}
return config;
}
export function getClineEnvironmentConfig(
env?: ClineEnvironment,
): ClineEnvironmentConfig {
const config = getEnvConfig(env);
return applyConfigOverrides(config, readProcessEnv());
}