From 1422d9b7df3104a2b1a4e669406c6946b799d542 Mon Sep 17 00:00:00 2001 From: Jean-Michel Gambard <49202412+Tripouille@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:23:16 +0100 Subject: [PATCH] feat(status): add failOnChanges option --- src/commands/status.ts | 7 +++++++ src/index.ts | 1 + tests/commands/status.test.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/commands/status.ts b/src/commands/status.ts index dc18de5..18ee5ad 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -1,3 +1,4 @@ +import { exit } from "node:process"; import type { I18nCliConfig } from "@/types/cli.js"; import type { Languages } from "@/types/language.js"; import { computeTranslationFolderRequiredChanges } from "@/utils/compute-translation-folder-required-changes.js"; @@ -9,6 +10,7 @@ import chalk from "chalk"; export type StatusCommandOptions = { verbose?: boolean; veryVerbose?: boolean; + failOnChanges?: boolean; }; export async function statusCommand(config: I18nCliConfig, options: StatusCommandOptions) { @@ -47,4 +49,9 @@ export async function statusCommand(config: I18nCliConfig, options: StatusComman )}`} ${`${chalk.red(`- ${tokenPathsToDeleteMap.size}`)}`}`, ); } + + if (options.failOnChanges) { + const changesCount = tokenPathsToCreateMap.size + tokenPathsToDeleteMap.size; + if (changesCount) exit(1); + } } diff --git a/src/index.ts b/src/index.ts index e0c18cf..11c0331 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,6 +34,7 @@ export function createI18nCli(params: CreateI18nCliParams) { "-vv, --very-verbose", "Show the tokens that require changes and the associated languages", ) + .option("-foc, --fail-on-changes", "Fail if there are tokens that require changes") .action((options) => { statusCommand(config, options); }); diff --git a/tests/commands/status.test.ts b/tests/commands/status.test.ts index c96ec1a..3fc86ec 100644 --- a/tests/commands/status.test.ts +++ b/tests/commands/status.test.ts @@ -1,3 +1,4 @@ +import { exit } from "node:process"; import { type StatusCommandOptions, statusCommand } from "@/commands/status.js"; import type { CreateI18nCliParams } from "@/index.js"; import type { TranslationFolder } from "@/types/translation.js"; @@ -10,6 +11,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("@/utils/create-translation-folder.js"); vi.mock("@/utils/compute-translation-folder-required-changes.js"); vi.mock("@/utils/group-translation-folder-required-changes-by-token-path.js"); +vi.mock("node:process"); const config: CreateI18nCliParams = { i18nFolderAbsolutePath: "/path/to/translations", @@ -109,4 +111,28 @@ describe(statusCommand.name, () => { [chalk.red("- inner.deepest.deep in [es]")], ]); }); + + it("exits with code 1 if failOnChanges is set and there are changes", async () => { + const logger = { log: vi.fn() }; + const options: StatusCommandOptions = { failOnChanges: true }; + + await statusCommand({ ...config, logger }, options); + + expect(exit).toHaveBeenCalledWith(1); + }); + + it("does not exit with code 1 if failOnChanges is set and there are no changes", async () => { + const logger = { log: vi.fn() }; + const options: StatusCommandOptions = { failOnChanges: true }; + + vi.mocked(computeTranslationFolderRequiredChanges).mockReturnValue(new Map()); + vi.mocked(groupTranslationFolderRequiredChangesByTokenPath).mockReturnValue({ + tokenPathsToCreateMap: new Map(), + tokenPathsToDeleteMap: new Map(), + }); + + await statusCommand({ ...config, logger }, options); + + expect(exit).not.toHaveBeenCalled(); + }); });