@@ -432,4 +432,154 @@ public async Task CreateChangelog_WithPrOptionAndAreaMapping_MapsLabelsToAreas()
432432 yamlContent . Should ( ) . Contain ( "- security" ) ;
433433 yamlContent . Should ( ) . Contain ( "- search" ) ;
434434 }
435+
436+ [ Fact ]
437+ public void MapLabelsToAreas_WithAreaNameContainingCommas_PresservesFullName ( )
438+ {
439+ // Arrange
440+ var labelToAreas = new Dictionary < string , IReadOnlyList < string > > ( StringComparer . OrdinalIgnoreCase )
441+ {
442+ [ "Team:Alerting Services" ] = [ "Alerting, connectors, and reporting" ] ,
443+ [ "Team:Search" ] = [ "Search" ]
444+ } ;
445+
446+ // Act
447+ var result = PrInfoProcessor . MapLabelsToAreas (
448+ [ "Team:Alerting Services" , "Team:Search" ] ,
449+ labelToAreas
450+ ) ;
451+
452+ // Assert
453+ result . Should ( ) . HaveCount ( 2 ) ;
454+ result . Should ( ) . Contain ( "Alerting, connectors, and reporting" ) ; // Not split
455+ result . Should ( ) . Contain ( "Search" ) ;
456+ }
457+
458+ [ Fact ]
459+ public async Task CreateChangelog_WithAreaNameContainingCommas_PreservesAreaName ( )
460+ {
461+ // Arrange: Area name contains commas
462+ var prInfo = new GitHubPrInfo
463+ {
464+ Title = "Fix alerting issues" ,
465+ Labels = [ "type:bug" , "Team:Alerting Services" ]
466+ } ;
467+
468+ A . CallTo ( ( ) => MockGitHubService . FetchPrInfoAsync (
469+ A < string > . _ ,
470+ A < string ? > . _ ,
471+ A < string ? > . _ ,
472+ A < CancellationToken > . _ ) )
473+ . Returns ( prInfo ) ;
474+
475+ // language=yaml
476+ var configContent =
477+ """
478+ pivot:
479+ types:
480+ bug-fix: "type:bug"
481+ feature:
482+ breaking-change:
483+ areas:
484+ "Alerting, connectors, and reporting":
485+ - "Team:Alerting Services"
486+ lifecycles:
487+ - preview
488+ - beta
489+ - ga
490+ """ ;
491+ var configPath = await CreateConfigDirectory ( configContent ) ;
492+
493+ var service = CreateService ( ) ;
494+
495+ var input = new CreateChangelogArguments
496+ {
497+ Prs = [ "https://github.com/elastic/elasticsearch/pull/12345" ] ,
498+ Products = [ new ProductArgument { Product = "elasticsearch" , Target = "9.2.0" } ] ,
499+ Config = configPath ,
500+ Output = CreateOutputDirectory ( )
501+ } ;
502+
503+ // Act
504+ var result = await service . CreateChangelog ( Collector , input , TestContext . Current . CancellationToken ) ;
505+
506+ // Assert
507+ if ( ! result )
508+ {
509+ foreach ( var diagnostic in Collector . Diagnostics )
510+ Output . WriteLine ( $ "{ diagnostic . Severity } : { diagnostic . Message } ") ;
511+ }
512+
513+ result . Should ( ) . BeTrue ( ) ;
514+ Collector . Errors . Should ( ) . Be ( 0 ) ;
515+
516+ var outputDir = input . Output ?? FileSystem . Directory . GetCurrentDirectory ( ) ;
517+ if ( ! FileSystem . Directory . Exists ( outputDir ) )
518+ FileSystem . Directory . CreateDirectory ( outputDir ) ;
519+ var files = FileSystem . Directory . GetFiles ( outputDir , "*.yaml" ) ;
520+ var yamlContent = await FileSystem . File . ReadAllTextAsync ( files [ 0 ] , TestContext . Current . CancellationToken ) ;
521+ yamlContent . Should ( ) . Contain ( "- Alerting, connectors, and reporting" ) ; // Full name, not split
522+ }
523+
524+ [ Fact ]
525+ public async Task CreateChangelog_WithOneLabelMappedToMultipleAreas_AddsAllAreas ( )
526+ {
527+ // Arrange: Same label under multiple areas
528+ var prInfo = new GitHubPrInfo
529+ {
530+ Title = "Cross-area change" ,
531+ Labels = [ "type:enhancement" , "Team:Search" ]
532+ } ;
533+
534+ A . CallTo ( ( ) => MockGitHubService . FetchPrInfoAsync (
535+ A < string > . _ ,
536+ A < string ? > . _ ,
537+ A < string ? > . _ ,
538+ A < CancellationToken > . _ ) )
539+ . Returns ( prInfo ) ;
540+
541+ // language=yaml
542+ var configContent =
543+ """
544+ pivot:
545+ types:
546+ enhancement: "type:enhancement"
547+ feature:
548+ bug-fix:
549+ breaking-change:
550+ areas:
551+ "Search":
552+ - "Team:Search"
553+ "Observability":
554+ - "Team:Search"
555+ lifecycles:
556+ - ga
557+ """ ;
558+ var configPath = await CreateConfigDirectory ( configContent ) ;
559+
560+ var service = CreateService ( ) ;
561+
562+ var input = new CreateChangelogArguments
563+ {
564+ Prs = [ "https://github.com/elastic/elasticsearch/pull/12345" ] ,
565+ Products = [ new ProductArgument { Product = "elasticsearch" } ] ,
566+ Config = configPath ,
567+ Output = CreateOutputDirectory ( )
568+ } ;
569+
570+ // Act
571+ var result = await service . CreateChangelog ( Collector , input , TestContext . Current . CancellationToken ) ;
572+
573+ // Assert
574+ result . Should ( ) . BeTrue ( ) ;
575+ Collector . Errors . Should ( ) . Be ( 0 ) ;
576+
577+ var outputDir = input . Output ;
578+ if ( ! FileSystem . Directory . Exists ( outputDir ) )
579+ FileSystem . Directory . CreateDirectory ( outputDir ) ;
580+ var files = FileSystem . Directory . GetFiles ( outputDir , "*.yaml" ) ;
581+ var yamlContent = await FileSystem . File . ReadAllTextAsync ( files [ 0 ] , TestContext . Current . CancellationToken ) ;
582+ yamlContent . Should ( ) . Contain ( "- Search" ) ;
583+ yamlContent . Should ( ) . Contain ( "- Observability" ) ;
584+ }
435585}
0 commit comments