diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90ad6e2a..c925e646 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,7 +114,6 @@ stateDiagram-v2 } state core { - getLogger() sharedHelpers sharedConstants types @@ -163,7 +162,7 @@ Bootstrapping all the files you'll need to start coding. yarn cli create-plugin ``` -Then learn more about what you can use from [the ecosystem](/packages/core). +Then learn more about what you can use from [the ecosystem](/packages/factory). ## Tests diff --git a/README.md b/README.md index 47b5990c..217eeab3 100644 --- a/README.md +++ b/README.md @@ -372,6 +372,7 @@ type GlobalContext = { writeDuration?: number; }; cwd: string; + getLogger: (name: string) => [Logger](/packages/factory/src/helpers.ts); // Added in `buildStart`. git?: { hash: string; diff --git a/packages/core/src/log.ts b/packages/core/src/log.ts deleted file mode 100644 index 4ac31f21..00000000 --- a/packages/core/src/log.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2019-Present Datadog, Inc. - -import c from 'chalk'; - -import type { LogLevel } from './types'; - -export type Logger = (text: any, type?: LogLevel) => void; - -// TODO Move this into a plugin and better integrate with the bundlers. -// TODO Warnings/errors should be added to the build report. -const log = (text: any, level: LogLevel, type: LogLevel = 'debug', name?: string) => { - // By default (debug) we print dimmed. - let color = c.dim; - let logFn = console.log; - - if (type === 'error') { - color = c.red; - logFn = console.error; - } else if (type === 'warn') { - color = c.yellow; - logFn = console.warn; - } else if (type === 'info') { - color = c.cyan; - logFn = console.log; - } - - const prefix = name ? `[${type}|${name}] ` : ''; - - if ( - level === 'debug' || - (level === 'info' && ['info', 'error', 'warn'].includes(type)) || - (level === 'warn' && ['error', 'warn'].includes(type)) || - (level === 'error' && type === 'error') - ) { - const content = typeof text === 'string' ? text : JSON.stringify(text, null, 2); - logFn(`${color(prefix)}${content}`); - } -}; - -export const getLogger = - (level: LogLevel = 'warn', name?: string): Logger => - (text: any, type: LogLevel = 'debug') => - log(text, level, type, name); diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 9a58bb5b..8b1cf3e3 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -41,6 +41,7 @@ export type SerializedOutput = Assign; export type BuildReport = { errors: string[]; warnings: string[]; + logs: { pluginName: string; type: LogLevel; message: string; time: number }[]; entries?: Entry[]; inputs?: Input[]; outputs?: Output[]; @@ -73,12 +74,21 @@ export type BundlerReport = { export type ToInjectItem = { type: 'file' | 'code'; value: string; fallback?: ToInjectItem }; +export type Logger = { + (text: any, type?: LogLevel): void; + error: (text: any) => void; + warn: (text: any) => void; + info: (text: any) => void; + debug: (text: any) => void; +}; +export type GetLogger = (name: string) => Logger; export type GlobalContext = { auth?: AuthOptions; inject: (item: ToInjectItem) => void; bundler: BundlerReport; build: BuildReport; cwd: string; + getLogger: GetLogger; git?: RepositoryData; pluginNames: string[]; start: number; @@ -103,13 +113,13 @@ export type AuthOptions = { apiKey?: string; }; -export interface GetPluginsOptions { +export interface BaseOptions { auth?: AuthOptions; disableGit?: boolean; logLevel?: LogLevel; } -export interface Options extends GetPluginsOptions { +export interface Options extends BaseOptions { // Each product should have a unique entry. // #types-injection-marker [rum.CONFIG_KEY]?: RumOptions; @@ -118,6 +128,9 @@ export interface Options extends GetPluginsOptions { customPlugins?: GetCustomPlugins; } +export type GetPluginsOptions = Required; +export type OptionsWithDefaults = Assign; + export type PluginName = `datadog-${Lowercase}-plugin`; type Data = { data: BodyInit; headers?: Record }; diff --git a/packages/factory/README.md b/packages/factory/README.md index 3ae2e009..3af47770 100644 --- a/packages/factory/README.md +++ b/packages/factory/README.md @@ -50,6 +50,32 @@ Most of the time they will interact via the global context. [📝 Full documentation ➡️](/packages/plugins/injection#readme) +## Logger + +If you need to log anything into the console you'll have to use the global Logger. +Simply instantiate your logger in your plugin's initialization. + +```typescript +// ./packages/plugins/my-plugin/index.ts +[...] + +export const getMyPlugins = (context: GlobalContext) => { + const logger = context.getLogger('my-plugin'); +}; +``` + +Then you can either use one of the helpers or programmatically use a specific level: + +```typescript +const logLevel = 'warn'; +logger('This will be a warning', logLevel); + +logger.warn('This is also a warning'); +logger.error('This is an error'); +logger.info('This is an info'); +logger.debug('This is a debug message'); +``` + ## Global Context A global, shared context within the build plugins ecosystem.
@@ -107,6 +133,7 @@ type GlobalContext = { writeDuration?: number; }; cwd: string; + getLogger: (name: string) => [Logger](/packages/factory/src/helpers.ts); // Added in `buildStart`. git?: { hash: string; diff --git a/packages/factory/package.json b/packages/factory/package.json index e64a5ab0..e65a8e8a 100644 --- a/packages/factory/package.json +++ b/packages/factory/package.json @@ -23,6 +23,7 @@ "@dd/internal-injection-plugin": "workspace:*", "@dd/rum-plugin": "workspace:*", "@dd/telemetry-plugin": "workspace:*", + "chalk": "2.3.1", "unplugin": "1.14.1" } } diff --git a/packages/factory/src/helpers.ts b/packages/factory/src/helpers.ts index 6bcfb52e..f927973d 100644 --- a/packages/factory/src/helpers.ts +++ b/packages/factory/src/helpers.ts @@ -3,22 +3,85 @@ // Copyright 2019-Present Datadog, Inc. import type { + BuildReport, BundlerFullName, BundlerName, FactoryMeta, + GetLogger, GlobalContext, + LogLevel, Options, + OptionsWithDefaults, ToInjectItem, } from '@dd/core/types'; +import c from 'chalk'; + +const logPriority: Record = { + debug: 0, + info: 1, + warn: 2, + error: 3, + none: 4, +}; + +const getLoggerFactory = + (build: BuildReport, logLevel: LogLevel = 'warn'): GetLogger => + (name) => { + const log = (text: any, type: LogLevel = 'debug') => { + // By default (debug) we print dimmed. + let color = c.dim; + let logFn = console.log; + + if (type === 'error') { + color = c.red; + logFn = console.error; + } else if (type === 'warn') { + color = c.yellow; + logFn = console.warn; + } else if (type === 'info') { + color = c.cyan; + logFn = console.log; + } + + const prefix = `[${type}|${name}]`; + + // Keep a trace of the log in the build report. + const content = typeof text === 'string' ? text : JSON.stringify(text, null, 2); + build.logs.push({ pluginName: name, type, message: content, time: Date.now() }); + if (type === 'error') { + build.errors.push(content); + } + if (type === 'warn') { + build.warnings.push(content); + } + + // Only log if the log level is high enough. + if (logPriority[type] >= logPriority[logLevel]) { + logFn(`${color(prefix)} ${content}`); + } + }; + + const logFn = (text: any, type: LogLevel = 'debug') => { + log(text, type); + }; + + // Add shortcuts for the other log levels. + logFn.error = (text: any) => log(text, 'error'); + logFn.warn = (text: any) => log(text, 'warn'); + logFn.info = (text: any) => log(text, 'info'); + logFn.debug = (text: any) => log(text, 'debug'); + + return logFn; + }; export const getContext = ({ - auth, + options, bundlerName, bundlerVersion, injections, version, }: { - auth: Options['auth']; + options: OptionsWithDefaults; bundlerName: BundlerName; bundlerVersion: string; injections: ToInjectItem[]; @@ -26,9 +89,13 @@ export const getContext = ({ }): GlobalContext => { const cwd = process.cwd(); const variant = bundlerName === 'webpack' ? bundlerVersion.split('.')[0] : ''; - + const build: BuildReport = { + errors: [], + warnings: [], + logs: [], + }; const context: GlobalContext = { - auth, + auth: options.auth, pluginNames: [], bundler: { name: bundlerName, @@ -37,14 +104,12 @@ export const getContext = ({ outDir: cwd, version: bundlerVersion, }, - build: { - errors: [], - warnings: [], - }, + build, cwd, inject: (item: ToInjectItem) => { injections.push(item); }, + getLogger: getLoggerFactory(build, options.logLevel), start: Date.now(), version, }; @@ -52,7 +117,7 @@ export const getContext = ({ return context; }; -export const validateOptions = (options: Options = {}): Options => { +export const validateOptions = (options: Options = {}): OptionsWithDefaults => { return { auth: {}, disableGit: false, diff --git a/packages/factory/src/index.ts b/packages/factory/src/index.ts index 80c76d93..6a143331 100644 --- a/packages/factory/src/index.ts +++ b/packages/factory/src/index.ts @@ -16,6 +16,7 @@ import type { FactoryMeta, GlobalContext, Options, + OptionsWithDefaults, PluginOptions, ToInjectItem, } from '@dd/core/types'; @@ -59,7 +60,7 @@ export const buildPluginFactory = ({ // TODO: Validate API Key and endpoint. // TODO: Inject a metric logger into the global context. - const options = validateOptions(opts); + const options: OptionsWithDefaults = validateOptions(opts); // Set the host name for the esbuild plugin. if (unpluginMetaContext.framework === 'esbuild') { @@ -69,7 +70,7 @@ export const buildPluginFactory = ({ // Create the global context. const injections: ToInjectItem[] = []; const context: GlobalContext = getContext({ - auth: options.auth, + options, bundlerVersion: bundler.version || bundler.VERSION, bundlerName: unpluginMetaContext.framework as BundlerName, injections, @@ -83,10 +84,10 @@ export const buildPluginFactory = ({ const plugins: (PluginOptions | UnpluginOptions)[] = [ // Prefill with our internal plugins. // #internal-plugins-injection-marker - ...getBuildReportPlugins(options, context), + ...getBuildReportPlugins(context), ...getBundlerReportPlugins(context), ...getGitPlugins(options, context), - ...getInjectionPlugins(bundler, options, context, injections), + ...getInjectionPlugins(bundler, context, injections), // #internal-plugins-injection-marker ]; diff --git a/packages/plugins/build-report/src/esbuild.ts b/packages/plugins/build-report/src/esbuild.ts index 885a5c2a..77019046 100644 --- a/packages/plugins/build-report/src/esbuild.ts +++ b/packages/plugins/build-report/src/esbuild.ts @@ -3,8 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { getResolvedPath, isInjectionFile } from '@dd/core/helpers'; -import type { Logger } from '@dd/core/log'; -import type { Entry, GlobalContext, Input, Output, PluginOptions } from '@dd/core/types'; +import type { Logger, Entry, GlobalContext, Input, Output, PluginOptions } from '@dd/core/types'; import { glob } from 'glob'; import { cleanName, getAbsolutePath, getType } from './helpers'; @@ -68,8 +67,8 @@ export const getEsbuildPlugin = (context: GlobalContext, log: Logger): PluginOpt const entryNames = getEntryNames(entrypoints, context); build.onEnd((result) => { - context.build.errors = result.errors.map((err) => err.text); - context.build.warnings = result.warnings.map((err) => err.text); + context.build.errors.push(...result.errors.map((err) => err.text)); + context.build.warnings.push(...result.warnings.map((err) => err.text)); const warn = (warning: string) => { context.build.warnings.push(warning); diff --git a/packages/plugins/build-report/src/helpers.ts b/packages/plugins/build-report/src/helpers.ts index fa421bae..080fd5c3 100644 --- a/packages/plugins/build-report/src/helpers.ts +++ b/packages/plugins/build-report/src/helpers.ts @@ -51,6 +51,7 @@ export const serializeBuildReport = (report: BuildReport): SerializedBuildReport const jsonReport: SerializedBuildReport = { errors: report.errors, warnings: report.warnings, + logs: report.logs, start: report.start, end: report.end, duration: report.duration, @@ -103,6 +104,7 @@ export const unserializeBuildReport = (report: SerializedBuildReport): BuildRepo const buildReport: BuildReport = { errors: report.errors, warnings: report.warnings, + logs: report.logs, start: report.start, end: report.end, duration: report.duration, diff --git a/packages/plugins/build-report/src/index.ts b/packages/plugins/build-report/src/index.ts index 5700946a..a8945e8a 100644 --- a/packages/plugins/build-report/src/index.ts +++ b/packages/plugins/build-report/src/index.ts @@ -2,8 +2,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import { getLogger } from '@dd/core/log'; -import type { GlobalContext, Options, PluginOptions } from '@dd/core/types'; +import type { GlobalContext, PluginOptions } from '@dd/core/types'; import { getEsbuildPlugin } from './esbuild'; import { getRollupPlugin } from './rollup'; @@ -11,8 +10,8 @@ import { getWebpackPlugin } from './webpack'; const PLUGIN_NAME = 'datadog-build-report-plugin'; -export const getBuildReportPlugins = (opts: Options, context: GlobalContext): PluginOptions[] => { - const log = getLogger(opts.logLevel, PLUGIN_NAME); +export const getBuildReportPlugins = (context: GlobalContext): PluginOptions[] => { + const log = context.getLogger(PLUGIN_NAME); return [ { name: PLUGIN_NAME, diff --git a/packages/plugins/build-report/src/rollup.ts b/packages/plugins/build-report/src/rollup.ts index 5b512874..5ccf56c0 100644 --- a/packages/plugins/build-report/src/rollup.ts +++ b/packages/plugins/build-report/src/rollup.ts @@ -2,8 +2,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; -import type { Entry, GlobalContext, Input, Output, PluginOptions } from '@dd/core/types'; +import type { Logger, Entry, GlobalContext, Input, Output, PluginOptions } from '@dd/core/types'; import { cleanName, cleanPath, cleanReport, getAbsolutePath, getType } from './helpers'; diff --git a/packages/plugins/build-report/src/webpack.ts b/packages/plugins/build-report/src/webpack.ts index 85185bc9..bb4c7d2b 100644 --- a/packages/plugins/build-report/src/webpack.ts +++ b/packages/plugins/build-report/src/webpack.ts @@ -2,8 +2,8 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; import type { + Logger, Entry, GlobalContext, Input, @@ -292,8 +292,8 @@ export const getWebpackPlugin = } // Save everything in the context. - context.build.errors = result.errors.map((err) => err.message); - context.build.warnings = [...warnings, ...result.warnings.map((err) => err.message)]; + context.build.errors.push(...result.errors.map((err) => err.message)); + context.build.warnings.push(...warnings, ...result.warnings.map((err) => err.message)); context.build.inputs = inputs; context.build.outputs = outputs; context.build.entries = entries; diff --git a/packages/plugins/injection/src/helpers.ts b/packages/plugins/injection/src/helpers.ts index 25a1c687..2e765b67 100644 --- a/packages/plugins/injection/src/helpers.ts +++ b/packages/plugins/injection/src/helpers.ts @@ -3,8 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { doRequest, truncateString } from '@dd/core/helpers'; -import type { Logger } from '@dd/core/log'; -import type { ToInjectItem } from '@dd/core/types'; +import type { Logger, ToInjectItem } from '@dd/core/types'; import { getAbsolutePath } from '@dd/internal-build-report-plugin/helpers'; import { readFile } from 'fs/promises'; diff --git a/packages/plugins/injection/src/index.ts b/packages/plugins/injection/src/index.ts index 850adab3..dae1f27d 100644 --- a/packages/plugins/injection/src/index.ts +++ b/packages/plugins/injection/src/index.ts @@ -4,8 +4,7 @@ import { INJECTED_FILE } from '@dd/core/constants'; import { outputFile, rm } from '@dd/core/helpers'; -import { getLogger } from '@dd/core/log'; -import type { GlobalContext, Options, PluginOptions, ToInjectItem } from '@dd/core/types'; +import type { GlobalContext, PluginOptions, ToInjectItem } from '@dd/core/types'; import path from 'path'; import { PLUGIN_NAME, PREPARATION_PLUGIN_NAME } from './constants'; @@ -13,11 +12,10 @@ import { processInjections } from './helpers'; export const getInjectionPlugins = ( bundler: any, - opts: Options, context: GlobalContext, toInject: ToInjectItem[], ): PluginOptions[] => { - const log = getLogger(opts.logLevel, PLUGIN_NAME); + const log = context.getLogger(PLUGIN_NAME); const contentToInject: string[] = []; const getContentToInject = () => { diff --git a/packages/plugins/rum/src/index.ts b/packages/plugins/rum/src/index.ts index 549fdf4a..01e71c46 100644 --- a/packages/plugins/rum/src/index.ts +++ b/packages/plugins/rum/src/index.ts @@ -2,7 +2,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import { getLogger } from '@dd/core/log'; import type { GlobalContext, GetPlugins } from '@dd/core/types'; import { PLUGIN_NAME } from './constants'; @@ -22,7 +21,7 @@ export const getPlugins: GetPlugins = ( opts: OptionsWithRum, context: GlobalContext, ) => { - const log = getLogger(opts.logLevel, PLUGIN_NAME); + const log = context.getLogger(PLUGIN_NAME); // Verify configuration. const rumOptions = validateOptions(opts, log); return [ diff --git a/packages/plugins/rum/src/sourcemaps/index.ts b/packages/plugins/rum/src/sourcemaps/index.ts index eb00b94d..6020f346 100644 --- a/packages/plugins/rum/src/sourcemaps/index.ts +++ b/packages/plugins/rum/src/sourcemaps/index.ts @@ -2,8 +2,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; -import type { GlobalContext } from '@dd/core/types'; +import type { Logger, GlobalContext } from '@dd/core/types'; import chalk from 'chalk'; import { outdent } from 'outdent'; diff --git a/packages/plugins/rum/src/sourcemaps/sender.ts b/packages/plugins/rum/src/sourcemaps/sender.ts index a50626b6..f19c825f 100644 --- a/packages/plugins/rum/src/sourcemaps/sender.ts +++ b/packages/plugins/rum/src/sourcemaps/sender.ts @@ -3,8 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { NB_RETRIES, doRequest, formatDuration } from '@dd/core/helpers'; -import type { Logger } from '@dd/core/log'; -import type { GlobalContext } from '@dd/core/types'; +import type { Logger, GlobalContext } from '@dd/core/types'; import { File } from 'buffer'; import chalk from 'chalk'; import fs from 'fs'; diff --git a/packages/plugins/rum/src/validate.ts b/packages/plugins/rum/src/validate.ts index 42d69d90..add00334 100644 --- a/packages/plugins/rum/src/validate.ts +++ b/packages/plugins/rum/src/validate.ts @@ -2,7 +2,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; +import type { Logger } from '@dd/core/types'; import chalk from 'chalk'; import { CONFIG_KEY, PLUGIN_NAME } from './constants'; diff --git a/packages/plugins/telemetry/src/common/output/files.ts b/packages/plugins/telemetry/src/common/output/files.ts index 3d2b9053..a1ba2f96 100644 --- a/packages/plugins/telemetry/src/common/output/files.ts +++ b/packages/plugins/telemetry/src/common/output/files.ts @@ -3,7 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { formatDuration, outputJson } from '@dd/core/helpers'; -import type { Logger } from '@dd/core/log'; +import type { Logger } from '@dd/core/types'; import type { MetricToSend, OutputOptions, Report } from '@dd/telemetry-plugin/types'; import path from 'path'; diff --git a/packages/plugins/telemetry/src/common/output/text.ts b/packages/plugins/telemetry/src/common/output/text.ts index 3172a040..87f1ac94 100644 --- a/packages/plugins/telemetry/src/common/output/text.ts +++ b/packages/plugins/telemetry/src/common/output/text.ts @@ -3,8 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { formatDuration, truncateString } from '@dd/core/helpers'; -import type { Logger } from '@dd/core/log'; -import type { Entry, GlobalContext, Output } from '@dd/core/types'; +import type { Logger, Entry, GlobalContext, Output } from '@dd/core/types'; import { serializeBuildReport } from '@dd/internal-build-report-plugin/helpers'; import chalk from 'chalk'; import prettyBytes from 'pretty-bytes'; diff --git a/packages/plugins/telemetry/src/common/sender.ts b/packages/plugins/telemetry/src/common/sender.ts index 9a5f634f..251028b9 100644 --- a/packages/plugins/telemetry/src/common/sender.ts +++ b/packages/plugins/telemetry/src/common/sender.ts @@ -3,7 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { doRequest, formatDuration } from '@dd/core/helpers'; -import type { Logger } from '@dd/core/log'; +import type { Logger } from '@dd/core/types'; import type { MetricToSend } from '@dd/telemetry-plugin/types'; export const sendMetrics = ( diff --git a/packages/plugins/telemetry/src/esbuild-plugin/index.ts b/packages/plugins/telemetry/src/esbuild-plugin/index.ts index d0f5bfd4..434788c8 100644 --- a/packages/plugins/telemetry/src/esbuild-plugin/index.ts +++ b/packages/plugins/telemetry/src/esbuild-plugin/index.ts @@ -2,8 +2,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; -import type { GlobalContext, PluginOptions } from '@dd/core/types'; +import type { Logger, GlobalContext, PluginOptions } from '@dd/core/types'; import type { BundlerContext } from '@dd/telemetry-plugin/types'; import type { BuildResult } from 'esbuild'; diff --git a/packages/plugins/telemetry/src/index.ts b/packages/plugins/telemetry/src/index.ts index e059e51b..f1ee3932 100644 --- a/packages/plugins/telemetry/src/index.ts +++ b/packages/plugins/telemetry/src/index.ts @@ -2,7 +2,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import { getLogger } from '@dd/core/log'; import type { GlobalContext, GetPlugins, PluginOptions } from '@dd/core/types'; import { getMetrics } from './common/aggregator'; @@ -44,7 +43,7 @@ export const getPlugins: GetPlugins = ( }; const telemetryOptions = validateOptions(options); - const logger = getLogger(options.logLevel, PLUGIN_NAME); + const logger = context.getLogger(PLUGIN_NAME); const plugins: PluginOptions[] = []; // Webpack and Esbuild specific plugins. diff --git a/packages/tests/src/_jest/helpers/mocks.ts b/packages/tests/src/_jest/helpers/mocks.ts index 471d5eee..1aaf0a34 100644 --- a/packages/tests/src/_jest/helpers/mocks.ts +++ b/packages/tests/src/_jest/helpers/mocks.ts @@ -6,8 +6,11 @@ import { outputJsonSync } from '@dd/core/helpers'; import type { File, GetCustomPlugins, + GetPluginsOptions, GlobalContext, IterableElement, + Logger, + LogLevel, Options, } from '@dd/core/types'; import { serializeBuildReport } from '@dd/internal-build-report-plugin/helpers'; @@ -35,13 +38,29 @@ export const defaultEntries = { }; export const defaultDestination = path.resolve(ROOT, 'packages/tests/src/_jest/fixtures/dist'); -export const defaultPluginOptions: Options = { +export const defaultPluginOptions: GetPluginsOptions = { auth: { apiKey: '123', }, + disableGit: false, logLevel: 'debug', }; +const logFn: any = jest.fn((text: any, type?: LogLevel) => {}); +logFn.error = (text: any) => { + logFn(text, 'error'); +}; +logFn.warn = (text: any) => { + logFn(text, 'warn'); +}; +logFn.info = (text: any) => { + logFn(text, 'info'); +}; +logFn.debug = (text: any) => { + logFn(text, 'debug'); +}; +export const mockLogger: Logger = logFn; + export const getContextMock = (options: Partial = {}): GlobalContext => { return { auth: { apiKey: 'FAKE_API_KEY' }, @@ -54,9 +73,11 @@ export const getContextMock = (options: Partial = {}): GlobalCont build: { warnings: [], errors: [], + logs: [], }, cwd: '/cwd/path', inject: jest.fn(), + getLogger: jest.fn(() => mockLogger), pluginNames: [], start: Date.now(), version: 'FAKE_VERSION', diff --git a/packages/tests/src/factory/index.test.ts b/packages/tests/src/factory/index.test.ts index 12288eed..8f5348ad 100644 --- a/packages/tests/src/factory/index.test.ts +++ b/packages/tests/src/factory/index.test.ts @@ -27,7 +27,7 @@ describe('Factory', () => { const { buildPluginFactory } = await import('@dd/factory'); expect(() => { const factory = buildPluginFactory({ bundler: {}, version: '1.0.0' }); - // Vite can call the factory without options. + // Vite could call the factory without options. // @ts-expect-error - We are testing the factory without options. factory.vite(); }).not.toThrow(); diff --git a/packages/tests/src/plugins/injection/helpers.test.ts b/packages/tests/src/plugins/injection/helpers.test.ts index e6d2b30a..76ce4620 100644 --- a/packages/tests/src/plugins/injection/helpers.test.ts +++ b/packages/tests/src/plugins/injection/helpers.test.ts @@ -2,7 +2,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; import type { ToInjectItem } from '@dd/core/types'; import { processInjections, @@ -10,6 +9,7 @@ import { processLocalFile, processDistantFile, } from '@dd/internal-injection-plugin/helpers'; +import { mockLogger } from '@dd/tests/_jest/helpers/mocks'; import { vol } from 'memfs'; import nock from 'nock'; import path from 'path'; @@ -37,7 +37,6 @@ const nonExistingDistantFile: ToInjectItem = { }; describe('Injection Plugin Helpers', () => { - const mockLogger: Logger = jest.fn(); let nockScope: nock.Scope; beforeEach(() => { diff --git a/packages/tests/src/plugins/rum/sourcemaps/files.test.ts b/packages/tests/src/plugins/rum/sourcemaps/files.test.ts index 9a77b192..7bb1e1aa 100644 --- a/packages/tests/src/plugins/rum/sourcemaps/files.test.ts +++ b/packages/tests/src/plugins/rum/sourcemaps/files.test.ts @@ -24,6 +24,7 @@ describe('RUM Plugin Sourcemaps Files', () => { build: { warnings: [], errors: [], + logs: [], outputs: [ 'fixtures/common.js', 'fixtures/common.min.js.map', diff --git a/packages/tests/src/plugins/rum/sourcemaps/sender.test.ts b/packages/tests/src/plugins/rum/sourcemaps/sender.test.ts index 7742670a..c3f8e821 100644 --- a/packages/tests/src/plugins/rum/sourcemaps/sender.test.ts +++ b/packages/tests/src/plugins/rum/sourcemaps/sender.test.ts @@ -4,7 +4,7 @@ import { doRequest } from '@dd/core/helpers'; import { getData, sendSourcemaps, upload } from '@dd/rum-plugin/sourcemaps/sender'; -import { getContextMock } from '@dd/tests/_jest/helpers/mocks'; +import { getContextMock, mockLogger } from '@dd/tests/_jest/helpers/mocks'; import { vol } from 'memfs'; import { type Stream } from 'stream'; import { unzipSync } from 'zlib'; @@ -89,7 +89,7 @@ describe('RUM Plugin Sourcemaps', () => { [getSourcemapMock()], getSourcemapsConfiguration(), getContextMock(), - () => {}, + mockLogger, ); expect(doRequestMock).toHaveBeenCalledTimes(1); @@ -105,17 +105,15 @@ describe('RUM Plugin Sourcemaps', () => { __dirname, ); - const logMock = jest.fn(); - await sendSourcemaps( [getSourcemapMock()], getSourcemapsConfiguration(), getContextMock(), - logMock, + mockLogger, ); - expect(logMock).toHaveBeenCalledTimes(1); - expect(logMock).toHaveBeenCalledWith( + expect(mockLogger).toHaveBeenCalledTimes(1); + expect(mockLogger).toHaveBeenCalledWith( expect.stringMatching('Failed to prepare payloads, aborting upload'), 'error', ); @@ -137,7 +135,7 @@ describe('RUM Plugin Sourcemaps', () => { [getSourcemapMock()], getSourcemapsConfiguration({ bailOnError: true }), getContextMock(), - () => {}, + mockLogger, ); }).rejects.toThrow('Failed to prepare payloads, aborting upload'); expect(doRequestMock).not.toHaveBeenCalled(); @@ -170,7 +168,7 @@ describe('RUM Plugin Sourcemaps', () => { payloads, getSourcemapsConfiguration(), getContextMock(), - () => {}, + mockLogger, ); expect(warnings).toHaveLength(0); @@ -186,7 +184,7 @@ describe('RUM Plugin Sourcemaps', () => { payloads, getSourcemapsConfiguration(), getContextMock(), - jest.fn(), + mockLogger, ); expect(errors).toHaveLength(1); @@ -209,7 +207,7 @@ describe('RUM Plugin Sourcemaps', () => { payloads, getSourcemapsConfiguration({ bailOnError: true }), getContextMock(), - () => {}, + mockLogger, ), ).rejects.toThrow('Fake Error'); }); diff --git a/packages/tests/src/plugins/rum/validate.test.ts b/packages/tests/src/plugins/rum/validate.test.ts index 02639188..c12f1277 100644 --- a/packages/tests/src/plugins/rum/validate.test.ts +++ b/packages/tests/src/plugins/rum/validate.test.ts @@ -4,6 +4,7 @@ import type { RumSourcemapsOptions } from '@dd/rum-plugin/types'; import { validateOptions, validateSourcemapsOptions } from '@dd/rum-plugin/validate'; +import { mockLogger } from '@dd/tests/_jest/helpers/mocks'; import stripAnsi from 'strip-ansi'; import { getMinimalSourcemapsConfiguration } from './testHelpers'; @@ -20,7 +21,7 @@ describe('RUM Plugins validate', () => { disabled: false, }, }, - jest.fn(), + mockLogger, ); expect(config).toEqual({ @@ -40,7 +41,7 @@ describe('RUM Plugins validate', () => { sourcemaps: {} as RumSourcemapsOptions, }, }, - jest.fn(), + mockLogger, ); }).toThrow(); }); diff --git a/packages/tests/src/plugins/telemetry/common/helpers.test.ts b/packages/tests/src/plugins/telemetry/common/helpers.test.ts index 19c043f6..7b252523 100644 --- a/packages/tests/src/plugins/telemetry/common/helpers.test.ts +++ b/packages/tests/src/plugins/telemetry/common/helpers.test.ts @@ -9,13 +9,14 @@ import { validateOptions, } from '@dd/telemetry-plugin/common/helpers'; import { CONFIG_KEY } from '@dd/telemetry-plugin'; +import { defaultPluginOptions } from '@dd/tests/_jest/helpers/mocks'; import { getMockCompilation, getMockModule, mockCompilation } from '../testHelpers'; describe('Telemetry Helpers', () => { describe('validateOptions', () => { test('Should return the default options', () => { - const options = { [CONFIG_KEY]: {} }; + const options = { ...defaultPluginOptions, [CONFIG_KEY]: {} }; expect(validateOptions(options)).toEqual({ disabled: false, enableTracing: false, @@ -30,6 +31,7 @@ describe('Telemetry Helpers', () => { test('Should return the options with the provided values', () => { const fakeFilter = jest.fn(); const options = { + ...defaultPluginOptions, [CONFIG_KEY]: { disabled: true, enableTracing: true, @@ -53,6 +55,7 @@ describe('Telemetry Helpers', () => { test('Should add https:// if the endpoint does not have one', () => { const options = { + ...defaultPluginOptions, [CONFIG_KEY]: { endPoint: 'app.datadoghq.eu', }, diff --git a/packages/tests/src/plugins/telemetry/common/output/files.test.ts b/packages/tests/src/plugins/telemetry/common/output/files.test.ts index f020d308..d4479ca9 100644 --- a/packages/tests/src/plugins/telemetry/common/output/files.test.ts +++ b/packages/tests/src/plugins/telemetry/common/output/files.test.ts @@ -4,7 +4,8 @@ import { outputFiles } from '@dd/telemetry-plugin/common/output/files'; import type { OutputOptions } from '@dd/telemetry-plugin/types'; -import { mockLogger, mockReport } from '@dd/tests/plugins/telemetry/testHelpers'; +import { mockLogger } from '@dd/tests/_jest/helpers/mocks'; +import { mockReport } from '@dd/tests/plugins/telemetry/testHelpers'; import { vol } from 'memfs'; import path from 'path'; diff --git a/packages/tests/src/plugins/telemetry/testHelpers.ts b/packages/tests/src/plugins/telemetry/testHelpers.ts index 340e3794..0252d74b 100644 --- a/packages/tests/src/plugins/telemetry/testHelpers.ts +++ b/packages/tests/src/plugins/telemetry/testHelpers.ts @@ -2,8 +2,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2019-Present Datadog, Inc. -import type { Logger } from '@dd/core/log'; -import type { LogLevel, Options } from '@dd/core/types'; import type { Report, Compilation, @@ -13,7 +11,7 @@ import type { TelemetryOptions, Module, } from '@dd/telemetry-plugin/types'; -import { FAKE_URL } from '@dd/tests/_jest/helpers/mocks'; +import { FAKE_URL, defaultPluginOptions } from '@dd/tests/_jest/helpers/mocks'; import type { PluginBuild, Metafile } from 'esbuild'; import esbuild from 'esbuild'; @@ -113,12 +111,6 @@ export const mockReport: Report = { }, }; -export const mockOptions: Options = { - auth: { - apiKey: '', - }, -}; -export const mockLogger: Logger = jest.fn((text: any, type?: LogLevel) => {}); export const mockOutputOptions: OutputOptions = true; export const mockOptionsDD: OptionsDD = { tags: [], @@ -128,7 +120,7 @@ export const mockOptionsDD: OptionsDD = { }; export const mockTelemetryOptions: TelemetryOptions = {}; export const mockOptionsWithTelemetry: OptionsWithTelemetry = { - ...mockOptions, + ...defaultPluginOptions, telemetry: mockTelemetryOptions, }; diff --git a/packages/tools/src/commands/create-plugin/templates.ts b/packages/tools/src/commands/create-plugin/templates.ts index 4b27ff4a..043752b9 100644 --- a/packages/tools/src/commands/create-plugin/templates.ts +++ b/packages/tools/src/commands/create-plugin/templates.ts @@ -27,7 +27,6 @@ export const getFiles = (context: Context): File[] => { content: (ctx) => { const hooksContent = ctx.hooks.map((hook) => getHookTemplate(hook)).join('\n'); return outdent` - import { getLogger } from '@dd/core/log'; import type { GlobalContext, GetPlugins } from '@dd/core/types'; import { CONFIG_KEY, PLUGIN_NAME } from './constants'; @@ -58,7 +57,8 @@ export const getFiles = (context: Context): File[] => { opts: OptionsWith${pascalCase}, context: GlobalContext, ) => { - const log = getLogger(opts.logLevel, PLUGIN_NAME); + const log = context.getLogger(PLUGIN_NAME); + // Verify configuration. const options = validateOptions(opts); @@ -99,18 +99,12 @@ export const getFiles = (context: Context): File[] => { content: (ctx) => { const hooksContent = ctx.hooks.map((hook) => getHookTemplate(hook)).join('\n'); return outdent` - import { getLogger } from '@dd/core/log'; - import type { GlobalContext, Options, PluginOptions } from '@dd/core/types'; + import type { GlobalContext, PluginOptions } from '@dd/core/types'; import { PLUGIN_NAME } from './constants'; - // Feel free to change how you want to handle the plugin's creation. - // TODO Call this function from packages/factory/src/internalPlugins.ts - export const get${pascalCase}Plugins = ( - opts: Options, - context: GlobalContext, - ): PluginOptions[] => { - const log = getLogger(opts.logLevel, PLUGIN_NAME); + export const get${pascalCase}Plugins = (context: GlobalContext): PluginOptions[] => { + const log = context.getLogger(PLUGIN_NAME); return [ { diff --git a/packages/tools/src/helpers.ts b/packages/tools/src/helpers.ts index 57564770..98cd69fe 100644 --- a/packages/tools/src/helpers.ts +++ b/packages/tools/src/helpers.ts @@ -3,7 +3,7 @@ // Copyright 2019-Present Datadog, Inc. import { readJsonSync } from '@dd/core/helpers'; -import type { GetPlugins } from '@dd/core/types'; +import type { GetPlugins, Logger } from '@dd/core/types'; import chalk from 'chalk'; import { execFile, execFileSync } from 'child_process'; import path from 'path'; @@ -149,6 +149,12 @@ export const getSupportedBundlers = (getPlugins: GetPlugins) => { build: { warnings: [], errors: [], + logs: [], + }, + getLogger() { + const fn = () => {}; + // We don't care about the logger here. + return fn as unknown as Logger; }, inject() {}, pluginNames: [], diff --git a/yarn.lock b/yarn.lock index ada35051..06033937 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1601,6 +1601,7 @@ __metadata: "@dd/internal-injection-plugin": "workspace:*" "@dd/rum-plugin": "workspace:*" "@dd/telemetry-plugin": "workspace:*" + chalk: "npm:2.3.1" unplugin: "npm:1.14.1" languageName: unknown linkType: soft