@@ -800,3 +800,331 @@ def test_ticket_key_without_hash_prefix(self, test_config):
800800 assert note .url == note .ticket_url
801801 assert note .short_link == "#8624"
802802 assert note .short_repo_link == "sequentech/meta#8624"
803+
804+
805+ class TestDescriptionAndMigrationExtraction :
806+ """Tests for extracting description and migration notes from ticket bodies."""
807+
808+ def test_extract_description_section (self , test_config ):
809+ """Test extraction of Description section from ticket body."""
810+ ticket_body = """## Description
811+ This is the description text.
812+ It can span multiple lines.
813+
814+ ## Other Section
815+ Something else here."""
816+
817+ ticket = Ticket (
818+ repo_id = 1 ,
819+ number = 123 ,
820+ key = "123" ,
821+ title = "Test ticket" ,
822+ state = "closed" ,
823+ body = ticket_body ,
824+ url = "https://github.com/test/repo/issues/123"
825+ )
826+
827+ change = ConsolidatedChange (
828+ type = "ticket" ,
829+ ticket_key = "123" ,
830+ prs = [],
831+ commits = []
832+ )
833+
834+ generator = ReleaseNoteGenerator (test_config )
835+ note = generator .create_release_note (change , ticket )
836+
837+ assert note .description is not None
838+ assert "This is the description text" in note .description
839+ assert "It can span multiple lines" in note .description
840+ assert "Other Section" not in note .description
841+
842+ def test_extract_summary_section (self , test_config ):
843+ """Test extraction of Summary section (alternative to Description)."""
844+ ticket_body = """## Summary
845+ This is a summary of the changes.
846+
847+ ## Details
848+ More information here."""
849+
850+ ticket = Ticket (
851+ repo_id = 1 ,
852+ number = 124 ,
853+ key = "124" ,
854+ title = "Test ticket" ,
855+ state = "closed" ,
856+ body = ticket_body ,
857+ url = "https://github.com/test/repo/issues/124"
858+ )
859+
860+ change = ConsolidatedChange (
861+ type = "ticket" ,
862+ ticket_key = "124" ,
863+ prs = [],
864+ commits = []
865+ )
866+
867+ generator = ReleaseNoteGenerator (test_config )
868+ note = generator .create_release_note (change , ticket )
869+
870+ assert note .description is not None
871+ assert "This is a summary of the changes" in note .description
872+ assert "Details" not in note .description
873+
874+ def test_extract_migration_notes_section (self , test_config ):
875+ """Test extraction of Migration section from ticket body."""
876+ ticket_body = """## Description
877+ Some description.
878+
879+ ## Migration
880+ Run the following command:
881+ ```
882+ python manage.py migrate
883+ ```
884+
885+ ## Other Section
886+ Something else."""
887+
888+ ticket = Ticket (
889+ repo_id = 1 ,
890+ number = 125 ,
891+ key = "125" ,
892+ title = "Test ticket" ,
893+ state = "closed" ,
894+ body = ticket_body ,
895+ url = "https://github.com/test/repo/issues/125"
896+ )
897+
898+ change = ConsolidatedChange (
899+ type = "ticket" ,
900+ ticket_key = "125" ,
901+ prs = [],
902+ commits = []
903+ )
904+
905+ generator = ReleaseNoteGenerator (test_config )
906+ note = generator .create_release_note (change , ticket )
907+
908+ assert note .migration_notes is not None
909+ assert "Run the following command" in note .migration_notes
910+ assert "python manage.py migrate" in note .migration_notes
911+ assert "Other Section" not in note .migration_notes
912+
913+ def test_extract_migration_notes_alternative_heading (self , test_config ):
914+ """Test extraction of Migration Notes section (alternative heading)."""
915+ ticket_body = """## Description
916+ Some description.
917+
918+ ## Migration Notes
919+ Database schema changes required:
920+ - Add new column
921+ - Update indexes
922+
923+ ## Testing
924+ Test steps."""
925+
926+ ticket = Ticket (
927+ repo_id = 1 ,
928+ number = 126 ,
929+ key = "126" ,
930+ title = "Test ticket" ,
931+ state = "closed" ,
932+ body = ticket_body ,
933+ url = "https://github.com/test/repo/issues/126"
934+ )
935+
936+ change = ConsolidatedChange (
937+ type = "ticket" ,
938+ ticket_key = "126" ,
939+ prs = [],
940+ commits = []
941+ )
942+
943+ generator = ReleaseNoteGenerator (test_config )
944+ note = generator .create_release_note (change , ticket )
945+
946+ assert note .migration_notes is not None
947+ assert "Database schema changes required" in note .migration_notes
948+ assert "Add new column" in note .migration_notes
949+ assert "Testing" not in note .migration_notes
950+
951+ def test_no_description_section (self , test_config ):
952+ """Test ticket without Description section returns None."""
953+ ticket_body = """## Other Section
954+ Some content.
955+
956+ ## Another Section
957+ More content."""
958+
959+ ticket = Ticket (
960+ repo_id = 1 ,
961+ number = 127 ,
962+ key = "127" ,
963+ title = "Test ticket" ,
964+ state = "closed" ,
965+ body = ticket_body ,
966+ url = "https://github.com/test/repo/issues/127"
967+ )
968+
969+ change = ConsolidatedChange (
970+ type = "ticket" ,
971+ ticket_key = "127" ,
972+ prs = [],
973+ commits = []
974+ )
975+
976+ generator = ReleaseNoteGenerator (test_config )
977+ note = generator .create_release_note (change , ticket )
978+
979+ assert note .description is None
980+
981+ def test_no_migration_section (self , test_config ):
982+ """Test ticket without Migration section returns None."""
983+ ticket_body = """## Description
984+ Some description.
985+
986+ ## Other Section
987+ Some content."""
988+
989+ ticket = Ticket (
990+ repo_id = 1 ,
991+ number = 128 ,
992+ key = "128" ,
993+ title = "Test ticket" ,
994+ state = "closed" ,
995+ body = ticket_body ,
996+ url = "https://github.com/test/repo/issues/128"
997+ )
998+
999+ change = ConsolidatedChange (
1000+ type = "ticket" ,
1001+ ticket_key = "128" ,
1002+ prs = [],
1003+ commits = []
1004+ )
1005+
1006+ generator = ReleaseNoteGenerator (test_config )
1007+ note = generator .create_release_note (change , ticket )
1008+
1009+ assert note .migration_notes is None
1010+
1011+ def test_case_insensitive_section_matching (self , test_config ):
1012+ """Test that section matching is case-insensitive."""
1013+ ticket_body = """## description
1014+ Lowercase description heading.
1015+
1016+ ## MIGRATION
1017+ Uppercase migration heading."""
1018+
1019+ ticket = Ticket (
1020+ repo_id = 1 ,
1021+ number = 129 ,
1022+ key = "129" ,
1023+ title = "Test ticket" ,
1024+ state = "closed" ,
1025+ body = ticket_body ,
1026+ url = "https://github.com/test/repo/issues/129"
1027+ )
1028+
1029+ change = ConsolidatedChange (
1030+ type = "ticket" ,
1031+ ticket_key = "129" ,
1032+ prs = [],
1033+ commits = []
1034+ )
1035+
1036+ generator = ReleaseNoteGenerator (test_config )
1037+ note = generator .create_release_note (change , ticket )
1038+
1039+ assert note .description is not None
1040+ assert "Lowercase description heading" in note .description
1041+ assert note .migration_notes is not None
1042+ assert "Uppercase migration heading" in note .migration_notes
1043+
1044+ def test_extract_both_description_and_migration (self , test_config ):
1045+ """Test extracting both description and migration notes from same ticket."""
1046+ ticket_body = """## Description
1047+ This feature adds new functionality.
1048+
1049+ ## Migration
1050+ Run: python manage.py migrate
1051+
1052+ ## Testing
1053+ Test instructions."""
1054+
1055+ ticket = Ticket (
1056+ repo_id = 1 ,
1057+ number = 130 ,
1058+ key = "130" ,
1059+ title = "Test ticket" ,
1060+ state = "closed" ,
1061+ body = ticket_body ,
1062+ url = "https://github.com/test/repo/issues/130"
1063+ )
1064+
1065+ change = ConsolidatedChange (
1066+ type = "ticket" ,
1067+ ticket_key = "130" ,
1068+ prs = [],
1069+ commits = []
1070+ )
1071+
1072+ generator = ReleaseNoteGenerator (test_config )
1073+ note = generator .create_release_note (change , ticket )
1074+
1075+ assert note .description is not None
1076+ assert "This feature adds new functionality" in note .description
1077+ assert note .migration_notes is not None
1078+ assert "Run: python manage.py migrate" in note .migration_notes
1079+ assert "Testing" not in note .description
1080+ assert "Testing" not in note .migration_notes
1081+
1082+ def test_empty_ticket_body (self , test_config ):
1083+ """Test ticket with empty body."""
1084+ ticket = Ticket (
1085+ repo_id = 1 ,
1086+ number = 131 ,
1087+ key = "131" ,
1088+ title = "Test ticket" ,
1089+ state = "closed" ,
1090+ body = "" ,
1091+ url = "https://github.com/test/repo/issues/131"
1092+ )
1093+
1094+ change = ConsolidatedChange (
1095+ type = "ticket" ,
1096+ ticket_key = "131" ,
1097+ prs = [],
1098+ commits = []
1099+ )
1100+
1101+ generator = ReleaseNoteGenerator (test_config )
1102+ note = generator .create_release_note (change , ticket )
1103+
1104+ assert note .description is None
1105+ assert note .migration_notes is None
1106+
1107+ def test_none_ticket_body (self , test_config ):
1108+ """Test ticket with None body."""
1109+ ticket = Ticket (
1110+ repo_id = 1 ,
1111+ number = 132 ,
1112+ key = "132" ,
1113+ title = "Test ticket" ,
1114+ state = "closed" ,
1115+ body = None ,
1116+ url = "https://github.com/test/repo/issues/132"
1117+ )
1118+
1119+ change = ConsolidatedChange (
1120+ type = "ticket" ,
1121+ ticket_key = "132" ,
1122+ prs = [],
1123+ commits = []
1124+ )
1125+
1126+ generator = ReleaseNoteGenerator (test_config )
1127+ note = generator .create_release_note (change , ticket )
1128+
1129+ assert note .description is None
1130+ assert note .migration_notes is None
0 commit comments