@@ -4,45 +4,119 @@ import fetch from 'node-fetch';
4
4
5
5
/**
6
6
* Stylizes a markdown body into an appropriate embed message style.
7
- * H3s converted to bold and underlined.
8
- * H2s converted to bold.
9
- * Redundant whitespace and newlines removed.
10
- * @param description
11
- * @returns {* }
7
+ * Remove HTML comments (commonly added by 'Generate release notes' button)
8
+ * Better URL linking for common Github links: PRs, Issues, Compare
9
+ * Redundant whitespace and newlines removed, keeping at max 2 to provide space between paragraphs
10
+ * Trim leading/trailing whitespace
11
+ * If reduce_headings:
12
+ * H3s converted to bold and underlined
13
+ * H2s converted to bold
14
+ * @param {string } description
12
15
*/
13
16
const formatDescription = ( description ) => {
14
- return description
15
- . replace ( / # # # ( .* ?) \n / g, function ( substring ) {
16
- const newString = substring . slice ( 4 ) . replace ( / ( \r \n | \n | \r ) / gm, "" )
17
- return `**__${ newString } __**`
17
+ let edit = description
18
+ . replace ( / < ! - - .* ?- - > / gs, '' )
19
+ . replace (
20
+ new RegExp (
21
+ "https://github.com/(.+)/(.+)/(issues|pull|commit|compare)/(\\S+)" ,
22
+ "g"
23
+ ) ,
24
+ ( match , user , repo , type , id ) => {
25
+ return `[${ getTypePrefix ( type ) + id } ](${ match } )`
26
+ }
27
+ )
28
+ . replace ( / \n \s * \n / g, ( ws ) => {
29
+ const nlCount = ( ws . match ( / \n / g) || [ ] ) . length
30
+ return nlCount >= 2 ? '\n\n' : '\n'
18
31
} )
19
- . replace ( / # # ( .* ?) \n / g, function ( substring ) {
20
- const newString = substring . slice ( 3 ) . replace ( / ( \r \n | \n | \r ) / gm, "" )
21
- return `**${ newString } **`
22
- } )
23
- . replace ( / \n \s * \n / g, '\n' )
32
+ . trim ( )
33
+
34
+ if ( core . getBooleanInput ( 'reduce_headings' ) ) {
35
+ edit = edit
36
+ . replace ( / ^ # # # \s + ( .+ ) $ / gm, '**__$1__**' )
37
+ . replace ( / ^ # # \s + ( .+ ) $ / gm, '**$1**' )
38
+ }
39
+
40
+ return edit
41
+ }
42
+
43
+ /**
44
+ * Get a prefix to use for Github link display
45
+ * @param {'issues' | 'pull' | 'commit' | 'compare' } type
46
+ */
47
+ function getTypePrefix ( type ) {
48
+ switch ( type ) {
49
+ case 'issues' :
50
+ return 'Issue #'
51
+ case 'pull' :
52
+ return 'PR #'
53
+ case 'commit' :
54
+ return 'Commit #'
55
+ case 'compare' :
56
+ return ''
57
+ default :
58
+ return '#'
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Gets the max description length if set to a valid number,
64
+ * otherwise the default of 4096
65
+ */
66
+ function getMaxDescription ( ) {
67
+ try {
68
+ const max = core . getInput ( 'max_description' )
69
+ if ( typeof max === 'string' && max . length ) {
70
+ // 4096 is max for Embed Description
71
+ // https://discord.com/developers/docs/resources/channel#embed-object-embed-limits
72
+ return Math . min ( parseInt ( max , 10 ) , 4096 )
73
+ }
74
+ } catch ( err ) {
75
+ core . warning ( `max_description not a valid number: ${ err } ` )
76
+ }
77
+ return 4096
24
78
}
25
79
26
80
/**
27
81
* Get the context of the action, returns a GitHub Release payload.
28
- * @returns {Promise<{html_url, body: (*|string), name: string}> }
29
82
*/
30
- async function getContext ( ) {
83
+ function getContext ( ) {
31
84
const payload = github . context . payload ;
32
85
33
86
return {
34
- body : payload . release . body . length < 1500
35
- ? payload . release . body
36
- : payload . release . body . substring ( 0 , 1500 ) + ` ([...](${ payload . release . html_url } ))` ,
37
- name : payload . release . name ,
87
+ body : payload . release . body ,
88
+ name : payload . release . name ,
38
89
html_url : payload . release . html_url
39
90
}
40
91
}
41
92
93
+ /**
94
+ *
95
+ * @param {string } str
96
+ * @param {number } maxLength
97
+ * @param {string= } url
98
+ */
99
+ function limit ( str , maxLength , url ) {
100
+ if ( str . length <= maxLength )
101
+ return str
102
+ let replacement = '…'
103
+ if ( url ) {
104
+ replacement = `([${ replacement } ](${ url } ))`
105
+ }
106
+ maxLength = maxLength - replacement . length
107
+ str = str . substring ( 0 , maxLength )
108
+
109
+ const lastWhitespace = str . search ( / [ ^ \s ] * $ / )
110
+ if ( lastWhitespace > - 1 ) {
111
+ str = str . substring ( 0 , lastWhitespace )
112
+ }
113
+
114
+ return str + replacement
115
+ }
116
+
42
117
/**
43
118
* Handles the action.
44
119
* Get inputs, creates a stylized response webhook, and sends it to the channel.
45
- * @returns {Promise<void> }
46
120
*/
47
121
async function run ( ) {
48
122
const webhookUrl = core . getInput ( 'webhook_url' ) ;
@@ -56,22 +130,25 @@ async function run () {
56
130
57
131
if ( ! webhookUrl ) return core . setFailed ( 'webhook_url not set. Please set it.' ) ;
58
132
59
- const { body, html_url, name} = await getContext ( ) ;
133
+ const { body, html_url, name} = getContext ( ) ;
60
134
61
135
const description = formatDescription ( body ) ;
62
136
63
137
let embedMsg = {
64
- title : name ,
138
+ title : limit ( name , 256 ) ,
65
139
url : html_url ,
66
140
color : color ,
67
141
description : description ,
68
142
footer : { }
69
143
}
70
144
71
- if ( footerTitle != '' ) embedMsg . footer . text = footerTitle ;
145
+ if ( footerTitle != '' ) embedMsg . footer . text = limit ( footerTitle , 2048 ) ;
72
146
if ( footerIconUrl != '' ) embedMsg . footer . icon_url = footerIconUrl ;
73
147
if ( footerTimestamp == 'true' ) embedMsg . timestamp = new Date ( ) . toISOString ( ) ;
74
148
149
+ let embedSize = embedMsg . title . length + ( embedMsg . footer ?. text ?. length ?? 0 )
150
+ embedMsg . description = limit ( embedMsg . description , Math . min ( getMaxDescription ( ) , 6000 - embedSize ) , embedMsg . url )
151
+
75
152
let requestBody = {
76
153
embeds : [ embedMsg ]
77
154
}
0 commit comments