mirror of
https://github.com/softprops/action-gh-release.git
synced 2025-05-11 02:44:20 +00:00
feat: add generate from latest tag
This commit is contained in:
parent
c9b46fe7aa
commit
4a08b319df
5 changed files with 114 additions and 14 deletions
|
@ -52,6 +52,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -72,6 +73,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -92,6 +94,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -125,6 +128,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -150,6 +154,7 @@ describe("util", () => {
|
||||||
input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
|
input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -174,6 +179,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: "releases",
|
input_discussion_category_name: "releases",
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -199,6 +205,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: true,
|
input_generate_release_notes: true,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -227,6 +234,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -253,6 +261,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -278,6 +287,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -302,6 +312,7 @@ describe("util", () => {
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined,
|
||||||
input_generate_release_notes: false,
|
input_generate_release_notes: false,
|
||||||
|
input_previous_tag: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,6 +43,10 @@ inputs:
|
||||||
generate_release_notes:
|
generate_release_notes:
|
||||||
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."
|
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."
|
||||||
required: false
|
required: false
|
||||||
|
previous_tag:
|
||||||
|
description: "The tag name of the previous release. If not specified, the previous tag will be detected automatically."
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
append_body:
|
append_body:
|
||||||
description: "Append to existing body instead of overwriting it. Default is false."
|
description: "Append to existing body instead of overwriting it. Default is false."
|
||||||
required: false
|
required: false
|
||||||
|
|
2
dist/index.js
vendored
2
dist/index.js
vendored
File diff suppressed because one or more lines are too long
109
src/github.ts
109
src/github.ts
|
@ -44,7 +44,6 @@ export interface Releaser {
|
||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
target_commitish: string | undefined;
|
target_commitish: string | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
}): Promise<{ data: Release }>;
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
updateRelease(params: {
|
updateRelease(params: {
|
||||||
|
@ -58,13 +57,21 @@ export interface Releaser {
|
||||||
draft: boolean | undefined;
|
draft: boolean | undefined;
|
||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
}): Promise<{ data: Release }>;
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
allReleases(params: {
|
allReleases(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
}): AsyncIterableIterator<{ data: Release[] }>;
|
}): AsyncIterableIterator<{ data: Release[] }>;
|
||||||
|
|
||||||
|
getLatestTag(params: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
}): Promise<undefined | string>;
|
||||||
|
|
||||||
|
generateReleaseBody(
|
||||||
|
params: Parameters<GitHub["rest"]["repos"]["generateReleaseNotes"]>[0]
|
||||||
|
): Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GitHubReleaser implements Releaser {
|
export class GitHubReleaser implements Releaser {
|
||||||
|
@ -91,9 +98,11 @@ export class GitHubReleaser implements Releaser {
|
||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
target_commitish: string | undefined;
|
target_commitish: string | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
}): Promise<{ data: Release }> {
|
}): Promise<{ data: Release }> {
|
||||||
return this.github.rest.repos.createRelease(params);
|
return this.github.rest.repos.createRelease({
|
||||||
|
...params,
|
||||||
|
generate_release_notes: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRelease(params: {
|
updateRelease(params: {
|
||||||
|
@ -107,9 +116,11 @@ export class GitHubReleaser implements Releaser {
|
||||||
draft: boolean | undefined;
|
draft: boolean | undefined;
|
||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
}): Promise<{ data: Release }> {
|
}): Promise<{ data: Release }> {
|
||||||
return this.github.rest.repos.updateRelease(params);
|
return this.github.rest.repos.updateRelease({
|
||||||
|
...params,
|
||||||
|
generate_release_notes: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
allReleases(params: {
|
allReleases(params: {
|
||||||
|
@ -121,6 +132,41 @@ export class GitHubReleaser implements Releaser {
|
||||||
this.github.rest.repos.listReleases.endpoint.merge(updatedParams)
|
this.github.rest.repos.listReleases.endpoint.merge(updatedParams)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLatestTag(params: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
}): Promise<undefined | string> {
|
||||||
|
try {
|
||||||
|
const release = await this.github.rest.repos.getLatestRelease(params);
|
||||||
|
|
||||||
|
if (!release?.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return release.data.tag_name;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateReleaseBody(
|
||||||
|
params: Parameters<GitHub["rest"]["repos"]["generateReleaseNotes"]>[0]
|
||||||
|
): Promise<string> {
|
||||||
|
try {
|
||||||
|
const { data } = await this.github.rest.repos.generateReleaseNotes(params);
|
||||||
|
|
||||||
|
if (!data.body) {
|
||||||
|
throw new Error("No release body generated");
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.body;
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const asset = (path: string): ReleaseAsset => {
|
export const asset = (path: string): ReleaseAsset => {
|
||||||
|
@ -196,8 +242,40 @@ export const release = async (
|
||||||
? config.github_ref.replace("refs/tags/", "")
|
? config.github_ref.replace("refs/tags/", "")
|
||||||
: "");
|
: "");
|
||||||
|
|
||||||
|
const previous_tag = config.input_previous_tag;
|
||||||
const discussion_category_name = config.input_discussion_category_name;
|
const discussion_category_name = config.input_discussion_category_name;
|
||||||
const generate_release_notes = config.input_generate_release_notes;
|
const generate_release_notes = config.input_generate_release_notes;
|
||||||
|
|
||||||
|
const latestTag: string | undefined = !previous_tag
|
||||||
|
? await releaser.getLatestTag({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (latestTag) {
|
||||||
|
console.log(`🏷️ Latest tag related to a release is ${latestTag}`);
|
||||||
|
} else if (previous_tag) {
|
||||||
|
console.log(`🏷️ Previous tag is ${previous_tag}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag_name = tag;
|
||||||
|
|
||||||
|
let body: string = generate_release_notes
|
||||||
|
? await releaser.generateReleaseBody({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
tag_name,
|
||||||
|
previous_tag_name: previous_tag || latestTag,
|
||||||
|
})
|
||||||
|
: "";
|
||||||
|
|
||||||
|
if (generate_release_notes && previous_tag || latestTag) {
|
||||||
|
console.log(`Will generate release notes using ${previous_tag || latestTag} as previous tag`);
|
||||||
|
}
|
||||||
|
|
||||||
|
body = body ? `${body}\n` : "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// you can't get a an existing draft by tag
|
// you can't get a an existing draft by tag
|
||||||
// so we must find one in the list of all releases
|
// so we must find one in the list of all releases
|
||||||
|
@ -232,7 +310,6 @@ export const release = async (
|
||||||
target_commitish = existingRelease.data.target_commitish;
|
target_commitish = existingRelease.data.target_commitish;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag_name = tag;
|
|
||||||
const name = config.input_name || existingRelease.data.name || tag;
|
const name = config.input_name || existingRelease.data.name || tag;
|
||||||
// revisit: support a new body-concat-strategy input for accumulating
|
// revisit: support a new body-concat-strategy input for accumulating
|
||||||
// body parts as a release gets updated. some users will likely want this while
|
// body parts as a release gets updated. some users will likely want this while
|
||||||
|
@ -240,11 +317,13 @@ export const release = async (
|
||||||
// no one wants
|
// no one wants
|
||||||
const workflowBody = releaseBody(config) || "";
|
const workflowBody = releaseBody(config) || "";
|
||||||
const existingReleaseBody = existingRelease.data.body || "";
|
const existingReleaseBody = existingRelease.data.body || "";
|
||||||
let body: string;
|
|
||||||
if (config.input_append_body && workflowBody && existingReleaseBody) {
|
if (config.input_append_body && workflowBody && existingReleaseBody) {
|
||||||
body = existingReleaseBody + "\n" + workflowBody;
|
console.log('➕ Appending existing release body');
|
||||||
|
body = body + existingReleaseBody + "\n" + workflowBody;
|
||||||
} else {
|
} else {
|
||||||
body = workflowBody || existingReleaseBody;
|
console.log(`➕ Using ${workflowBody ? 'workflow body' : 'existing release body'}`);
|
||||||
|
body = body + (workflowBody || existingReleaseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
const draft =
|
const draft =
|
||||||
|
@ -267,14 +346,19 @@ export const release = async (
|
||||||
draft,
|
draft,
|
||||||
prerelease,
|
prerelease,
|
||||||
discussion_category_name,
|
discussion_category_name,
|
||||||
generate_release_notes,
|
|
||||||
});
|
});
|
||||||
return release.data;
|
return release.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.status === 404) {
|
if (error.status === 404) {
|
||||||
const tag_name = tag;
|
const tag_name = tag;
|
||||||
const name = config.input_name || tag;
|
const name = config.input_name || tag;
|
||||||
const body = releaseBody(config);
|
const workflowBody = releaseBody(config) || "";
|
||||||
|
|
||||||
|
if (config.input_append_body && workflowBody) {
|
||||||
|
console.log('➕ Appending existing release body');
|
||||||
|
body = body + workflowBody;
|
||||||
|
}
|
||||||
|
|
||||||
const draft = config.input_draft;
|
const draft = config.input_draft;
|
||||||
const prerelease = config.input_prerelease;
|
const prerelease = config.input_prerelease;
|
||||||
const target_commitish = config.input_target_commitish;
|
const target_commitish = config.input_target_commitish;
|
||||||
|
@ -296,7 +380,6 @@ export const release = async (
|
||||||
prerelease,
|
prerelease,
|
||||||
target_commitish,
|
target_commitish,
|
||||||
discussion_category_name,
|
discussion_category_name,
|
||||||
generate_release_notes,
|
|
||||||
});
|
});
|
||||||
return release.data;
|
return release.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface Config {
|
||||||
input_discussion_category_name?: string;
|
input_discussion_category_name?: string;
|
||||||
input_generate_release_notes?: boolean;
|
input_generate_release_notes?: boolean;
|
||||||
input_append_body?: boolean;
|
input_append_body?: boolean;
|
||||||
|
input_previous_tag?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const uploadUrl = (url: string): string => {
|
export const uploadUrl = (url: string): string => {
|
||||||
|
@ -70,6 +71,7 @@ export const parseConfig = (env: Env): Config => {
|
||||||
env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
|
env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
|
||||||
input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == "true",
|
input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == "true",
|
||||||
input_append_body: env.INPUT_APPEND_BODY == "true",
|
input_append_body: env.INPUT_APPEND_BODY == "true",
|
||||||
|
input_previous_tag: env.INPUT_PREVIOUS_TAG?.trim() || undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue