@@ -77,39 +77,59 @@ async function getLinkedIssues(prNumber) {
7777
7878// --- Classify title by flexible prefix ---
7979function classifyTitle ( title ) {
80- // remove leading emoji and spaces
81- const cleaned = title . replace ( / ^ [ \s \p{ Emoji_Presentation} \p{ Extended_Pictographic} ] + / u, '' ) ;
80+ // Remove emojis and spaces at start
81+ const cleaned = title . replace ( / ^ [ \s \p{ Emoji_Presentation} \p{ Extended_Pictographic} ] + / u, "" ) ;
82+
83+ // Match [Feat], Feat:, Feat - etc.
8284 const match = cleaned . match ( / ^ \s * (?: \[ ( [ ^ \] ] + ) \] | ( [ ^ \s : ] + ) ) \s * : ? \s * / i) ;
83- const rawPrefix = match ? ( match [ 1 ] || match [ 2 ] ) : null ;
85+ if ( ! match ) return "Other" ;
86+
87+ // If multiple prefixes inside [Feat, Enhancement] — split and take first
88+ let rawPrefix = ( match [ 1 ] || match [ 2 ] ) ?. split ( "," ) [ 0 ] . trim ( ) || null ;
8489 if ( ! rawPrefix ) return "Other" ;
8590
8691 const prefix = rawPrefix . toLowerCase ( ) ;
8792 const map = {
88- " task" : "🚀 Tasks" ,
89- " composite" : "🚀 Tasks" ,
93+ task : "🚀 Tasks" ,
94+ composite : "🚀 Tasks" ,
9095 "ux/ui" : "🔧 Enhancements" ,
91- "enhancement" : "🔧 Enhancements" ,
92- "bug" : "🐞 Bug Fixes" ,
93- "feat" : "✨ New Features" ,
94- "refactor" : "🛠 Refactoring" ,
95- "docs" : "📚 Documentation" ,
96- "test" : "✅ Tests" ,
97- "chore" : "⚙️ Chores" ,
98- "proposal" : "💡 Ideas & Proposals" ,
99- "idea" : "💡 Ideas & Proposals" ,
100- "discussion" : "💡 Ideas & Proposals" ,
96+ enhancement : "🔧 Enhancements" ,
97+ bug : "🐞 Bug Fixes" ,
98+ feat : "✨ New Features" ,
99+ feature : "✨ New Features" ,
100+ refactor : "🛠 Refactoring" ,
101+ docs : "📚 Documentation" ,
102+ doc : "📚 Documentation" ,
103+ test : "✅ Tests" ,
104+ chore : "⚙️ Chores" ,
105+ proposal : "💡 Ideas & Proposals" ,
106+ idea : "💡 Ideas & Proposals" ,
107+ discussion : "💡 Ideas & Proposals" ,
101108 } ;
102109
103110 return map [ prefix ] || "Other" ;
104111}
105112
113+ // --- Normalize prefix style in titles ---
114+ function normalizeTitlePrefixes ( title ) {
115+ return title . replace ( / ^ \s * (?: \[ ( [ ^ \] ] + ) \] | ( [ ^ \s : ] + ) ) \s * : ? \s * / i, ( match , p1 , p2 ) => {
116+ const prefixText = p1 || p2 ;
117+ if ( ! prefixText ) return match ;
118+ // Preserve multiple prefixes, capitalize each, wrap in [ ]
119+ const formatted = prefixText
120+ . split ( "," )
121+ . map ( p => `[${ p . trim ( ) . charAt ( 0 ) . toUpperCase ( ) + p . trim ( ) . slice ( 1 ) . toLowerCase ( ) } ]` )
122+ . join ( " " ) ;
123+ return `${ formatted } ` ;
124+ } ) ;
125+ }
126+
106127// --- Semantic versioning ---
107128function nextVersion ( lastTag ) {
108129 if ( ! lastTag ) return "v0.1.0" ;
109130 const match = lastTag . match ( / ^ v ( \d + ) \. ( \d + ) \. ( \d + ) / ) ;
110131 if ( ! match ) return "v0.1.0" ;
111-
112- let [ _ , major , minor , patch ] = match . map ( Number ) ;
132+ let [ , major , minor , patch ] = match . map ( Number ) ;
113133 patch += 1 ;
114134 return `v${ major } .${ minor } .${ patch } ` ;
115135}
@@ -163,7 +183,7 @@ async function main() {
163183 }
164184 }
165185
166- // 5️⃣ Classify
186+ // 5️⃣ Classify and build sections
167187 const sections = {
168188 "🚀 Tasks" : [ ] ,
169189 "🔧 Enhancements" : [ ] ,
@@ -179,17 +199,15 @@ async function main() {
179199
180200 for ( const [ num , info ] of Object . entries ( issueMap ) ) {
181201 const section = classifyTitle ( info . title ) ;
182- sections [ section ] . push (
183- `#${ num } ${ info . title } ↳ PRs: ${ info . prs
184- . sort ( ( a , b ) => a - b ) // сортировка по возрастанию
185- . map ( n => `#${ n } ` )
186- . join ( ", " ) } `
187- ) ;
202+ const title = normalizeTitlePrefixes ( info . title ) ;
203+ const prsText = info . prs . sort ( ( a , b ) => a - b ) . map ( n => `#${ n } ` ) . join ( ", " ) ;
204+ sections [ section ] . push ( `#${ num } ${ title } \n↳ PRs: ${ prsText } ` ) ;
188205 }
189206
190207 for ( const pr of prsWithoutIssue ) {
191208 const section = classifyTitle ( pr . title ) ;
192- sections [ section ] . push ( `#${ pr . number } ${ pr . title } ` ) ;
209+ const title = normalizeTitlePrefixes ( pr . title ) ;
210+ sections [ section ] . push ( `#${ pr . number } ${ title } ` ) ;
193211 }
194212
195213 // 6️⃣ Build release notes text
@@ -203,15 +221,15 @@ async function main() {
203221 }
204222
205223 console . log ( releaseNotesText ) ;
206- // --- Find or create draft release ---
224+
225+ // 7️⃣ Find or create draft release
207226 let draftRelease = null ;
208227 try {
209228 const { data : releases } = await octokit . repos . listReleases ( { owner : OWNER , repo : REPO , per_page : 10 } ) ;
210229 draftRelease = releases . find ( r => r . draft ) ;
211230 } catch { }
212231
213232 if ( draftRelease ) {
214- // Update existing draft
215233 await octokit . repos . updateRelease ( {
216234 owner : OWNER ,
217235 repo : REPO ,
@@ -221,7 +239,6 @@ async function main() {
221239 } ) ;
222240 console . log ( `✅ Draft release updated: ${ draftRelease . tag_name } ` ) ;
223241 } else {
224- // Create new draft
225242 await octokit . repos . createRelease ( {
226243 owner : OWNER ,
227244 repo : REPO ,
@@ -234,7 +251,7 @@ async function main() {
234251 console . log ( `✅ Draft release created: ${ newTag } ` ) ;
235252 }
236253
237- console . log ( `✅ Release created: ${ newTag } ` ) ;
254+ console . log ( `✅ Release processing completed ` ) ;
238255}
239256
240257// --- Run ---
0 commit comments