@@ -44,7 +44,6 @@ export interface Releaser {
4444 prerelease : boolean | undefined ;
4545 target_commitish : string | undefined ;
4646 discussion_category_name : string | undefined ;
47- generate_release_notes : boolean | undefined ;
4847 } ) : Promise < { data : Release } > ;
4948
5049 updateRelease ( params : {
@@ -58,13 +57,21 @@ export interface Releaser {
5857 draft : boolean | undefined ;
5958 prerelease : boolean | undefined ;
6059 discussion_category_name : string | undefined ;
61- generate_release_notes : boolean | undefined ;
6260 } ) : Promise < { data : Release } > ;
6361
6462 allReleases ( params : {
6563 owner : string ;
6664 repo : string ;
6765 } ) : AsyncIterableIterator < { data : Release [ ] } > ;
66+
67+ getLatestTag ( params : {
68+ owner : string ;
69+ repo : string ;
70+ } ) : Promise < undefined | string > ;
71+
72+ generateReleaseBody (
73+ params : Parameters < GitHub [ "rest" ] [ "repos" ] [ "generateReleaseNotes" ] > [ 0 ]
74+ ) : Promise < string > ;
6875}
6976
7077export class GitHubReleaser implements Releaser {
@@ -91,9 +98,11 @@ export class GitHubReleaser implements Releaser {
9198 prerelease : boolean | undefined ;
9299 target_commitish : string | undefined ;
93100 discussion_category_name : string | undefined ;
94- generate_release_notes : boolean | undefined ;
95101 } ) : Promise < { data : Release } > {
96- return this . github . rest . repos . createRelease ( params ) ;
102+ return this . github . rest . repos . createRelease ( {
103+ ...params ,
104+ generate_release_notes : false ,
105+ } ) ;
97106 }
98107
99108 updateRelease ( params : {
@@ -107,9 +116,11 @@ export class GitHubReleaser implements Releaser {
107116 draft : boolean | undefined ;
108117 prerelease : boolean | undefined ;
109118 discussion_category_name : string | undefined ;
110- generate_release_notes : boolean | undefined ;
111119 } ) : Promise < { data : Release } > {
112- return this . github . rest . repos . updateRelease ( params ) ;
120+ return this . github . rest . repos . updateRelease ( {
121+ ...params ,
122+ generate_release_notes : false ,
123+ } ) ;
113124 }
114125
115126 allReleases ( params : {
@@ -121,6 +132,41 @@ export class GitHubReleaser implements Releaser {
121132 this . github . rest . repos . listReleases . endpoint . merge ( updatedParams )
122133 ) ;
123134 }
135+
136+ async getLatestTag ( params : {
137+ owner : string ;
138+ repo : string ;
139+ } ) : Promise < undefined | string > {
140+ try {
141+ const release = await this . github . rest . repos . getLatestRelease ( params ) ;
142+
143+ if ( ! release ?. data ) {
144+ return ;
145+ }
146+
147+ return release . data . tag_name ;
148+ } catch ( e ) {
149+ console . error ( e ) ;
150+
151+ return ;
152+ }
153+ }
154+
155+ async generateReleaseBody (
156+ params : Parameters < GitHub [ "rest" ] [ "repos" ] [ "generateReleaseNotes" ] > [ 0 ]
157+ ) : Promise < string > {
158+ try {
159+ const { data } = await this . github . rest . repos . generateReleaseNotes ( params ) ;
160+
161+ if ( ! data . body ) {
162+ throw new Error ( "No release body generated" ) ;
163+ }
164+
165+ return data . body ;
166+ } catch ( e ) {
167+ throw e ;
168+ }
169+ }
124170}
125171
126172export const asset = ( path : string ) : ReleaseAsset => {
@@ -196,8 +242,40 @@ export const release = async (
196242 ? config . github_ref . replace ( "refs/tags/" , "" )
197243 : "" ) ;
198244
245+ const previous_tag = config . input_previous_tag ;
199246 const discussion_category_name = config . input_discussion_category_name ;
200247 const generate_release_notes = config . input_generate_release_notes ;
248+
249+ const latestTag : string | undefined = ! previous_tag
250+ ? await releaser . getLatestTag ( {
251+ owner,
252+ repo,
253+ } )
254+ : undefined ;
255+
256+ if ( latestTag ) {
257+ console . log ( `🏷️ Latest tag related to a release is ${ latestTag } ` ) ;
258+ } else if ( previous_tag ) {
259+ console . log ( `🏷️ Previous tag is ${ previous_tag } ` ) ;
260+ }
261+
262+ const tag_name = tag ;
263+
264+ let body : string = generate_release_notes
265+ ? await releaser . generateReleaseBody ( {
266+ owner,
267+ repo,
268+ tag_name,
269+ previous_tag_name : previous_tag || latestTag ,
270+ } )
271+ : "" ;
272+
273+ if ( generate_release_notes && previous_tag || latestTag ) {
274+ console . log ( `Will generate release notes using ${ previous_tag || latestTag } as previous tag` ) ;
275+ }
276+
277+ body = body ? `${ body } \n` : "" ;
278+
201279 try {
202280 // you can't get a an existing draft by tag
203281 // so we must find one in the list of all releases
@@ -232,19 +310,20 @@ export const release = async (
232310 target_commitish = existingRelease . data . target_commitish ;
233311 }
234312
235- const tag_name = tag ;
236313 const name = config . input_name || existingRelease . data . name || tag ;
237314 // revisit: support a new body-concat-strategy input for accumulating
238315 // body parts as a release gets updated. some users will likely want this while
239316 // others won't previously this was duplicating content for most which
240317 // no one wants
241318 const workflowBody = releaseBody ( config ) || "" ;
242319 const existingReleaseBody = existingRelease . data . body || "" ;
243- let body : string ;
320+
244321 if ( config . input_append_body && workflowBody && existingReleaseBody ) {
245- body = existingReleaseBody + "\n" + workflowBody ;
322+ console . log ( '➕ Appending existing release body' ) ;
323+ body = body + existingReleaseBody + "\n" + workflowBody ;
246324 } else {
247- body = workflowBody || existingReleaseBody ;
325+ console . log ( `➕ Using ${ workflowBody ? 'workflow body' : 'existing release body' } ` ) ;
326+ body = body + ( workflowBody || existingReleaseBody ) ;
248327 }
249328
250329 const draft =
@@ -267,14 +346,19 @@ export const release = async (
267346 draft,
268347 prerelease,
269348 discussion_category_name,
270- generate_release_notes,
271349 } ) ;
272350 return release . data ;
273351 } catch ( error ) {
274352 if ( error . status === 404 ) {
275353 const tag_name = tag ;
276354 const name = config . input_name || tag ;
277- const body = releaseBody ( config ) ;
355+ const workflowBody = releaseBody ( config ) || "" ;
356+
357+ if ( config . input_append_body && workflowBody ) {
358+ console . log ( '➕ Appending existing release body' ) ;
359+ body = body + workflowBody ;
360+ }
361+
278362 const draft = config . input_draft ;
279363 const prerelease = config . input_prerelease ;
280364 const target_commitish = config . input_target_commitish ;
@@ -296,7 +380,6 @@ export const release = async (
296380 prerelease,
297381 target_commitish,
298382 discussion_category_name,
299- generate_release_notes,
300383 } ) ;
301384 return release . data ;
302385 } catch ( error ) {
0 commit comments