0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-04-01 02:42:23 -05:00

fix: add legacyMergeConfigs legacy plugins (#5170)

* fix: add legacyMergeConfigs legacy plugins

* Update server.ts

* Update plugin-async-loader.ts

* Create yellow-flies-sniff.md

* add tests

* Update packages/loaders/src/plugin-async-loader.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Juan Picado 2025-03-29 15:24:27 +01:00 committed by GitHub
parent da1650c421
commit 8f28186645
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 78 additions and 13 deletions

View file

@ -0,0 +1,10 @@
---
'@verdaccio/search-indexer': patch
'@verdaccio/server': patch
'@verdaccio/loaders': patch
'@verdaccio/store': patch
'@verdaccio/auth': patch
'@verdaccio/web': patch
---
fix: add legacyMergeConfigs legacy plugins

View file

@ -123,6 +123,7 @@ class Auth implements IAuthMiddleware, TokenEncryption, pluginUtils.IBasicAuth {
typeof allow_publish !== 'undefined'
);
},
false,
this.config?.serverSettings?.pluginPrefix,
PLUGIN_CATEGORY.AUTHENTICATION
);

View file

@ -1,5 +1,6 @@
import buildDebug from 'debug';
import fs from 'fs';
import _ from 'lodash';
import { dirname, isAbsolute, join, resolve } from 'path';
import { pluginUtils } from '@verdaccio/core';
@ -15,6 +16,10 @@ async function isDirectory(pathFolder: string) {
return stat.isDirectory();
}
function mergeConfig(appConfig: unknown, pluginConfig: unknown) {
return _.merge({}, appConfig, pluginConfig);
}
// type Plugins<T> =
// | pluginUtils.Auth<T>
// | pluginUtils.Storage<T>
@ -47,6 +52,7 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
pluginConfigs: any = {},
pluginOptions: pluginUtils.PluginOptions,
sanityCheck: (plugin: PluginType<T>) => boolean,
legacyMergeConfigs: boolean = false,
prefix: string = 'verdaccio',
pluginCategory: string = ''
): Promise<PluginType<T>[]> {
@ -82,7 +88,12 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
logger.error(a, b);
});
if (plugin && isValid(plugin)) {
plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
plugin = executePlugin(
plugin,
pluginConfigs[pluginId],
pluginOptions,
legacyMergeConfigs
);
if (!sanityCheck(plugin)) {
logger.error(
{ content: externalFilePlugin },
@ -115,7 +126,7 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
logger.error(a, b);
});
if (plugin && isValid(plugin)) {
plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions);
plugin = executePlugin(plugin, pluginConfigs[pluginId], pluginOptions, legacyMergeConfigs);
if (!sanityCheck(plugin)) {
logger.error({ content: pluginName }, "@{content} doesn't look like a valid plugin");
continue;
@ -143,8 +154,15 @@ export async function asyncLoadPlugin<T extends pluginUtils.Plugin<T>>(
export function executePlugin<T>(
plugin: PluginType<T>,
pluginConfig: unknown,
pluginOptions: pluginUtils.PluginOptions
pluginOptions: pluginUtils.PluginOptions,
legacyMergeConfigs: boolean = false
): PluginType<T> {
// this is a legacy support for plugins that are not using the new API
if (legacyMergeConfigs) {
debug('>>> plugin merge config enabled');
let originalConfig = pluginOptions.config;
pluginConfig = mergeConfig(originalConfig, pluginConfig);
}
if (isES6(plugin)) {
debug('plugin is ES6');
// @ts-expect-error no relevant for the code

View file

@ -1,7 +1,13 @@
function ValidVerdaccioPlugin() {
return {
authenticate: function () {},
};
class ValidVerdaccioPlugin {
config;
options;
constructor(config, options) {
console.log('ValidVerdaccioPlugin constructor', config);
this.config = config;
this.options = options;
}
authenticate() {}
}
module.exports = ValidVerdaccioPlugin;
module.exports = (...rest) => new ValidVerdaccioPlugin(...rest);

View file

@ -5,7 +5,7 @@ import { Config, parseConfigFile } from '@verdaccio/config';
import { pluginUtils } from '@verdaccio/core';
import { logger, setup } from '@verdaccio/logger';
import { asyncLoadPlugin } from '../src/plugin-async-loader';
import { asyncLoadPlugin } from '../src/index';
function getConfig(file: string) {
const conPath = path.join(__dirname, './partials/config', file);
@ -71,6 +71,7 @@ describe('plugin loader', () => {
expect(plugins).toHaveLength(0);
});
});
describe('relative path', () => {
test('should resolve plugin based on relative path', async () => {
const config = getConfig('relative-plugins.yaml');
@ -93,6 +94,7 @@ describe('plugin loader', () => {
});
// config.config_path is not considered for loading plugins due legacy support
// @ts-ignore
test('should fails if config path is missing (only config_path)', async () => {
const config = getConfig('relative-plugins.yaml');
// @ts-expect-error
@ -142,6 +144,7 @@ describe('plugin loader', () => {
config.auth,
{ config, logger },
authSanitize,
false,
'customprefix'
);
@ -172,4 +175,27 @@ describe('plugin loader', () => {
expect(plugins).toHaveLength(1);
});
});
describe('legacy merge configs', () => {
// whenever 6.x and 7.x version are out of support, we can remove this test
test('should merge configuration with plugin configuration', async () => {
const config = getConfig('relative-plugins.yaml');
// force file instead a folder.
const plugins = await asyncLoadPlugin(config.auth, { config, logger }, authSanitize, true);
expect(plugins).toHaveLength(1);
const plugin = plugins[0];
// just check if the plugin has the main config
expect(plugin.config).toHaveProperty('self_path');
expect(plugin.config).toHaveProperty('storage');
// assume all config props are merged
// check if the plugin has the auth config
expect(plugin.config).toHaveProperty('auth');
expect(plugin.config.auth).toEqual({
plugin: {
enabled: true,
},
});
});
});
});

View file

@ -38,7 +38,7 @@
"type-check": "tsc --noEmit -p tsconfig.build.json",
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps",
"build": "esbuild src/index.ts --bundle --outfile=build/dist.js --platform=node --target=node12 && pnpm run build:types"
"build": "esbuild src/index.ts --bundle --outfile=build/dist.js --platform=node --target=node18 && pnpm run build:types"
},
"devDependencies": {
"@verdaccio/types": "workspace:13.0.0-next-8.4",

View file

@ -22,7 +22,7 @@ import {
import { Storage } from '@verdaccio/store';
import { ConfigYaml } from '@verdaccio/types';
import { Config as IConfig } from '@verdaccio/types';
import webMiddleware from '@verdaccio/web';
import webMiddleware, { PLUGIN_UI_PREFIX } from '@verdaccio/web';
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
import hookDebug from './debug';
@ -73,7 +73,8 @@ const defineAPI = async function (config: IConfig, storage: Storage): Promise<Ex
function (plugin) {
return typeof plugin.register_middlewares !== 'undefined';
},
config?.serverSettings?.pluginPrefix ?? 'verdaccio',
false,
config?.serverSettings?.pluginPrefix ?? PLUGIN_UI_PREFIX,
PLUGIN_CATEGORY.MIDDLEWARE
);

View file

@ -80,6 +80,7 @@ class LocalStorage {
(plugin) => {
return typeof plugin.getPackageStorage !== 'undefined';
},
false,
this.config?.serverSettings?.pluginPrefix,
PLUGIN_CATEGORY.STORAGE
);

View file

@ -686,6 +686,7 @@ class Storage {
(plugin: pluginUtils.ManifestFilter<Config>) => {
return typeof plugin.filter_metadata !== 'undefined';
},
false,
this.config?.serverSettings?.pluginPrefix,
PLUGIN_CATEGORY.FILTER
);
@ -1712,7 +1713,7 @@ class Storage {
proxy: npmjs
A package requires uplinks syncronization if the proxy section is defined. There can be
more than one uplink. The more uplinks are defined, the longer the request will take.
more than one uplink. The more uplinks are defined, the longer the request will take.
The requests are made in serial and if 1st call fails, the second will be triggered, otherwise
the 1st will reply and others will be discarded. The order is important.

View file

@ -26,6 +26,7 @@ export async function loadTheme(config: any) {
*/
return plugin.staticPath && plugin.manifest && plugin.manifestFiles;
},
false,
config?.serverSettings?.pluginPrefix ?? PLUGIN_UI_PREFIX,
PLUGIN_CATEGORY.THEME
);