@@ -44,7 +44,6 @@ export interface Releaser {
44
44
prerelease : boolean | undefined ;
45
45
target_commitish : string | undefined ;
46
46
discussion_category_name : string | undefined ;
47
- generate_release_notes : boolean | undefined ;
48
47
} ) : Promise < { data : Release } > ;
49
48
50
49
updateRelease ( params : {
@@ -58,13 +57,21 @@ export interface Releaser {
58
57
draft : boolean | undefined ;
59
58
prerelease : boolean | undefined ;
60
59
discussion_category_name : string | undefined ;
61
- generate_release_notes : boolean | undefined ;
62
60
} ) : Promise < { data : Release } > ;
63
61
64
62
allReleases ( params : {
65
63
owner : string ;
66
64
repo : string ;
67
65
} ) : 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 > ;
68
75
}
69
76
70
77
export class GitHubReleaser implements Releaser {
@@ -91,9 +98,11 @@ export class GitHubReleaser implements Releaser {
91
98
prerelease : boolean | undefined ;
92
99
target_commitish : string | undefined ;
93
100
discussion_category_name : string | undefined ;
94
- generate_release_notes : boolean | undefined ;
95
101
} ) : 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
+ } ) ;
97
106
}
98
107
99
108
updateRelease ( params : {
@@ -107,9 +116,11 @@ export class GitHubReleaser implements Releaser {
107
116
draft : boolean | undefined ;
108
117
prerelease : boolean | undefined ;
109
118
discussion_category_name : string | undefined ;
110
- generate_release_notes : boolean | undefined ;
111
119
} ) : 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
+ } ) ;
113
124
}
114
125
115
126
allReleases ( params : {
@@ -121,6 +132,41 @@ export class GitHubReleaser implements Releaser {
121
132
this . github . rest . repos . listReleases . endpoint . merge ( updatedParams )
122
133
) ;
123
134
}
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
+ }
124
170
}
125
171
126
172
export const asset = ( path : string ) : ReleaseAsset => {
@@ -196,8 +242,40 @@ export const release = async (
196
242
? config . github_ref . replace ( "refs/tags/" , "" )
197
243
: "" ) ;
198
244
245
+ const previous_tag = config . input_previous_tag ;
199
246
const discussion_category_name = config . input_discussion_category_name ;
200
247
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
+
201
279
try {
202
280
// you can't get a an existing draft by tag
203
281
// so we must find one in the list of all releases
@@ -232,19 +310,20 @@ export const release = async (
232
310
target_commitish = existingRelease . data . target_commitish ;
233
311
}
234
312
235
- const tag_name = tag ;
236
313
const name = config . input_name || existingRelease . data . name || tag ;
237
314
// revisit: support a new body-concat-strategy input for accumulating
238
315
// body parts as a release gets updated. some users will likely want this while
239
316
// others won't previously this was duplicating content for most which
240
317
// no one wants
241
318
const workflowBody = releaseBody ( config ) || "" ;
242
319
const existingReleaseBody = existingRelease . data . body || "" ;
243
- let body : string ;
320
+
244
321
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 ;
246
324
} else {
247
- body = workflowBody || existingReleaseBody ;
325
+ console . log ( `➕ Using ${ workflowBody ? 'workflow body' : 'existing release body' } ` ) ;
326
+ body = body + ( workflowBody || existingReleaseBody ) ;
248
327
}
249
328
250
329
const draft =
@@ -267,14 +346,19 @@ export const release = async (
267
346
draft,
268
347
prerelease,
269
348
discussion_category_name,
270
- generate_release_notes,
271
349
} ) ;
272
350
return release . data ;
273
351
} catch ( error ) {
274
352
if ( error . status === 404 ) {
275
353
const tag_name = tag ;
276
354
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
+
278
362
const draft = config . input_draft ;
279
363
const prerelease = config . input_prerelease ;
280
364
const target_commitish = config . input_target_commitish ;
@@ -296,7 +380,6 @@ export const release = async (
296
380
prerelease,
297
381
target_commitish,
298
382
discussion_category_name,
299
- generate_release_notes,
300
383
} ) ;
301
384
return release . data ;
302
385
} catch ( error ) {
0 commit comments