Support the make_latest option

This commit is contained in:
Ben Ramsey 2023-02-15 12:08:11 -06:00
parent d4e8205d7e
commit 23833f9b88
No known key found for this signature in database
GPG key ID: B02D97989C8C071B
6 changed files with 119 additions and 18 deletions

View file

@ -165,22 +165,23 @@ jobs:
The following are optional as `step.with` keys The following are optional as `step.with` keys
| Name | Type | Description | | Name | Type | Description |
| -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |----------------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `body` | String | Text communicating notable changes in this release | | `body` | String | Text communicating notable changes in this release |
| `body_path` | String | Path to load text communicating notable changes in this release | | `body_path` | String | Path to load text communicating notable changes in this release |
| `draft` | Boolean | Indicator of whether or not this release is a draft | | `draft` | Boolean | Indicator of whether or not this release is a draft |
| `prerelease` | Boolean | Indicator of whether or not is a prerelease | | `prerelease` | Boolean | Indicator of whether or not is a prerelease |
| `files` | String | Newline-delimited globs of paths to assets to upload for release | | `make_latest` | Boolean or `"legacy"` | Indicator of whether or not this is the latest release; defaults to `true`. `"legacy"` specifies that the latest release should be determined based on the release creation date and higher semantic version. Drafts and prereleases cannot be set as latest. |
| `name` | String | Name of the release. defaults to tag name | | `files` | String | Newline-delimited globs of paths to assets to upload for release |
| `tag_name` | String | Name of a tag. defaults to `github.ref` | | `name` | String | Name of the release. defaults to tag name |
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing | | `tag_name` | String | Name of a tag. defaults to `github.ref` |
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable | | `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing |
| `target_commitish` | String | Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Defaults to repository default branch. | | `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable |
| `token` | String | Secret GitHub Personal Access Token. Defaults to `${{ github.token }}` | | `target_commitish` | String | Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Defaults to repository default branch. |
| `discussion_category_name` | String | If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. For more information, see ["Managing categories for discussions in your repository."](https://docs.github.com/en/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository) | | `token` | String | Secret GitHub Personal Access Token. Defaults to `${{ github.token }}` |
| `generate_release_notes` | Boolean | 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. See the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information | | `discussion_category_name` | String | If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. For more information, see ["Managing categories for discussions in your repository."](https://docs.github.com/en/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository) |
| `append_body` | Boolean | Append to existing body instead of overwriting it | | `generate_release_notes` | Boolean | 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. See the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information |
| `append_body` | Boolean | Append to existing body instead of overwriting it |
💡 When providing a `body` and `body_path` at the same time, `body_path` will be 💡 When providing a `body` and `body_path` at the same time, `body_path` will be
attempted first, then falling back on `body` if the path can not be read from. attempted first, then falling back on `body` if the path can not be read from.

View file

@ -125,6 +125,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_make_latest: true,
} }
); );
}); });
@ -150,6 +151,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_make_latest: true,
} }
); );
}); });
@ -174,6 +176,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_make_latest: true,
} }
); );
}); });
@ -199,6 +202,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_make_latest: true,
} }
); );
}); });
@ -227,6 +231,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_make_latest: true,
} }
); );
}); });
@ -253,6 +258,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_make_latest: true,
} }
); );
}); });
@ -278,6 +284,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_make_latest: true,
} }
); );
}); });
@ -302,10 +309,46 @@ 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_make_latest: true,
} }
); );
}); });
describe("parses basic config with make_latest", () => {
describe.each([
["true", true],
["false", false],
["legacy", "legacy"],
])('with value "%s"', (value, expected) => {
it(`parses to ${expected}`, () => {
assert.deepStrictEqual(
parseConfig({
INPUT_MAKE_LATEST: value,
}),
{
github_ref: "",
github_repository: "",
github_token: "",
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
input_draft: undefined,
input_prerelease: undefined,
input_files: [],
input_name: undefined,
input_tag_name: undefined,
input_fail_on_unmatched_files: false,
input_target_commitish: undefined,
input_discussion_category_name: undefined,
input_generate_release_notes: false,
input_make_latest: expected,
}
);
});
});
});
}); });
describe("isTag", () => { describe("isTag", () => {
it("returns true for tags", async () => { it("returns true for tags", async () => {
assert.equal(isTag("refs/tags/foo"), true); assert.equal(isTag("refs/tags/foo"), true);

View file

@ -21,6 +21,9 @@ inputs:
prerelease: prerelease:
description: "Identify the release as a prerelease. Defaults to false" description: "Identify the release as a prerelease. Defaults to false"
required: false required: false
make_latest:
description: "Indicates whether this is the latest release. Defaults to true"
required: false
files: files:
description: "Newline-delimited list of path globs for asset files to upload" description: "Newline-delimited list of path globs for asset files to upload"
required: false required: false

4
dist/index.js vendored

File diff suppressed because one or more lines are too long

View file

@ -34,6 +34,11 @@ export interface Releaser {
tag: string; tag: string;
}): Promise<{ data: Release }>; }): Promise<{ data: Release }>;
getLatestRelease(params: {
owner: string;
repo: string;
}): Promise<{ data: Release }>;
createRelease(params: { createRelease(params: {
owner: string; owner: string;
repo: string; repo: string;
@ -45,6 +50,7 @@ export interface Releaser {
target_commitish: string | undefined; target_commitish: string | undefined;
discussion_category_name: string | undefined; discussion_category_name: string | undefined;
generate_release_notes: boolean | undefined; generate_release_notes: boolean | undefined;
make_latest: boolean | "legacy" | undefined;
}): Promise<{ data: Release }>; }): Promise<{ data: Release }>;
updateRelease(params: { updateRelease(params: {
@ -59,6 +65,7 @@ export interface Releaser {
prerelease: boolean | undefined; prerelease: boolean | undefined;
discussion_category_name: string | undefined; discussion_category_name: string | undefined;
generate_release_notes: boolean | undefined; generate_release_notes: boolean | undefined;
make_latest: boolean | "legacy" | undefined;
}): Promise<{ data: Release }>; }): Promise<{ data: Release }>;
allReleases(params: { allReleases(params: {
@ -81,6 +88,13 @@ export class GitHubReleaser implements Releaser {
return this.github.rest.repos.getReleaseByTag(params); return this.github.rest.repos.getReleaseByTag(params);
} }
getLatestRelease(params: {
owner: string;
repo: string;
}): Promise<{ data: Release }> {
return this.github.rest.repos.getLatestRelease(params);
}
createRelease(params: { createRelease(params: {
owner: string; owner: string;
repo: string; repo: string;
@ -92,6 +106,7 @@ export class GitHubReleaser implements Releaser {
target_commitish: string | undefined; target_commitish: string | undefined;
discussion_category_name: string | undefined; discussion_category_name: string | undefined;
generate_release_notes: boolean | undefined; generate_release_notes: boolean | undefined;
make_latest: boolean | "legacy" | undefined;
}): Promise<{ data: Release }> { }): Promise<{ data: Release }> {
return this.github.rest.repos.createRelease(params); return this.github.rest.repos.createRelease(params);
} }
@ -108,6 +123,7 @@ export class GitHubReleaser implements Releaser {
prerelease: boolean | undefined; prerelease: boolean | undefined;
discussion_category_name: string | undefined; discussion_category_name: string | undefined;
generate_release_notes: boolean | undefined; generate_release_notes: boolean | undefined;
make_latest: boolean | "legacy" | undefined;
}): Promise<{ data: Release }> { }): Promise<{ data: Release }> {
return this.github.rest.repos.updateRelease(params); return this.github.rest.repos.updateRelease(params);
} }
@ -219,6 +235,31 @@ export const release = async (
}); });
const release_id = existingRelease.data.id; const release_id = existingRelease.data.id;
let is_latest_release = false;
try {
let latestRelease = await releaser.getLatestRelease({
owner,
repo,
});
is_latest_release = release_id === latestRelease.data.id;
} catch (error) {
// If we couldn't find the latest release, then this is the latest release,
// as long as it's not a draft or a prerelease.
if (error.status === 404) {
is_latest_release =
config.input_draft !== true && config.input_prerelease !== true;
} else {
console.log(
`⚠️ Unexpected error fetching latest GitHub release for repository ${config.github_repository}: ${error}`
);
// Throw a new error without a status code to avoid creating a new
// release in the code that catches this error.
throw "Error fetching latest GitHub release";
}
}
let target_commitish: string; let target_commitish: string;
if ( if (
config.input_target_commitish && config.input_target_commitish &&
@ -255,6 +296,10 @@ export const release = async (
config.input_prerelease !== undefined config.input_prerelease !== undefined
? config.input_prerelease ? config.input_prerelease
: existingRelease.data.prerelease; : existingRelease.data.prerelease;
const make_latest =
config.input_make_latest !== undefined
? config.input_make_latest
: is_latest_release;
const release = await releaser.updateRelease({ const release = await releaser.updateRelease({
owner, owner,
@ -268,6 +313,7 @@ export const release = async (
prerelease, prerelease,
discussion_category_name, discussion_category_name,
generate_release_notes, generate_release_notes,
make_latest,
}); });
return release.data; return release.data;
} catch (error) { } catch (error) {
@ -277,6 +323,7 @@ export const release = async (
const body = releaseBody(config); const body = releaseBody(config);
const draft = config.input_draft; const draft = config.input_draft;
const prerelease = config.input_prerelease; const prerelease = config.input_prerelease;
const make_latest = config.input_make_latest;
const target_commitish = config.input_target_commitish; const target_commitish = config.input_target_commitish;
let commitMessage: string = ""; let commitMessage: string = "";
if (target_commitish) { if (target_commitish) {
@ -297,6 +344,7 @@ export const release = async (
target_commitish, target_commitish,
discussion_category_name, discussion_category_name,
generate_release_notes, generate_release_notes,
make_latest,
}); });
return release.data; return release.data;
} catch (error) { } catch (error) {

View file

@ -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_make_latest?: boolean | "legacy";
} }
export const uploadUrl = (url: string): string => { export const uploadUrl = (url: string): string => {
@ -70,6 +71,11 @@ 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_make_latest: env.INPUT_MAKE_LATEST
? env.INPUT_MAKE_LATEST === "legacy"
? "legacy"
: env.INPUT_MAKE_LATEST === "true"
: true,
}; };
}; };