@@ -24,37 +24,91 @@ export async function sendWebhook(inp: {inputs: Inputs, api: OctokitApi, repoDat
2424
2525 const thumbnail = `https://opengraph.githubassets.com/1/${ owner } /${ repo } /releases/tag/${ tag } ` ;
2626
27- let assets = '' ;
27+ // Prepare Asset Fields (Split if > 1024)
28+ let assetLines : string [ ] = [ ] ;
2829 for ( const asset of updatedRelease . data . assets ) {
29- assets += `- :page_facing_up: [${ asset . name } ](${ asset . browser_download_url } )\n` ;
30+ assetLines . push ( `- :page_facing_up: [${ asset . name } ](${ asset . browser_download_url } )` ) ;
3031 }
31- assets += `- :package: [Source code (zip)](${ updatedRelease . data . zipball_url } )\n` ;
32- assets += `- :package: [Source code (tar.gz)](${ updatedRelease . data . tarball_url } )\n` ;
32+ assetLines . push ( `- :package: [Source code (zip)](${ updatedRelease . data . zipball_url } )` ) ;
33+ assetLines . push ( `- :package: [Source code (tar.gz)](${ updatedRelease . data . tarball_url } )` ) ;
3334
35+ const assetFields : { name : string ; value : string ; inline : boolean } [ ] = [ ] ;
36+ let currentAssetChunk = '' ;
37+
38+ for ( const line of assetLines ) {
39+ if ( currentAssetChunk . length + line . length + 1 > 1024 ) {
40+ assetFields . push ( { name : 'Assets' , value : currentAssetChunk , inline : false } ) ;
41+ currentAssetChunk = '' ;
42+ }
43+ currentAssetChunk += line + '\n' ;
44+ }
45+ if ( currentAssetChunk ) {
46+ assetFields . push ( { name : 'Assets' , value : currentAssetChunk , inline : false } ) ;
47+ }
48+
49+ // Prepare Static Fields
3450 const time = Math . floor ( new Date ( updatedRelease . data . created_at ) . getTime ( ) / 1000 ) ;
35- const author = updatedRelease . data . author . type === 'User' ? updatedRelease . data . author . login : updatedRelease . data . author . login . replace ( '[bot]' , '' ) ;
3651 const sha = inputs . changes [ inputs . changes . length - 1 ] . commit . slice ( 0 , 7 ) ;
3752 const statusEmoji = failed ? ':red_circle:' : ':green_circle:' ;
3853 const status = failed ? 'Failed' : 'Success' ;
3954 const runID = process . env . GITHUB_RUN_ID ! ;
4055
56+ const staticFields = [
57+ { name : '' , value : `:watch: <t:${ time } :R>` , inline : true } ,
58+ { name : '' , value : `:label: [${ tag } ](${ url } /${ owner } /${ repo } /tree/${ tag } )` , inline : true } ,
59+ { name : '' , value : `:lock_with_ink_pen: [${ sha } ](${ url } /${ owner } /${ repo } /commit/${ sha } )` , inline : true } ,
60+ { name : '' , value : `${ statusEmoji } [${ status } ](${ url } /${ owner } /${ repo } /actions/runs/${ runID } )` , inline : true }
61+ ] ;
62+
63+ // Enforce Field Count Limit (Max 25)
64+ // We have 4 static fields, leaving 21 slots for assets
65+ if ( assetFields . length > 21 ) {
66+ assetFields . length = 21 ;
67+ }
68+ const allFields = [ ...assetFields , ...staticFields ] ;
69+
70+ // Truncate & Calculate Sizes
71+ // Author Name: Max 256
72+ const embedAuthorName = `${ owner } /${ repo } ` . substring ( 0 , 256 ) ;
73+
74+ // Title: Max 256
75+ const embedTitle = inputs . release . name . substring ( 0 , 256 ) ;
76+
77+ // Footer: Max 2048
78+ let author = updatedRelease . data . author . type === 'User' ? updatedRelease . data . author . login : updatedRelease . data . author . login . replace ( '[bot]' , '' ) ;
79+ const embedFooterText = `Released by ${ author } ` . substring ( 0 , 2048 ) ;
80+
81+ // Calculate current used size (excluding description)
82+ let currentTotalSize = 0 ;
83+ currentTotalSize += embedAuthorName . length ;
84+ currentTotalSize += embedTitle . length ;
85+ currentTotalSize += embedFooterText . length ;
86+
87+ for ( const f of allFields ) {
88+ currentTotalSize += ( f . name . length || 0 ) + ( f . value . length || 0 ) ;
89+ }
90+
91+ // Description: Max 4096, but Total Embed must be <= 6000
92+ const availableForDesc = 6000 - currentTotalSize ;
93+ const maxDesc = Math . min ( 4096 , availableForDesc ) ;
94+ const description = ( inputs . release . body || '' ) . substring ( 0 , Math . max ( 0 , maxDesc ) ) ;
95+
4196 const embed = new Embed ( )
4297 . setTimestamp ( )
4398 . setAuthor ( {
44- name : ` ${ owner } / ${ repo } ` ,
99+ name : embedAuthorName ,
45100 url : `${ url } /${ owner } /${ repo } ` ,
46101 icon_url : `${ url } /${ owner } .png`
47102 } )
48103 . setColor ( color )
49- . setTitle ( inputs . release . name )
104+ . setTitle ( embedTitle )
50105 . setUrl ( updatedRelease . data . html_url )
51- . setDescription ( inputs . release . body . substring ( 0 , 4000 ) )
52- . addField ( { name : 'Assets' , value : assets , inline : false } )
53- . addField ( { name : '' , value : `:watch: <t:${ time } :R>` , inline : true } )
54- . addField ( { name : '' , value : `:label: [${ tag } ](${ url } /${ owner } /${ repo } /tree/${ tag } )` , inline : true } )
55- . addField ( { name : '' , value : `:lock_with_ink_pen: [${ sha } ](${ url } /${ owner } /${ repo } /commit/${ sha } )` , inline : true } )
56- . addField ( { name : '' , value : `${ statusEmoji } [${ status } ](${ url } /${ owner } /${ repo } /actions/runs/${ runID } )` , inline : true } )
57- . setFooter ( { text : `Released by ${ author } ` , icon_url : updatedRelease . data . author . avatar_url } )
106+ . setDescription ( description )
107+ . setFooter ( { text : embedFooterText , icon_url : updatedRelease . data . author . avatar_url } )
108+
109+ for ( const field of allFields ) {
110+ embed . addField ( field ) ;
111+ }
58112
59113 if ( thumbnail ) {
60114 embed . setImage ( { url : thumbnail } ) ;
0 commit comments