Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/config-update-path-persistence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@godaddy/cli": patch
---

Fix application config updates so action, subscription, and extension additions write back to the resolved config file instead of re-resolving the environment path.
36 changes: 22 additions & 14 deletions src/services/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as nodeFs from "node:fs";
import { join } from "node:path";
import { isAbsolute, join } from "node:path";
import { FileSystem } from "@effect/platform/FileSystem";
import * as TOML from "@iarna/toml";
import { type ArkErrors, type } from "arktype";
Expand Down Expand Up @@ -207,7 +207,9 @@ export function getConfigFilePath(
configPath?: string,
): string {
if (configPath) {
return join(process.cwd(), configPath);
return isAbsolute(configPath)
? configPath
: join(process.cwd(), configPath);
}

const resolvedEnv = resolveConfigEnvironment(env);
Expand Down Expand Up @@ -235,7 +237,7 @@ export function getConfigFileEffect({

// If a specific config path is provided, use that
if (configPath) {
const absolutePath = join(process.cwd(), configPath);
const absolutePath = getConfigFilePath(undefined, configPath);
const exists = yield* fileExists(absolutePath);
if (exists) {
const content = yield* fs.readFileString(absolutePath);
Expand Down Expand Up @@ -298,7 +300,7 @@ export function getConfigFile({
const resolvedEnv = resolveConfigEnvironment(env);

if (configPath) {
const absolutePath = join(process.cwd(), configPath);
const absolutePath = getConfigFilePath(undefined, configPath);
if (nodeFs.existsSync(absolutePath)) {
const content = nodeFs.readFileSync(absolutePath, "utf-8");
return Config(TOML.parse(content));
Expand Down Expand Up @@ -429,7 +431,7 @@ function getConfigFilePathForUpdateEffect(
const resolvedEnv = resolveConfigEnvironment(env);

if (configPath) {
const absolutePath = join(process.cwd(), configPath);
const absolutePath = getConfigFilePath(undefined, configPath);
const exists = yield* fileExists(absolutePath);
if (exists) {
return { path: absolutePath };
Expand Down Expand Up @@ -467,13 +469,12 @@ function getConfigFilePathForUpdateEffect(
/**
* Write a full Config object to the TOML file.
*/
function writeConfigToFileEffect(
function writeConfigToResolvedPathEffect(
data: Config,
env?: ConfigEnvironment,
filePath: string,
): Effect.Effect<void, ConfigurationError, FileSystem> {
return Effect.gen(function* () {
const fs = yield* FileSystem;
const filePath = getConfigFilePath(env);

// Try to read the existing file to preserve structure
let existingConfig = {};
Expand Down Expand Up @@ -558,6 +559,13 @@ function writeConfigToFileEffect(
);
}

function writeConfigToFileEffect(
data: Config,
env?: ConfigEnvironment,
): Effect.Effect<void, ConfigurationError, FileSystem> {
return writeConfigToResolvedPathEffect(data, getConfigFilePath(env));
}

/**
* Write the config data to the appropriate TOML file.
*/
Expand Down Expand Up @@ -614,11 +622,11 @@ export function addActionToConfigEffect(
actions: [...(configResult.actions || []), action],
};

const { env } = yield* getConfigFilePathForUpdateEffect(
const { path } = yield* getConfigFilePathForUpdateEffect(
options.configPath,
options.env,
);
yield* writeConfigToFileEffect(updatedConfig, env);
yield* writeConfigToResolvedPathEffect(updatedConfig, path);
}).pipe(
Effect.catchAll((error) =>
Effect.fail(toConfigError(error, "Unable to update actions in config")),
Expand Down Expand Up @@ -651,11 +659,11 @@ export function addSubscriptionToConfigEffect(
},
};

const { env } = yield* getConfigFilePathForUpdateEffect(
const { path } = yield* getConfigFilePathForUpdateEffect(
options.configPath,
options.env,
);
yield* writeConfigToFileEffect(updatedConfig, env);
yield* writeConfigToResolvedPathEffect(updatedConfig, path);
}).pipe(
Effect.catchAll((error) =>
Effect.fail(
Expand Down Expand Up @@ -783,11 +791,11 @@ export function addExtensionToConfigEffect(
extensions: updatedExtensions,
} satisfies Config;

const { env } = yield* getConfigFilePathForUpdateEffect(
const { path } = yield* getConfigFilePathForUpdateEffect(
options.configPath,
options.env,
);
yield* writeConfigToFileEffect(updatedConfig, env);
yield* writeConfigToResolvedPathEffect(updatedConfig, path);
}).pipe(
Effect.catchAll((error) =>
Effect.fail(
Expand Down
37 changes: 37 additions & 0 deletions tests/unit/services/config-routing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as path from "node:path";
import { afterEach, beforeEach, describe, expect, test } from "vitest";
import {
type Config,
addActionToConfigEffect,
createConfigFileEffect,
createEnvFileEffect,
getConfigFilePath,
Expand Down Expand Up @@ -67,6 +68,42 @@ describe("Config Environment Routing", () => {
expect(fs.existsSync(path.join(tempDir, "godaddy.ote.toml"))).toBe(false);
});

test("adds actions to the explicit config path", async () => {
const configPath = path.join(tempDir, "godaddy.ote.toml");
fs.writeFileSync(
configPath,
[
'name = "test-app"',
'client_id = "a502484b-d7b1-4509-aa88-08b391a54c28"',
'description = "Test app"',
'version = "1.0.0"',
'url = "https://example.com"',
'proxy_url = "https://example.com/api"',
'authorization_scopes = [ "shopper.readonly" ]',
"actions = [ ]",
"",
"[subscriptions]",
"webhook = [ ]",
"",
].join("\n"),
);

await runEffect(
addActionToConfigEffect(
{
name: "commerce.communications.broadcast",
url: "/actions/broadcast",
},
{ configPath },
),
);

const content = fs.readFileSync(configPath, "utf-8");
expect(content).toContain('name = "commerce.communications.broadcast"');
expect(content).toContain('url = "/actions/broadcast"');
expect(fs.existsSync(path.join(tempDir, "godaddy.toml"))).toBe(false);
});

test("writes env file to mapped environment file", async () => {
process.env.GODADDY_API_BASE_URL = "https://api.test-godaddy.com";

Expand Down
Loading