Skip to content

Commit b60ade2

Browse files
fix: add OCI URL replacement for user-provided dynamic-plugins config (#36)
* fix: add OCI URL replacement for user-provided dynamic-plugins config * fix: add OCI URL replacement for user-provided dynamic-plugins config
1 parent 37eb4db commit b60ade2

File tree

7 files changed

+98
-81
lines changed

7 files changed

+98
-81
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default defineConfig({
3333
{ text: "Examples", link: "/examples/" },
3434
{ text: "Overlay Testing", link: "/overlay/" },
3535
{
36-
text: "v1.1.8",
36+
text: "v1.1.9",
3737
items: [{ text: "Changelog", link: "/changelog" }],
3838
},
3939
],

docs/changelog.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## [1.1.8] - Current
5+
## [1.1.9] - Current
6+
7+
### Fixed
8+
- **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.
9+
10+
## [1.1.8]
611

712
### Fixed
813
- Fixed namespace deletion race condition during test retries

docs/overlay/examples/basic-plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ workspaces/<plugin>/e2e-tests/
6767
"eslint-plugin-check-file": "^3.3.1",
6868
"eslint-plugin-playwright": "^2.4.0",
6969
"prettier": "^3.7.4",
70-
"rhdh-e2e-test-utils": "1.1.8",
70+
"rhdh-e2e-test-utils": "1.1.9",
7171
"typescript": "^5.9.3",
7272
"typescript-eslint": "^8.50.0"
7373
}

docs/overlay/examples/tech-radar.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ workspaces/tech-radar/e2e-tests/
7070
"eslint-plugin-check-file": "^3.3.1",
7171
"eslint-plugin-playwright": "^2.4.0",
7272
"prettier": "^3.7.4",
73-
"rhdh-e2e-test-utils": "1.1.8",
73+
"rhdh-e2e-test-utils": "1.1.9",
7474
"typescript": "^5.9.3",
7575
"typescript-eslint": "^8.50.0"
7676
}

docs/overlay/test-structure/directory-layout.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Defines the test package with dependencies and scripts:
6767
"eslint-plugin-check-file": "^3.3.1",
6868
"eslint-plugin-playwright": "^2.4.0",
6969
"prettier": "^3.7.4",
70-
"rhdh-e2e-test-utils": "1.1.8",
70+
"rhdh-e2e-test-utils": "1.1.9",
7171
"typescript": "^5.9.3",
7272
"typescript-eslint": "^8.50.0"
7373
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rhdh-e2e-test-utils",
3-
"version": "1.1.8",
3+
"version": "1.1.9",
44
"description": "Test utilities for RHDH E2E tests",
55
"license": "Apache-2.0",
66
"type": "module",

src/utils/plugin-metadata.ts

