diff --git a/package.json b/package.json index 47382ab..c92a814 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "type": "git", "url": "https://github.com/hiroki0525/dandori.git" }, + "type": "module", "scripts": { "build": "turbo build", "prepare": "husky install", diff --git a/packages/cli/src/core/__tests__/index.test.ts b/packages/cli/src/core/__tests__/index.test.ts index d8a17b9..626fe09 100644 --- a/packages/cli/src/core/__tests__/index.test.ts +++ b/packages/cli/src/core/__tests__/index.test.ts @@ -16,6 +16,13 @@ import generateDandoriTasks, { OptionalTaskPropsOption, } from "@dandori/core"; +const { actualLoadFile } = await vi.hoisted(async () => { + const actualModule = await import("@dandori/libs"); + return { + actualLoadFile: actualModule.loadFile, + }; +}); + const tasks: DandoriTask[] = [ { id: "1", @@ -32,14 +39,13 @@ vi.mock("@dandori/core", () => ({ const mockLogError = vi.fn(); -vi.mock("@dandori/libs", async () => { - const actualModule = - await vi.importActual("@dandori/libs"); +vi.mock("@dandori/libs", () => { return { - ...actualModule, + logLevel: "info", getLogger: vi.fn(() => ({ error: mockLogError, })), + loadFile: actualLoadFile, }; }); diff --git a/packages/core/src/__tests__/index.test.ts b/packages/core/src/__tests__/index.test.ts index 0396d28..706dee0 100644 --- a/packages/core/src/__tests__/index.test.ts +++ b/packages/core/src/__tests__/index.test.ts @@ -33,11 +33,9 @@ vi.mock("openai", () => { const mockLogDebug = vi.fn(); -vi.mock("@dandori/libs", async () => { - const actualModule = - await vi.importActual("@dandori/libs"); +vi.mock("@dandori/libs", () => { return { - ...actualModule, + logLevel: "info", getLogger: vi.fn(() => ({ error: vi.fn(), debug: mockLogDebug, diff --git a/packages/libs/global.d.ts b/packages/libs/global.d.ts new file mode 100644 index 0000000..c54c6fc --- /dev/null +++ b/packages/libs/global.d.ts @@ -0,0 +1,9 @@ +declare module "process" { + global { + namespace NodeJS { + interface ProcessEnv { + LOG_LEVEL: "debug" | "info" | "warn" | "error"; + } + } + } +} diff --git a/packages/libs/src/__tests__/loadEnvFile.test.ts b/packages/libs/src/__tests__/loadEnvFile.test.ts index ed9ef9d..b5fd2cb 100644 --- a/packages/libs/src/__tests__/loadEnvFile.test.ts +++ b/packages/libs/src/__tests__/loadEnvFile.test.ts @@ -1,44 +1,95 @@ -import { describe, expect, vi, it, beforeEach } from "vitest"; -import { getLogger, setLogger } from "../logger"; -import pino from "pino"; - -const defaultLogger = pino({ - name: "dandori", - level: "debug", - transport: { - target: "pino-pretty", - options: { - colorize: true, - }, - }, -}); +import { loadEnvFile } from "../index"; +import { + describe, + it, + expect, + beforeAll, + afterAll, + beforeEach, + vi, + afterEach, +} from "vitest"; +import { mkdir, rm, rmdir, writeFile } from "fs/promises"; + +const mockErrorLog = vi.fn(); -vi.mock("pino", () => ({ - default: vi.fn(), +vi.mock("../logger", () => ({ + getLogger: vi.fn(() => ({ + error: mockErrorLog, + })), })); -describe("logger", () => { - describe("use default logger", () => { - it("get default logger", () => { - expect(getLogger()).toEqual(defaultLogger); +describe("loadEnvFile", () => { + describe("with valid .env file", () => { + const openApiKeyPropName = "OPENAI_API_KEY"; + + afterEach(() => { + delete process.env[openApiKeyPropName]; + }); + + describe("no filePath argument", () => { + const apiKey = "123"; + const envFileName = ".env"; + + beforeAll(async () => { + await writeFile(envFileName, `${openApiKeyPropName}=${apiKey}`); + }); + + afterAll(async () => { + await rm(envFileName); + }); + + beforeEach(() => { + loadEnvFile(); + }); + + it(`loaded ${openApiKeyPropName}`, () => { + expect(process.env[openApiKeyPropName]).toBe(apiKey); + }); + }); + + describe("filePath argument", () => { + const apiKey = "456"; + const envFileDir = "./dir"; + const envFilePath = `./${envFileDir}/.env`; + + beforeAll(async () => { + await mkdir(envFileDir); + await writeFile(envFilePath, `${openApiKeyPropName}=${apiKey}`); + }); + + afterAll(async () => { + await rm(envFilePath); + await rmdir(envFileDir); + }); + + beforeEach(() => { + loadEnvFile(envFilePath); + }); + + it(`loaded ${openApiKeyPropName}`, () => { + expect(process.env[openApiKeyPropName]).toBe(apiKey); + }); }); }); - describe("use custom logger", () => { - const customLogger = { - debug: vi.fn(), - info: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - customProp: vi.fn(), - }; - - beforeEach(() => { - setLogger(customLogger); + describe("without valid .env file", () => { + const runErrorLoadEnvFile = () => loadEnvFile("./nodir/.env"); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it("throw Error", async () => { + expect(runErrorLoadEnvFile).toThrowError(); }); - it("get custom logger", () => { - expect(getLogger()).toEqual(customLogger); + it("called error log", async () => { + try { + runErrorLoadEnvFile(); + } catch (e) { + expect(mockErrorLog).toBeCalled(); + } }); }); }); diff --git a/packages/libs/src/__tests__/logger.test.ts b/packages/libs/src/__tests__/logger.test.ts index b5fd2cb..ed9ef9d 100644 --- a/packages/libs/src/__tests__/logger.test.ts +++ b/packages/libs/src/__tests__/logger.test.ts @@ -1,95 +1,44 @@ -import { loadEnvFile } from "../index"; -import { - describe, - it, - expect, - beforeAll, - afterAll, - beforeEach, - vi, - afterEach, -} from "vitest"; -import { mkdir, rm, rmdir, writeFile } from "fs/promises"; - -const mockErrorLog = vi.fn(); +import { describe, expect, vi, it, beforeEach } from "vitest"; +import { getLogger, setLogger } from "../logger"; +import pino from "pino"; + +const defaultLogger = pino({ + name: "dandori", + level: "debug", + transport: { + target: "pino-pretty", + options: { + colorize: true, + }, + }, +}); -vi.mock("../logger", () => ({ - getLogger: vi.fn(() => ({ - error: mockErrorLog, - })), +vi.mock("pino", () => ({ + default: vi.fn(), })); -describe("loadEnvFile", () => { - describe("with valid .env file", () => { - const openApiKeyPropName = "OPENAI_API_KEY"; - - afterEach(() => { - delete process.env[openApiKeyPropName]; - }); - - describe("no filePath argument", () => { - const apiKey = "123"; - const envFileName = ".env"; - - beforeAll(async () => { - await writeFile(envFileName, `${openApiKeyPropName}=${apiKey}`); - }); - - afterAll(async () => { - await rm(envFileName); - }); - - beforeEach(() => { - loadEnvFile(); - }); - - it(`loaded ${openApiKeyPropName}`, () => { - expect(process.env[openApiKeyPropName]).toBe(apiKey); - }); - }); - - describe("filePath argument", () => { - const apiKey = "456"; - const envFileDir = "./dir"; - const envFilePath = `./${envFileDir}/.env`; - - beforeAll(async () => { - await mkdir(envFileDir); - await writeFile(envFilePath, `${openApiKeyPropName}=${apiKey}`); - }); - - afterAll(async () => { - await rm(envFilePath); - await rmdir(envFileDir); - }); - - beforeEach(() => { - loadEnvFile(envFilePath); - }); - - it(`loaded ${openApiKeyPropName}`, () => { - expect(process.env[openApiKeyPropName]).toBe(apiKey); - }); +describe("logger", () => { + describe("use default logger", () => { + it("get default logger", () => { + expect(getLogger()).toEqual(defaultLogger); }); }); - describe("without valid .env file", () => { - const runErrorLoadEnvFile = () => loadEnvFile("./nodir/.env"); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it("throw Error", async () => { - expect(runErrorLoadEnvFile).toThrowError(); + describe("use custom logger", () => { + const customLogger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + customProp: vi.fn(), + }; + + beforeEach(() => { + setLogger(customLogger); }); - it("called error log", async () => { - try { - runErrorLoadEnvFile(); - } catch (e) { - expect(mockErrorLog).toBeCalled(); - } + it("get custom logger", () => { + expect(getLogger()).toEqual(customLogger); }); }); }); diff --git a/packages/libs/src/logger.ts b/packages/libs/src/logger.ts index 4a8f896..021226a 100644 --- a/packages/libs/src/logger.ts +++ b/packages/libs/src/logger.ts @@ -14,12 +14,14 @@ export const setLogger = (newLogger: Logger): void => { logger = newLogger; }; +export const logLevel = process.env.LOG_LEVEL ?? "info"; + export const getLogger = (): Logger => { if (!logger) { setLogger( pino({ name: "dandori", - level: "debug", + level: logLevel, transport: { target: "pino-pretty", options: { diff --git a/packages/libs/tsconfig.json b/packages/libs/tsconfig.json index 7460ef4..e6eda4e 100644 --- a/packages/libs/tsconfig.json +++ b/packages/libs/tsconfig.json @@ -1,3 +1,4 @@ { - "extends": "../../tsconfig.json" + "extends": "../../tsconfig.json", + "include": ["./src/**/*", "global.d.ts"] } \ No newline at end of file diff --git a/packages/ui/src/__tests__/miro.test.ts b/packages/ui/src/__tests__/miro.test.ts index a93c9fa..9bb3768 100644 --- a/packages/ui/src/__tests__/miro.test.ts +++ b/packages/ui/src/__tests__/miro.test.ts @@ -20,15 +20,18 @@ vi.mock("@mirohq/miro-api", () => { const mockLogInfo = vi.fn(); -vi.mock("@dandori/libs", () => ({ - getLogger: vi.fn(() => ({ - debug: vi.fn(), - info: mockLogInfo, - })), - runPromisesSequentially: vi.fn((runPromises, _runningLogPrefix) => - Promise.all(runPromises.map((runPromise: () => any) => runPromise())), - ), -})); +vi.mock("@dandori/libs", () => { + return { + logLevel: "info", + getLogger: vi.fn(() => ({ + debug: vi.fn(), + info: mockLogInfo, + })), + runPromisesSequentially: vi.fn((runPromises, _runningLogPrefix) => + Promise.all(runPromises.map((runPromise: () => any) => runPromise())), + ), + }; +}); const mockRunPromisesSequentially = runPromisesSequentially as Mock; diff --git a/packages/ui/src/__tests__/notion.test.ts b/packages/ui/src/__tests__/notion.test.ts index f008dda..f8058ae 100644 --- a/packages/ui/src/__tests__/notion.test.ts +++ b/packages/ui/src/__tests__/notion.test.ts @@ -15,18 +15,25 @@ import { runPromisesSequentially } from "@dandori/libs"; vi.mock("@notionhq/client", () => { const Client = vi.fn(); + enum LogLevel { + DEBUG = "debug", + INFO = "info", + WARN = "warn", + ERROR = "error", + } Client.prototype = { pages: { create: vi.fn(), }, }; - return { Client }; + return { Client, LogLevel }; }); vi.mock("@dandori/libs", () => { return { + logLevel: "info", getLogger: vi.fn(() => ({ - debug: vi.fn(), + info: vi.fn(), })), runPromisesSequentially: vi.fn((runPromises, _runningLogPrefix) => Promise.all(runPromises.map((runPromise: () => any) => runPromise())), diff --git a/packages/ui/src/miro.ts b/packages/ui/src/miro.ts index 8add17d..8af6da5 100644 --- a/packages/ui/src/miro.ts +++ b/packages/ui/src/miro.ts @@ -2,7 +2,7 @@ import { MiroApi } from "@mirohq/miro-api"; import { DandoriTask } from "@dandori/core"; import FlatToNested from "flat-to-nested"; import TreeModel from "tree-model"; -import { getLogger, runPromisesSequentially } from "@dandori/libs"; +import { getLogger, logLevel, runPromisesSequentially } from "@dandori/libs"; export type GenerateDandoriMiroCardsOptions = { boardId: Parameters[0]; @@ -58,7 +58,7 @@ export async function generateDandoriMiroCards( process.env.MIRO_API_KEY, undefined, (...thing) => { - logger.debug(thing); + logger[logLevel](thing); }, ); const miroBoard = await miroApi.getBoard(options.boardId); diff --git a/packages/ui/src/notion.ts b/packages/ui/src/notion.ts index 989a477..3e18b2c 100644 --- a/packages/ui/src/notion.ts +++ b/packages/ui/src/notion.ts @@ -5,7 +5,7 @@ import { DandoriTaskStatus, } from "@dandori/core"; import { Client, LogLevel } from "@notionhq/client"; -import { getLogger, runPromisesSequentially } from "@dandori/libs"; +import { getLogger, logLevel, runPromisesSequentially } from "@dandori/libs"; type SupportNotionTaskOptionalProperty = Exclude< DandoriTaskOptionalProperty, @@ -128,6 +128,19 @@ const createPageParams = ( }; }; +const getLogLevel = () => { + switch (logLevel) { + case "debug": + return LogLevel.DEBUG; + case "warn": + return LogLevel.WARN; + case "error": + return LogLevel.ERROR; + default: + return LogLevel.INFO; + } +}; + export async function generateDandoriNotionPages( tasks: DandoriTask[], options: GenerateDandoriNotionDatabaseItemsOptions, @@ -135,6 +148,7 @@ export async function generateDandoriNotionPages( const logger = getLogger(); const client = new Client({ auth: process.env.NOTION_API_KEY, + logLevel: getLogLevel(), logger: ( level: LogLevel, message: string,