diff --git a/.changeset/channel-command-default.md b/.changeset/channel-command-default.md new file mode 100644 index 000000000..542bdb110 --- /dev/null +++ b/.changeset/channel-command-default.md @@ -0,0 +1,5 @@ +--- +"hot-updater": patch +--- + +Report the default `production` channel in `hot-updater channel` when the native files carry no channel value, instead of showing an empty channel. diff --git a/packages/hot-updater/src/utils/setChannel.spec.ts b/packages/hot-updater/src/utils/setChannel.spec.ts new file mode 100644 index 000000000..beef3f041 --- /dev/null +++ b/packages/hot-updater/src/utils/setChannel.spec.ts @@ -0,0 +1,75 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { getChannel } from "./setChannel"; + +const androidGet = vi.fn(); +const androidExists = vi.fn(); +const iosGet = vi.fn(); +const iosExists = vi.fn(); + +vi.mock("@hot-updater/cli-tools", () => ({ + loadConfig: vi.fn(async () => ({ + platform: { + android: { androidManifestPaths: [], stringResourcePaths: [] }, + ios: { infoPlistPaths: [] }, + }, + })), +})); + +vi.mock("./configParser/androidParser", () => ({ + AndroidConfigParser: class { + exists = androidExists; + get = androidGet; + }, +})); + +vi.mock("./configParser/iosParser", () => ({ + IosConfigParser: class { + exists = iosExists; + get = iosGet; + }, +})); + +describe("getChannel", () => { + beforeEach(() => { + vi.clearAllMocks(); + androidExists.mockResolvedValue(true); + iosExists.mockResolvedValue(true); + }); + + it("falls back to the native default channel when Android has none", async () => { + androidGet.mockResolvedValue({ + value: null, + paths: ["android/app/src/main/AndroidManifest.xml"], + }); + + await expect(getChannel("android")).resolves.toEqual({ + value: "production", + paths: ["android/app/src/main/AndroidManifest.xml"], + }); + }); + + it("falls back to the native default channel when iOS has none", async () => { + iosGet.mockResolvedValue({ + value: null, + paths: ["ios/HotUpdaterExample/Info.plist"], + }); + + await expect(getChannel("ios")).resolves.toEqual({ + value: "production", + paths: ["ios/HotUpdaterExample/Info.plist"], + }); + }); + + it("returns the configured channel when one is set", async () => { + androidGet.mockResolvedValue({ + value: "staging", + paths: ["android/app/src/main/AndroidManifest.xml"], + }); + + await expect(getChannel("android")).resolves.toEqual({ + value: "staging", + paths: ["android/app/src/main/AndroidManifest.xml"], + }); + }); +}); diff --git a/packages/hot-updater/src/utils/setChannel.ts b/packages/hot-updater/src/utils/setChannel.ts index 7cb12de77..bb27f625c 100644 --- a/packages/hot-updater/src/utils/setChannel.ts +++ b/packages/hot-updater/src/utils/setChannel.ts @@ -1,5 +1,4 @@ import { loadConfig } from "@hot-updater/cli-tools"; -import { merge } from "es-toolkit"; import { AndroidConfigParser } from "./configParser/androidParser"; import { IosConfigParser } from "./configParser/iosParser"; @@ -27,10 +26,8 @@ const getAndroidChannel = async (): Promise<{ if (!(await androidParser.exists())) { throw new Error("No Android native config files found"); } - return merge( - { value: DEFAULT_CHANNEL }, - await androidParser.get("hot_updater_channel"), - ); + const { value, paths } = await androidParser.get("hot_updater_channel"); + return { value: value ?? DEFAULT_CHANNEL, paths }; }; const setIosChannel = async (channel: string): Promise<{ paths: string[] }> => { @@ -50,10 +47,8 @@ const getIosChannel = async (): Promise<{ if (!(await iosParser.exists())) { throw new Error("No iOS Info.plist files found"); } - return merge( - { value: DEFAULT_CHANNEL }, - await iosParser.get("HOT_UPDATER_CHANNEL"), - ); + const { value, paths } = await iosParser.get("HOT_UPDATER_CHANNEL"); + return { value: value ?? DEFAULT_CHANNEL, paths }; }; export const setChannel = async (