Skip to content

Commit b32d267

Browse files
committed
feat: add generate from latest tag
1 parent c9b46fe commit b32d267

File tree

4 files changed

+113
-13
lines changed

4 files changed

+113
-13
lines changed

__tests__/util.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ describe("util", () => {
5252
input_target_commitish: undefined,
5353
input_discussion_category_name: undefined,
5454
input_generate_release_notes: false,
55+
input_previous_tag: undefined,
5556
})
5657
);
5758
});
@@ -72,6 +73,7 @@ describe("util", () => {
7273
input_target_commitish: undefined,
7374
input_discussion_category_name: undefined,
7475
input_generate_release_notes: false,
76+
input_previous_tag: undefined,
7577
})
7678
);
7779
});
@@ -92,6 +94,7 @@ describe("util", () => {
9294
input_target_commitish: undefined,
9395
input_discussion_category_name: undefined,
9496
input_generate_release_notes: false,
97+
input_previous_tag: undefined,
9598
})
9699
);
97100
});
@@ -125,6 +128,7 @@ describe("util", () => {
125128
input_target_commitish: undefined,
126129
input_discussion_category_name: undefined,
127130
input_generate_release_notes: false,
131+
input_previous_tag: undefined,
128132
}
129133
);
130134
});
@@ -150,6 +154,7 @@ describe("util", () => {
150154
input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
151155
input_discussion_category_name: undefined,
152156
input_generate_release_notes: false,
157+
input_previous_tag: undefined,
153158
}
154159
);
155160
});
@@ -174,6 +179,7 @@ describe("util", () => {
174179
input_target_commitish: undefined,
175180
input_discussion_category_name: "releases",
176181
input_generate_release_notes: false,
182+
input_previous_tag: undefined,
177183
}
178184
);
179185
});
@@ -199,6 +205,7 @@ describe("util", () => {
199205
input_target_commitish: undefined,
200206
input_discussion_category_name: undefined,
201207
input_generate_release_notes: true,
208+
input_previous_tag: undefined,
202209
}
203210
);
204211
});
@@ -227,6 +234,7 @@ describe("util", () => {
227234
input_target_commitish: undefined,
228235
input_discussion_category_name: undefined,
229236
input_generate_release_notes: false,
237+
input_previous_tag: undefined,
230238
}
231239
);
232240
});
@@ -253,6 +261,7 @@ describe("util", () => {
253261
input_target_commitish: undefined,
254262
input_discussion_category_name: undefined,
255263
input_generate_release_notes: false,
264+
input_previous_tag: undefined,
256265
}
257266
);
258267
});
@@ -278,6 +287,7 @@ describe("util", () => {
278287
input_target_commitish: undefined,
279288
input_discussion_category_name: undefined,
280289
input_generate_release_notes: false,
290+
input_previous_tag: undefined,
281291
}
282292
);
283293
});
@@ -302,6 +312,7 @@ describe("util", () => {
302312
input_target_commitish: undefined,
303313
input_discussion_category_name: undefined,
304314
input_generate_release_notes: false,
315+
input_previous_tag: undefined,
305316
}
306317
);
307318
});

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ inputs:
4343
generate_release_notes:
4444
description: "Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise, a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes."
4545
required: false
46+
previous_tag:
47+
description: "The tag name of the previous release. If not specified, the previous tag will be detected automatically."
48+
required: false
49+
default: ""
4650
append_body:
4751
description: "Append to existing body instead of overwriting it. Default is false."
4852
required: false

src/github.ts

Lines changed: 96 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7077
export 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

126172
export 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) {

src/util.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export interface Config {
1919
input_discussion_category_name?: string;
2020
input_generate_release_notes?: boolean;
2121
input_append_body?: boolean;
22+
input_previous_tag?: string;
2223
}
2324

2425
export const uploadUrl = (url: string): string => {
@@ -70,6 +71,7 @@ export const parseConfig = (env: Env): Config => {
7071
env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
7172
input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == "true",
7273
input_append_body: env.INPUT_APPEND_BODY == "true",
74+
input_previous_tag: env.INPUT_PREVIOUS_TAG?.trim() || undefined,
7375
};
7476
};
7577

0 commit comments

Comments
 (0)