From b2a378aeb700963c6d4a24eae06a01db58523c1a Mon Sep 17 00:00:00 2001 From: Subhash Khileri Date: Wed, 11 Feb 2026 23:14:15 +0530 Subject: [PATCH 1/2] fix: add OCI URL replacement for user-provided dynamic-plugins config --- docs/.vitepress/config.ts | 2 +- docs/changelog.md | 7 +- docs/overlay/examples/basic-plugin.md | 2 +- docs/overlay/examples/tech-radar.md | 2 +- .../test-structure/directory-layout.md | 2 +- package.json | 2 +- src/utils/plugin-metadata.ts | 164 ++++++++++-------- 7 files changed, 100 insertions(+), 81 deletions(-) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 93fa059..9aa5f59 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -33,7 +33,7 @@ export default defineConfig({ { text: "Examples", link: "/examples/" }, { text: "Overlay Testing", link: "/overlay/" }, { - text: "v1.1.8", + text: "v1.1.9", items: [{ text: "Changelog", link: "/changelog" }], }, ], diff --git a/docs/changelog.md b/docs/changelog.md index 1759ff0..7da2d0c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,7 +2,12 @@ All notable changes to this project will be documented in this file. -## [1.1.8] - Current +## [1.1.9] - Current + +### Fixed +- **OCI URL replacement with user-provided `dynamic-plugins.yaml`**: When a workspace provides its own `dynamic-plugins.yaml`, plugin package paths were not replaced with OCI URLs for PR builds. Extracted shared `replaceWithOCIUrls()` function so both `generateDynamicPluginsConfigFromMetadata()` and `loadAndInjectPluginMetadata()` code paths now perform OCI replacement when `GIT_PR_NUMBER` is set. + +## [1.1.8] ### Fixed - Fixed namespace deletion race condition during test retries diff --git a/docs/overlay/examples/basic-plugin.md b/docs/overlay/examples/basic-plugin.md index 0bdc8dc..8d143de 100644 --- a/docs/overlay/examples/basic-plugin.md +++ b/docs/overlay/examples/basic-plugin.md @@ -67,7 +67,7 @@ workspaces//e2e-tests/ "eslint-plugin-check-file": "^3.3.1", "eslint-plugin-playwright": "^2.4.0", "prettier": "^3.7.4", - "rhdh-e2e-test-utils": "1.1.8", + "rhdh-e2e-test-utils": "1.1.9", "typescript": "^5.9.3", "typescript-eslint": "^8.50.0" } diff --git a/docs/overlay/examples/tech-radar.md b/docs/overlay/examples/tech-radar.md index ac05d9f..6a7bf02 100644 --- a/docs/overlay/examples/tech-radar.md +++ b/docs/overlay/examples/tech-radar.md @@ -70,7 +70,7 @@ workspaces/tech-radar/e2e-tests/ "eslint-plugin-check-file": "^3.3.1", "eslint-plugin-playwright": "^2.4.0", "prettier": "^3.7.4", - "rhdh-e2e-test-utils": "1.1.8", + "rhdh-e2e-test-utils": "1.1.9", "typescript": "^5.9.3", "typescript-eslint": "^8.50.0" } diff --git a/docs/overlay/test-structure/directory-layout.md b/docs/overlay/test-structure/directory-layout.md index 8a071d7..a994dbb 100644 --- a/docs/overlay/test-structure/directory-layout.md +++ b/docs/overlay/test-structure/directory-layout.md @@ -67,7 +67,7 @@ Defines the test package with dependencies and scripts: "eslint-plugin-check-file": "^3.3.1", "eslint-plugin-playwright": "^2.4.0", "prettier": "^3.7.4", - "rhdh-e2e-test-utils": "1.1.8", + "rhdh-e2e-test-utils": "1.1.9", "typescript": "^5.9.3", "typescript-eslint": "^8.50.0" } diff --git a/package.json b/package.json index 1979c4b..b8cc6b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rhdh-e2e-test-utils", - "version": "1.1.8", + "version": "1.1.9", "description": "Test utilities for RHDH E2E tests", "license": "Apache-2.0", "type": "module", diff --git a/src/utils/plugin-metadata.ts b/src/utils/plugin-metadata.ts index d399ec4..18fb3dd 100644 --- a/src/utils/plugin-metadata.ts +++ b/src/utils/plugin-metadata.ts @@ -231,34 +231,34 @@ export function getMetadataDirectory( */ export async function parseMetadataFile( filePath: string, -): Promise { - try { - const content = await fs.readFile(filePath, "utf8"); - const parsed = yaml.load(content) as PackageCRD; +): Promise { + const content = await fs.readFile(filePath, "utf8"); + const parsed = yaml.load(content) as PackageCRD; - const packagePath = parsed?.spec?.dynamicArtifact; - const packageName = parsed?.spec?.packageName; - const pluginConfig = parsed?.spec?.appConfigExamples?.[0]?.content; + const packagePath = parsed?.spec?.dynamicArtifact; + const packageName = parsed?.spec?.packageName; + const pluginConfig = parsed?.spec?.appConfigExamples?.[0]?.content; - if (!packagePath) { - console.log( - `[PluginMetadata] Skipping ${filePath}: no spec.dynamicArtifact`, - ); - return null; - } - - console.log(`[PluginMetadata] Loaded metadata for: ${packagePath}`); + if (!packagePath) { + throw new Error( + `[PluginMetadata] Missing required field spec.dynamicArtifact in ${filePath}`, + ); + } - return { - packagePath, - pluginConfig: pluginConfig || {}, - packageName: packageName || "", - sourceFile: filePath, - }; - } catch (error) { - console.error(`[PluginMetadata] Error parsing ${filePath}:`, error); - return null; + if (!packageName) { + throw new Error( + `[PluginMetadata] Missing required field spec.packageName in ${filePath}`, + ); } + + console.log(`[PluginMetadata] Loaded metadata for: ${packagePath}`); + + return { + packagePath, + pluginConfig: pluginConfig || {}, + packageName, + sourceFile: filePath, + }; } /** @@ -282,14 +282,11 @@ export async function parseAllMetadataFiles( for (const file of files) { const metadata = await parseMetadataFile(file); - if (metadata) { - // Use extracted plugin name as key for flexible matching - const pluginName = extractPluginName(metadata.packagePath); - metadataMap.set(pluginName, metadata); - console.log( - `[PluginMetadata] Mapped plugin: ${pluginName} <- ${metadata.packagePath}`, - ); - } + const pluginName = extractPluginName(metadata.packagePath); + metadataMap.set(pluginName, metadata); + console.log( + `[PluginMetadata] Mapped plugin: ${pluginName} <- ${metadata.packagePath}`, + ); } console.log( @@ -318,6 +315,48 @@ export interface DynamicPluginsConfig { [key: string]: unknown; } +/** + * Replaces local package paths with OCI URLs for plugins that have matching metadata. + * Only applies to plugins with metadata (workspace plugins). Plugins without metadata + * (e.g., keycloak, bulk-import from auth defaults) keep their original paths. + * + * @param plugins The plugin entries to process + * @param metadataMap Map of plugin names to plugin metadata + * @param metadataPath Path to the metadata directory (used to resolve workspace root) + * @returns Plugin entries with OCI URLs replaced where applicable + */ +async function replaceWithOCIUrls( + plugins: PluginEntry[], + metadataMap: Map, + metadataPath: string, +): Promise { + const prNumber = process.env.GIT_PR_NUMBER; + if (!prNumber) { + return plugins; + } + + console.log( + `[PluginMetadata] PR build detected (PR #${prNumber}), fetching OCI URLs...`, + ); + const workspacePath = path.resolve(metadataPath, ".."); + const ociUrls = await getOCIUrlsForPR(workspacePath, prNumber); + + return plugins.map((plugin) => { + const pluginName = extractPluginName(plugin.package); + const metadata = metadataMap.get(pluginName); + if (!metadata?.packageName) return plugin; + + const displayName = metadata.packageName + .replace(/^@/, "") + .replace(/\//g, "-"); + const ociUrl = ociUrls.get(displayName); + if (!ociUrl) return plugin; + + console.log(`[PluginMetadata] Replacing ${plugin.package} with ${ociUrl}`); + return { ...plugin, package: ociUrl }; + }); +} + /** * Injects plugin configurations from metadata into a dynamic plugins config. * Metadata config serves as the base, user-provided pluginConfig overrides it. @@ -417,60 +456,24 @@ export async function generateDynamicPluginsConfigFromMetadata( ); } - // If PR number is set, fetch OCI URLs - const prNumber = process.env.GIT_PR_NUMBER; - let ociUrls: Map | null = null; - if (prNumber) { - console.log( - `[PluginMetadata] PR build detected (PR #${prNumber}), fetching OCI URLs...`, - ); - const workspacePath = path.resolve(metadataPath, ".."); - ociUrls = await getOCIUrlsForPR(workspacePath, prNumber); - } - // Build plugin entries from metadata - const plugins: PluginEntry[] = []; + let plugins: PluginEntry[] = []; for (const [pluginName, metadata] of metadataMap) { - let packageRef = metadata.packagePath; - - // Replace with OCI URL if available (required for PR builds) - if (ociUrls) { - if (!metadata.packageName) { - throw new Error( - `[PluginMetadata] PR build requires packageName in metadata but not found for: ${pluginName}\n` + - ` Source file: ${metadata.sourceFile}`, - ); - } - - const displayName = metadata.packageName - .replace(/^@/, "") - .replace(/\//g, "-"); - const ociUrl = ociUrls.get(displayName); - - if (!ociUrl) { - throw new Error( - `[PluginMetadata] PR build requires OCI URL but not found for: ${displayName}\n` + - ` Package name: ${metadata.packageName}\n` + - ` Source file: ${metadata.sourceFile}`, - ); - } - - console.log(`[PluginMetadata] Replacing ${packageRef} with ${ociUrl}`); - packageRef = ociUrl; - } - console.log( - `[PluginMetadata] Adding plugin: ${pluginName} (${packageRef})`, + `[PluginMetadata] Adding plugin: ${pluginName} (${metadata.packagePath})`, ); plugins.push({ - package: packageRef, + package: metadata.packagePath, disabled: false, pluginConfig: metadata.pluginConfig, }); } + // Replace local paths with OCI URLs for PR builds + plugins = await replaceWithOCIUrls(plugins, metadataMap, metadataPath); + console.log( `[PluginMetadata] Generated dynamic-plugins config with ${plugins.length} plugins`, ); @@ -517,5 +520,16 @@ export async function loadAndInjectPluginMetadata( } // Inject metadata configs into the dynamic plugins config - return injectMetadataConfig(dynamicPluginsConfig, metadataMap); + const result = injectMetadataConfig(dynamicPluginsConfig, metadataMap); + + // Replace local paths with OCI URLs for PR builds + if (result.plugins) { + result.plugins = await replaceWithOCIUrls( + result.plugins, + metadataMap, + metadataPath, + ); + } + + return result; } From c3ddf89ae1d017e094e572f1426e3d927e27ed4c Mon Sep 17 00:00:00 2001 From: Subhash Khileri Date: Wed, 11 Feb 2026 23:18:59 +0530 Subject: [PATCH 2/2] fix: add OCI URL replacement for user-provided dynamic-plugins config --- src/utils/plugin-metadata.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/plugin-metadata.ts b/src/utils/plugin-metadata.ts index 18fb3dd..6ebad98 100644 --- a/src/utils/plugin-metadata.ts +++ b/src/utils/plugin-metadata.ts @@ -251,8 +251,6 @@ export async function parseMetadataFile( ); } - console.log(`[PluginMetadata] Loaded metadata for: ${packagePath}`); - return { packagePath, pluginConfig: pluginConfig || {},