Lines changed: 87 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -231,34 +231,32 @@ export function getMetadataDirectory(
231231
*/
232232
export async function parseMetadataFile(
233233
filePath: string,
234-
): Promise<PluginMetadata | null> {
235-
try {
236-
const content = await fs.readFile(filePath, "utf8");
237-
const parsed = yaml.load(content) as PackageCRD;
234+
): Promise<PluginMetadata> {
235+
const content = await fs.readFile(filePath, "utf8");
236+
const parsed = yaml.load(content) as PackageCRD;
238237

239-
const packagePath = parsed?.spec?.dynamicArtifact;
240-
const packageName = parsed?.spec?.packageName;
241-
const pluginConfig = parsed?.spec?.appConfigExamples?.[0]?.content;
238+
const packagePath = parsed?.spec?.dynamicArtifact;
239+
const packageName = parsed?.spec?.packageName;
240+
const pluginConfig = parsed?.spec?.appConfigExamples?.[0]?.content;
242241

243-
if (!packagePath) {
244-
console.log(
245-
`[PluginMetadata] Skipping ${filePath}: no spec.dynamicArtifact`,
246-
);
247-
return null;
248-
}
249-
250-
console.log(`[PluginMetadata] Loaded metadata for: ${packagePath}`);
242+
if (!packagePath) {
243+
throw new Error(
244+
`[PluginMetadata] Missing required field spec.dynamicArtifact in ${filePath}`,
245+
);
246+
}
251247

252-
return {
253-
packagePath,
254-
pluginConfig: pluginConfig || {},
255-
packageName: packageName || "",
256-
sourceFile: filePath,
257-
};
258-
} catch (error) {
259-
console.error(`[PluginMetadata] Error parsing ${filePath}:`, error);
260-
return null;
248+
if (!packageName) {
249+
throw new Error(
250+
`[PluginMetadata] Missing required field spec.packageName in ${filePath}`,
251+
);
261252
}
253+
254+
return {
255+
packagePath,
256+
pluginConfig: pluginConfig || {},
257+
packageName,
258+
sourceFile: filePath,
259+
};
262260
}
263261

264262
/**
@@ -282,14 +280,11 @@ export async function parseAllMetadataFiles(
282280

283281
for (const file of files) {
284282
const metadata = await parseMetadataFile(file);
285-
if (metadata) {
286-
// Use extracted plugin name as key for flexible matching
287-
const pluginName = extractPluginName(metadata.packagePath);
288-
metadataMap.set(pluginName, metadata);
289-
console.log(
290-
`[PluginMetadata] Mapped plugin: ${pluginName} <- ${metadata.packagePath}`,
291-
);
292-
}
283+
const pluginName = extractPluginName(metadata.packagePath);
284+
metadataMap.set(pluginName, metadata);
285+
console.log(
286+
`[PluginMetadata] Mapped plugin: ${pluginName} <- ${metadata.packagePath}`,
287+
);
293288
}
294289

295290
console.log(
@@ -318,6 +313,48 @@ export interface DynamicPluginsConfig {
318313
[key: string]: unknown;
319314
}
320315

316+
/**
317+
* Replaces local package paths with OCI URLs for plugins that have matching metadata.
318+
* Only applies to plugins with metadata (workspace plugins). Plugins without metadata
319+
* (e.g., keycloak, bulk-import from auth defaults) keep their original paths.
320+
*
321+
* @param plugins The plugin entries to process
322+
* @param metadataMap Map of plugin names to plugin metadata
323+
* @param metadataPath Path to the metadata directory (used to resolve workspace root)
324+
* @returns Plugin entries with OCI URLs replaced where applicable
325+
*/
326+
async function replaceWithOCIUrls(
327+
plugins: PluginEntry[],
328+
metadataMap: Map<string, PluginMetadata>,
329+
metadataPath: string,
330+
): Promise<PluginEntry[]> {
331+
const prNumber = process.env.GIT_PR_NUMBER;
332+
if (!prNumber) {
333+
return plugins;
334+
}
335+
336+
console.log(
337+
`[PluginMetadata] PR build detected (PR #${prNumber}), fetching OCI URLs...`,
338+
);
339+
const workspacePath = path.resolve(metadataPath, "..");
340+
const ociUrls = await getOCIUrlsForPR(workspacePath, prNumber);
341+
342+
return plugins.map((plugin) => {
343+
const pluginName = extractPluginName(plugin.package);
344+
const metadata = metadataMap.get(pluginName);
345+
if (!metadata?.packageName) return plugin;
346+
347+
const displayName = metadata.packageName
348+
.replace(/^@/, "")
349+
.replace(/\//g, "-");
350+
const ociUrl = ociUrls.get(displayName);
351+
if (!ociUrl) return plugin;
352+
353+
console.log(`[PluginMetadata] Replacing ${plugin.package} with ${ociUrl}`);
354+
return { ...plugin, package: ociUrl };
355+
});
356+
}
357+
321358
/**
322359
* Injects plugin configurations from metadata into a dynamic plugins config.
323360
* Metadata config serves as the base, user-provided pluginConfig overrides it.
@@ -417,60 +454,24 @@ export async function generateDynamicPluginsConfigFromMetadata(
417454
);
418455
}
419456

420-
// If PR number is set, fetch OCI URLs
421-
const prNumber = process.env.GIT_PR_NUMBER;
422-
let ociUrls: Map<string, string> | null = null;
423-
if (prNumber) {
424-
console.log(
425-
`[PluginMetadata] PR build detected (PR #${prNumber}), fetching OCI URLs...`,
426-
);
427-
const workspacePath = path.resolve(metadataPath, "..");
428-
ociUrls = await getOCIUrlsForPR(workspacePath, prNumber);
429-
}
430-
431457
// Build plugin entries from metadata
432-
const plugins: PluginEntry[] = [];
458+
let plugins: PluginEntry[] = [];
433459

434460
for (const [pluginName, metadata] of metadataMap) {
435-
let packageRef = metadata.packagePath;
436-
437-
// Replace with OCI URL if available (required for PR builds)
438-
if (ociUrls) {
439-
if (!metadata.packageName) {
440-
throw new Error(
441-
`[PluginMetadata] PR build requires packageName in metadata but not found for: ${pluginName}\n` +
442-
` Source file: ${metadata.sourceFile}`,
443-
);
444-
}
445-
446-
const displayName = metadata.packageName
447-
.replace(/^@/, "")
448-
.replace(/\//g, "-");
449-
const ociUrl = ociUrls.get(displayName);
450-
451-
if (!ociUrl) {
452-
throw new Error(
453-
`[PluginMetadata] PR build requires OCI URL but not found for: ${displayName}\n` +
454-
` Package name: ${metadata.packageName}\n` +
455-
` Source file: ${metadata.sourceFile}`,
456-
);
457-
}
458-
459-
console.log(`[PluginMetadata] Replacing ${packageRef} with ${ociUrl}`);
460-
packageRef = ociUrl;
461-
}
462-
463461
console.log(
464-
`[PluginMetadata] Adding plugin: ${pluginName} (${packageRef})`,
462+
`[PluginMetadata] Adding plugin: ${pluginName} (${metadata.packagePath})`,
465463
);
466464

467465
plugins.push({
468-
package: packageRef,
466+
package: metadata.packagePath,
469467
disabled: false,
470468
pluginConfig: metadata.pluginConfig,
471469
});
472470
}
473471

472+
// Replace local paths with OCI URLs for PR builds
473+
plugins = await replaceWithOCIUrls(plugins, metadataMap, metadataPath);
474+
474475
console.log(
475476
`[PluginMetadata] Generated dynamic-plugins config with ${plugins.length} plugins`,
476477
);
@@ -517,5 +518,16 @@ export async function loadAndInjectPluginMetadata(
517518
}
518519

519520
// Inject metadata configs into the dynamic plugins config
520-
return injectMetadataConfig(dynamicPluginsConfig, metadataMap);
521+
const result = injectMetadataConfig(dynamicPluginsConfig, metadataMap);
522+
523+
// Replace local paths with OCI URLs for PR builds
524+
if (result.plugins) {
525+
result.plugins = await replaceWithOCIUrls(
526+
result.plugins,
527+
metadataMap,
528+
metadataPath,
529+
);
530+
}
531+
532+
return result;
521533
}

0 commit comments

Comments
 (0)