@@ -231,34 +231,34 @@ export function getMetadataDirectory(
231231 */
232232export 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+ console . log ( `[PluginMetadata] Loaded metadata for: ${ packagePath } ` ) ;
255+
256+ return {
257+ packagePath,
258+ pluginConfig : pluginConfig || { } ,
259+ packageName,
260+ sourceFile : filePath ,
261+ } ;
262262}
263263
264264/**
@@ -282,14 +282,11 @@ export async function parseAllMetadataFiles(
282282
283283 for ( const file of files ) {
284284 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- }
285+ const pluginName = extractPluginName ( metadata . packagePath ) ;
286+ metadataMap . set ( pluginName , metadata ) ;
287+ console . log (
288+ `[PluginMetadata] Mapped plugin: ${ pluginName } <- ${ metadata . packagePath } ` ,
289+ ) ;
293290 }
294291
295292 console . log (
@@ -318,6 +315,48 @@ export interface DynamicPluginsConfig {
318315 [ key : string ] : unknown ;
319316}
320317
318+ /**
319+ * Replaces local package paths with OCI URLs for plugins that have matching metadata.
320+ * Only applies to plugins with metadata (workspace plugins). Plugins without metadata
321+ * (e.g., keycloak, bulk-import from auth defaults) keep their original paths.
322+ *
323+ * @param plugins The plugin entries to process
324+ * @param metadataMap Map of plugin names to plugin metadata
325+ * @param metadataPath Path to the metadata directory (used to resolve workspace root)
326+ * @returns Plugin entries with OCI URLs replaced where applicable
327+ */
328+ async function replaceWithOCIUrls (
329+ plugins : PluginEntry [ ] ,
330+ metadataMap : Map < string , PluginMetadata > ,
331+ metadataPath : string ,
332+ ) : Promise < PluginEntry [ ] > {
333+ const prNumber = process . env . GIT_PR_NUMBER ;
334+ if ( ! prNumber ) {
335+ return plugins ;
336+ }
337+
338+ console . log (
339+ `[PluginMetadata] PR build detected (PR #${ prNumber } ), fetching OCI URLs...` ,
340+ ) ;
341+ const workspacePath = path . resolve ( metadataPath , ".." ) ;
342+ const ociUrls = await getOCIUrlsForPR ( workspacePath , prNumber ) ;
343+
344+ return plugins . map ( ( plugin ) => {
345+ const pluginName = extractPluginName ( plugin . package ) ;
346+ const metadata = metadataMap . get ( pluginName ) ;
347+ if ( ! metadata ?. packageName ) return plugin ;
348+
349+ const displayName = metadata . packageName
350+ . replace ( / ^ @ / , "" )
351+ . replace ( / \/ / g, "-" ) ;
352+ const ociUrl = ociUrls . get ( displayName ) ;
353+ if ( ! ociUrl ) return plugin ;
354+
355+ console . log ( `[PluginMetadata] Replacing ${ plugin . package } with ${ ociUrl } ` ) ;
356+ return { ...plugin , package : ociUrl } ;
357+ } ) ;
358+ }
359+
321360/**
322361 * Injects plugin configurations from metadata into a dynamic plugins config.
323362 * Metadata config serves as the base, user-provided pluginConfig overrides it.
@@ -417,60 +456,24 @@ export async function generateDynamicPluginsConfigFromMetadata(
417456 ) ;
418457 }
419458
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-
431459 // Build plugin entries from metadata
432- const plugins : PluginEntry [ ] = [ ] ;
460+ let plugins : PluginEntry [ ] = [ ] ;
433461
434462 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-
463463 console . log (
464- `[PluginMetadata] Adding plugin: ${ pluginName } (${ packageRef } )` ,
464+ `[PluginMetadata] Adding plugin: ${ pluginName } (${ metadata . packagePath } )` ,
465465 ) ;
466466
467467 plugins . push ( {
468- package : packageRef ,
468+ package : metadata . packagePath ,
469469 disabled : false ,
470470 pluginConfig : metadata . pluginConfig ,
471471 } ) ;
472472 }
473473
474+ // Replace local paths with OCI URLs for PR builds
475+ plugins = await replaceWithOCIUrls ( plugins , metadataMap , metadataPath ) ;
476+
474477 console . log (
475478 `[PluginMetadata] Generated dynamic-plugins config with ${ plugins . length } plugins` ,
476479 ) ;
@@ -517,5 +520,16 @@ export async function loadAndInjectPluginMetadata(
517520 }
518521
519522 // Inject metadata configs into the dynamic plugins config
520- return injectMetadataConfig ( dynamicPluginsConfig , metadataMap ) ;
523+ const result = injectMetadataConfig ( dynamicPluginsConfig , metadataMap ) ;
524+
525+ // Replace local paths with OCI URLs for PR builds
526+ if ( result . plugins ) {
527+ result . plugins = await replaceWithOCIUrls (
528+ result . plugins ,
529+ metadataMap ,
530+ metadataPath ,
531+ ) ;
532+ }
533+
534+ return result ;
521535}
0 commit comments