mirror of
https://github.com/softprops/action-gh-release.git
synced 2025-06-27 22:06:03 +00:00
Merge 4577bf1fa8
into 40521a2029
This commit is contained in:
commit
262a313453
6 changed files with 605 additions and 412 deletions
|
@ -61,6 +61,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
@ -84,6 +85,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
@ -107,6 +109,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
@ -143,6 +146,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -171,6 +175,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -198,6 +203,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: 'releases',
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -226,6 +232,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: true,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -258,6 +265,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -287,6 +295,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -306,6 +315,7 @@ describe('util', () => {
|
|||
input_draft: false,
|
||||
input_prerelease: true,
|
||||
input_preserve_order: undefined,
|
||||
input_previous_tag: undefined,
|
||||
input_files: [],
|
||||
input_overwrite_files: undefined,
|
||||
input_name: undefined,
|
||||
|
@ -342,6 +352,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: 'false',
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -369,6 +380,7 @@ describe('util', () => {
|
|||
input_discussion_category_name: undefined,
|
||||
input_generate_release_notes: false,
|
||||
input_make_latest: undefined,
|
||||
input_previous_tag: undefined,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
@ -50,6 +50,10 @@ inputs:
|
|||
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."
|
||||
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:
|
||||
description: "Append to existing body instead of overwriting it. Default is false."
|
||||
required: false
|
||||
|
|
2
dist/index.js
vendored
2
dist/index.js
vendored
File diff suppressed because one or more lines are too long
772
package-lock.json
generated
772
package-lock.json
generated
File diff suppressed because it is too large
Load diff
223
src/github.ts
223
src/github.ts
|
@ -13,6 +13,12 @@ export interface ReleaseAsset {
|
|||
size: number;
|
||||
}
|
||||
|
||||
export type GenerateReleaseNotesParams = Partial<
|
||||
Parameters<GitHub['rest']['repos']['generateReleaseNotes']['defaults']>[0]
|
||||
>;
|
||||
export type CreateReleaseParams = Partial<Parameters<GitHub['rest']['repos']['createRelease']>[0]>;
|
||||
export type UpdateReleaseParams = Partial<Parameters<GitHub['rest']['repos']['updateRelease']>[0]>;
|
||||
|
||||
export interface Release {
|
||||
id: number;
|
||||
upload_url: string;
|
||||
|
@ -29,36 +35,15 @@ export interface Release {
|
|||
export interface Releaser {
|
||||
getReleaseByTag(params: { owner: string; repo: string; tag: string }): Promise<{ data: Release }>;
|
||||
|
||||
createRelease(params: {
|
||||
owner: string;
|
||||
repo: string;
|
||||
tag_name: string;
|
||||
name: string;
|
||||
body: string | undefined;
|
||||
draft: boolean | undefined;
|
||||
prerelease: boolean | undefined;
|
||||
target_commitish: string | undefined;
|
||||
discussion_category_name: string | undefined;
|
||||
generate_release_notes: boolean | undefined;
|
||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
||||
}): Promise<{ data: Release }>;
|
||||
createRelease(params: CreateReleaseParams): Promise<{ data: Release }>;
|
||||
|
||||
updateRelease(params: {
|
||||
owner: string;
|
||||
repo: string;
|
||||
release_id: number;
|
||||
tag_name: string;
|
||||
target_commitish: string;
|
||||
name: string;
|
||||
body: string | undefined;
|
||||
draft: boolean | undefined;
|
||||
prerelease: boolean | undefined;
|
||||
discussion_category_name: string | undefined;
|
||||
generate_release_notes: boolean | undefined;
|
||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
||||
}): Promise<{ data: Release }>;
|
||||
updateRelease(params: UpdateReleaseParams): Promise<{ data: Release }>;
|
||||
|
||||
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }>;
|
||||
|
||||
getLatestTag(params: { owner: string; repo: string }): Promise<undefined | string>;
|
||||
|
||||
generateReleaseBody(params: GenerateReleaseNotesParams): Promise<string>;
|
||||
}
|
||||
|
||||
export class GitHubReleaser implements Releaser {
|
||||
|
@ -72,62 +57,59 @@ export class GitHubReleaser implements Releaser {
|
|||
repo: string;
|
||||
tag: string;
|
||||
}): Promise<{ data: Release }> {
|
||||
return this.github.rest.repos.getReleaseByTag(params);
|
||||
return this.github.rest.repos.getReleaseByTag(params as any);
|
||||
}
|
||||
|
||||
createRelease(params: {
|
||||
owner: string;
|
||||
repo: string;
|
||||
tag_name: string;
|
||||
name: string;
|
||||
body: string | undefined;
|
||||
draft: boolean | undefined;
|
||||
prerelease: boolean | undefined;
|
||||
target_commitish: string | undefined;
|
||||
discussion_category_name: string | undefined;
|
||||
generate_release_notes: boolean | undefined;
|
||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
||||
}): Promise<{ data: Release }> {
|
||||
if (
|
||||
typeof params.make_latest === 'string' &&
|
||||
!['true', 'false', 'legacy'].includes(params.make_latest)
|
||||
) {
|
||||
params.make_latest = undefined;
|
||||
createRelease(params: CreateReleaseParams): Promise<{ data: Release }> {
|
||||
return this.github.rest.repos.createRelease({
|
||||
...params,
|
||||
generate_release_notes: false,
|
||||
} as any);
|
||||
}
|
||||
|
||||
return this.github.rest.repos.createRelease(params);
|
||||
}
|
||||
|
||||
updateRelease(params: {
|
||||
owner: string;
|
||||
repo: string;
|
||||
release_id: number;
|
||||
tag_name: string;
|
||||
target_commitish: string;
|
||||
name: string;
|
||||
body: string | undefined;
|
||||
draft: boolean | undefined;
|
||||
prerelease: boolean | undefined;
|
||||
discussion_category_name: string | undefined;
|
||||
generate_release_notes: boolean | undefined;
|
||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
||||
}): Promise<{ data: Release }> {
|
||||
if (
|
||||
typeof params.make_latest === 'string' &&
|
||||
!['true', 'false', 'legacy'].includes(params.make_latest)
|
||||
) {
|
||||
params.make_latest = undefined;
|
||||
}
|
||||
|
||||
return this.github.rest.repos.updateRelease(params);
|
||||
updateRelease(params: UpdateReleaseParams): Promise<{ data: Release }> {
|
||||
return this.github.rest.repos.updateRelease({
|
||||
...params,
|
||||
generate_release_notes: false,
|
||||
} as any);
|
||||
}
|
||||
|
||||
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }> {
|
||||
const updatedParams = { per_page: 100, ...params };
|
||||
return this.github.paginate.iterator(
|
||||
this.github.rest.repos.listReleases.endpoint.merge(updatedParams),
|
||||
this.github.rest.repos.listReleases.endpoint.merge(updatedParams as any),
|
||||
);
|
||||
}
|
||||
|
||||
async getLatestTag(params: { owner: string; repo: string }): Promise<undefined | string> {
|
||||
try {
|
||||
const release = await this.github.rest.repos.getLatestRelease(params as any);
|
||||
|
||||
if (!release?.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
return release.data.tag_name;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async generateReleaseBody(params: GenerateReleaseNotesParams): Promise<string> {
|
||||
try {
|
||||
const { data } = await this.github.rest.repos.generateReleaseNotes(params as any);
|
||||
|
||||
if (!data.body) {
|
||||
throw new Error('No release body generated');
|
||||
}
|
||||
|
||||
return data.body;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const asset = (path: string): ReleaseAsset => {
|
||||
|
@ -215,8 +197,40 @@ export const release = async (
|
|||
config.input_tag_name ||
|
||||
(isTag(config.github_ref) ? config.github_ref.replace('refs/tags/', '') : '');
|
||||
|
||||
const previous_tag = config.input_previous_tag;
|
||||
const discussion_category_name = config.input_discussion_category_name;
|
||||
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,
|
||||
} as GenerateReleaseNotesParams)
|
||||
: '';
|
||||
|
||||
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 {
|
||||
const _release: Release | undefined = await findTagFromReleases(releaser, owner, repo, tag);
|
||||
|
||||
|
@ -250,7 +264,6 @@ export const release = async (
|
|||
target_commitish = existingRelease.target_commitish;
|
||||
}
|
||||
|
||||
const tag_name = tag;
|
||||
const name = config.input_name || existingRelease.name || tag;
|
||||
// revisit: support a new body-concat-strategy input for accumulating
|
||||
// body parts as a release gets updated. some users will likely want this while
|
||||
|
@ -258,18 +271,20 @@ export const release = async (
|
|||
// no one wants
|
||||
const workflowBody = releaseBody(config) || '';
|
||||
const existingReleaseBody = existingRelease.body || '';
|
||||
let body: string;
|
||||
|
||||
if (config.input_append_body && workflowBody && existingReleaseBody) {
|
||||
body = existingReleaseBody + '\n' + workflowBody;
|
||||
console.log('➕ Appending existing release body');
|
||||
body = body + existingReleaseBody + '\n' + workflowBody;
|
||||
} else {
|
||||
body = workflowBody || existingReleaseBody;
|
||||
console.log(`➕ Using ${workflowBody ? 'workflow body' : 'existing release body'}`);
|
||||
body = body + (workflowBody || existingReleaseBody);
|
||||
}
|
||||
|
||||
const draft = config.input_draft !== undefined ? config.input_draft : existingRelease.draft;
|
||||
const prerelease =
|
||||
config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
|
||||
|
||||
const make_latest = config.input_make_latest;
|
||||
const make_latest = config.input_make_latest!;
|
||||
|
||||
const release = await releaser.updateRelease({
|
||||
owner,
|
||||
|
@ -282,12 +297,55 @@ export const release = async (
|
|||
draft,
|
||||
prerelease,
|
||||
discussion_category_name,
|
||||
generate_release_notes,
|
||||
make_latest,
|
||||
});
|
||||
} as UpdateReleaseParams);
|
||||
return release.data;
|
||||
} catch (error) {
|
||||
if (error.status !== 404) {
|
||||
if (error.status === 404) {
|
||||
const tag_name = tag;
|
||||
const name = config.input_name || tag;
|
||||
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 prerelease = config.input_prerelease;
|
||||
const target_commitish = config.input_target_commitish;
|
||||
const make_latest = config.input_make_latest!;
|
||||
let commitMessage: string = '';
|
||||
if (target_commitish) {
|
||||
commitMessage = ` using commit "${target_commitish}"`;
|
||||
}
|
||||
console.log(`👩🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...`);
|
||||
try {
|
||||
let release = await releaser.createRelease({
|
||||
owner,
|
||||
repo,
|
||||
tag_name,
|
||||
name,
|
||||
body,
|
||||
draft,
|
||||
prerelease,
|
||||
target_commitish,
|
||||
discussion_category_name,
|
||||
make_latest,
|
||||
} as CreateReleaseParams);
|
||||
return release.data;
|
||||
} catch (error) {
|
||||
// presume a race with competing metrix runs
|
||||
console.log(
|
||||
`⚠️ GitHub release failed with status: ${
|
||||
error.status
|
||||
}\n${JSON.stringify(error.response.data.errors)}\nretrying... (${
|
||||
maxRetries - 1
|
||||
} retries remaining)`,
|
||||
);
|
||||
return release(config, releaser, maxRetries - 1);
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
`⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`,
|
||||
);
|
||||
|
@ -350,7 +408,7 @@ async function createRelease(
|
|||
const draft = config.input_draft;
|
||||
const prerelease = config.input_prerelease;
|
||||
const target_commitish = config.input_target_commitish;
|
||||
const make_latest = config.input_make_latest;
|
||||
const make_latest = config.input_make_latest!;
|
||||
let commitMessage: string = '';
|
||||
if (target_commitish) {
|
||||
commitMessage = ` using commit "${target_commitish}"`;
|
||||
|
@ -367,9 +425,8 @@ async function createRelease(
|
|||
prerelease,
|
||||
target_commitish,
|
||||
discussion_category_name,
|
||||
generate_release_notes,
|
||||
make_latest,
|
||||
});
|
||||
} as CreateReleaseParams);
|
||||
return release.data;
|
||||
} catch (error) {
|
||||
// presume a race with competing matrix runs
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { readFileSync, statSync } from 'fs';
|
||||
import * as glob from 'glob';
|
||||
import { statSync, readFileSync } from 'fs';
|
||||
|
||||
export interface Config {
|
||||
github_token: string;
|
||||
|
@ -22,6 +22,7 @@ export interface Config {
|
|||
input_generate_release_notes?: boolean;
|
||||
input_append_body?: boolean;
|
||||
input_make_latest: 'true' | 'false' | 'legacy' | undefined;
|
||||
input_previous_tag?: string;
|
||||
}
|
||||
|
||||
export const uploadUrl = (url: string): string => {
|
||||
|
@ -74,6 +75,7 @@ export const parseConfig = (env: Env): Config => {
|
|||
input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == 'true',
|
||||
input_append_body: env.INPUT_APPEND_BODY == 'true',
|
||||
input_make_latest: parseMakeLatest(env.INPUT_MAKE_LATEST),
|
||||
input_previous_tag: env.INPUT_PREVIOUS_TAG?.trim() || undefined,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue