Compare commits

...

15 Commits

Author SHA1 Message Date
83e65faee7 debug 2021-08-09 23:39:13 -04:00
c95b4533d0 debug 2021-08-09 23:36:44 -04:00
0eaa34fb9f debug 2021-08-09 23:33:55 -04:00
c54d2bad6b debug 2021-08-09 23:26:29 -04:00
4f0fb075a4 debug 2021-08-09 23:23:35 -04:00
815e458579 bump version 2021-08-09 09:28:34 -04:00
6ecde844e8 better error on release create failure (#143) 2021-08-09 09:26:48 -04:00
487fcd9442 bump version 2021-08-08 12:15:54 -04:00
8b7a7c0162 stringify errors object 2021-08-08 12:12:34 -04:00
6c87482fb9 fix upload err fmt 2021-08-08 12:10:40 -04:00
2956b0de81 document input 2021-08-08 11:59:31 -04:00
0aec73c6d6 document discussion link input 2021-08-08 11:57:10 -04:00
ce95482067 bump version + update changelog 2021-08-08 11:55:10 -04:00
2861dc8673 support linking to discussions (#136)
* support linking to discussions

* fmt

* wire param
2021-08-08 02:07:02 -04:00
dd98a235fd update readme 2021-08-08 00:47:44 -04:00
8 changed files with 136 additions and 40 deletions

View File

@ -1,3 +1,14 @@
## 0.1.11
- better error message on release create failed [#143](https://github.com/softprops/action-gh-release/pull/143)
## 0.1.10
- fixed error message formatting for file uploads
## 0.1.9
- add support for linking release to GitHub discussion [#136](https://github.com/softprops/action-gh-release/pull/136)
## 0.1.8 ## 0.1.8
- address recent warnings in assert upload api as well as introduce asset upload overrides, allowing for multiple runs for the same release with the same named asserts [#134](https://github.com/softprops/action-gh-release/pull/134) - address recent warnings in assert upload api as well as introduce asset upload overrides, allowing for multiple runs for the same release with the same named asserts [#134](https://github.com/softprops/action-gh-release/pull/134)

View File

@ -152,6 +152,9 @@ jobs:
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
with: with:
body_path: ${{ github.workspace }}-CHANGELOG.txt body_path: ${{ github.workspace }}-CHANGELOG.txt
# note you'll typically need to create a personal access token
# with permissions to create releases in the other repo
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
env: env:
GITHUB_REPOSITORY: my_gh_org/my_gh_repo GITHUB_REPOSITORY: my_gh_org/my_gh_repo
``` ```
@ -162,18 +165,20 @@ 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 | | `files` | String | Newline-delimited globs of paths to assets to upload for release |
| `name` | String | Name of the release. defaults to tag name | | `name` | String | Name of the release. defaults to tag name |
| `tag_name` | String | Name of a tag. defaults to `github.ref` | | `tag_name` | String | Name of a tag. defaults to `github.ref` |
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing | | `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. | | `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. |
| `token` | String | Secret GitHub Personal Access Token. Defaults to `${{ github.token }}` |
| `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) |
💡 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

@ -49,7 +49,8 @@ describe("util", () => {
input_files: [], input_files: [],
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
}) })
); );
}); });
@ -67,7 +68,8 @@ describe("util", () => {
input_files: [], input_files: [],
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
}) })
); );
}); });
@ -85,7 +87,8 @@ describe("util", () => {
input_files: [], input_files: [],
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
}) })
); );
}); });
@ -104,7 +107,8 @@ describe("util", () => {
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_fail_on_unmatched_files: false, input_fail_on_unmatched_files: false,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
}); });
}); });
@ -125,7 +129,30 @@ describe("util", () => {
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_fail_on_unmatched_files: false, input_fail_on_unmatched_files: false,
input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd" input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
input_discussion_category_name: undefined
}
);
});
it("supports discussion category names", () => {
assert.deepStrictEqual(
parseConfig({
INPUT_DISCUSSION_CATEGORY_NAME: "releases"
}),
{
github_ref: "",
github_repository: "",
github_token: "",
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: "releases"
} }
); );
}); });
@ -149,7 +176,8 @@ describe("util", () => {
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_fail_on_unmatched_files: false, input_fail_on_unmatched_files: false,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
} }
); );
}); });
@ -172,7 +200,8 @@ describe("util", () => {
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_fail_on_unmatched_files: false, input_fail_on_unmatched_files: false,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
} }
); );
}); });
@ -194,7 +223,8 @@ describe("util", () => {
input_name: undefined, input_name: undefined,
input_tag_name: undefined, input_tag_name: undefined,
input_fail_on_unmatched_files: false, input_fail_on_unmatched_files: false,
input_target_commitish: undefined input_target_commitish: undefined,
input_discussion_category_name: undefined
} }
); );
}); });

View File

@ -37,13 +37,16 @@ inputs:
target_commitish: target_commitish:
description: "Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA." description: "Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA."
required: false required: false
discussion_category_name:
description: "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. If there is already a discussion linked to the release, this parameter is ignored."
required: false
env: env:
"GITHUB_TOKEN": "As provided by Github Actions" "GITHUB_TOKEN": "As provided by Github Actions"
outputs: outputs:
url: url:
description: 'URL to the Release HTML Page' description: "URL to the Release HTML Page"
id: id:
description: 'Release ID' description: "Release ID"
upload_url: upload_url:
description: "URL for uploading assets to the release" description: "URL for uploading assets to the release"
runs: runs:

2
dist/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "action-gh-release", "name": "action-gh-release",
"version": "0.1.8", "version": "0.1.11",
"private": true, "private": true,
"description": "GitHub Action for creating GitHub Releases", "description": "GitHub Action for creating GitHub Releases",
"main": "lib/main.js", "main": "lib/main.js",

View File

@ -43,6 +43,7 @@ export interface Releaser {
draft: boolean | undefined; draft: boolean | undefined;
prerelease: boolean | undefined; prerelease: boolean | undefined;
target_commitish: string | undefined; target_commitish: string | undefined;
discussion_category_name: string | undefined;
}): Promise<{ data: Release }>; }): Promise<{ data: Release }>;
updateRelease(params: { updateRelease(params: {
@ -55,6 +56,7 @@ export interface Releaser {
body: string | undefined; body: string | undefined;
draft: boolean | undefined; draft: boolean | undefined;
prerelease: boolean | undefined; prerelease: boolean | undefined;
discussion_category_name: string | undefined;
}): Promise<{ data: Release }>; }): Promise<{ data: Release }>;
allReleases(params: { allReleases(params: {
@ -86,6 +88,7 @@ export class GitHubReleaser implements Releaser {
draft: boolean | undefined; draft: boolean | undefined;
prerelease: boolean | undefined; prerelease: boolean | undefined;
target_commitish: string | undefined; target_commitish: string | undefined;
discussion_category_name: string | undefined;
}): Promise<{ data: Release }> { }): Promise<{ data: Release }> {
return this.github.rest.repos.createRelease(params); return this.github.rest.repos.createRelease(params);
} }
@ -100,6 +103,7 @@ export class GitHubReleaser implements Releaser {
body: string | undefined; body: string | undefined;
draft: boolean | undefined; draft: boolean | undefined;
prerelease: boolean | undefined; prerelease: boolean | undefined;
discussion_category_name: string | undefined;
}): Promise<{ data: Release }> { }): Promise<{ data: Release }> {
return this.github.rest.repos.updateRelease(params); return this.github.rest.repos.updateRelease(params);
} }
@ -120,7 +124,7 @@ export const asset = (path: string): ReleaseAsset => {
name: basename(path), name: basename(path),
mime: mimeOrDefault(path), mime: mimeOrDefault(path),
size: lstatSync(path).size, size: lstatSync(path).size,
data: readFileSync(path) data: readFileSync(path),
}; };
}; };
@ -145,7 +149,7 @@ export const upload = async (
await github.rest.repos.deleteReleaseAsset({ await github.rest.repos.deleteReleaseAsset({
asset_id: currentAsset.id || 1, asset_id: currentAsset.id || 1,
owner, owner,
repo repo,
}); });
} }
console.log(`⬆️ Uploading ${name}...`); console.log(`⬆️ Uploading ${name}...`);
@ -155,15 +159,17 @@ export const upload = async (
headers: { headers: {
"content-length": `${size}`, "content-length": `${size}`,
"content-type": mime, "content-type": mime,
authorization: `token ${config.github_token}` authorization: `token ${config.github_token}`,
}, },
method: "POST", method: "POST",
body body,
}); });
const json = await resp.json(); const json = await resp.json();
if (resp.status !== 201) { if (resp.status !== 201) {
throw new Error( throw new Error(
"Failed to upload release asset ${name}. recieved status code ${resp.status}\n${json.message}\n${json.errors}" `Failed to upload release asset ${name}. recieved status code ${
resp.status
}\n${json.message}\n${JSON.stringify(json.errors)}`
); );
} }
return json; return json;
@ -185,25 +191,29 @@ export const release = async (
(isTag(config.github_ref) (isTag(config.github_ref)
? config.github_ref.replace("refs/tags/", "") ? config.github_ref.replace("refs/tags/", "")
: ""); : "");
const discussion_category_name = config.input_discussion_category_name;
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
if (config.input_draft) { if (config.input_draft) {
for await (const response of releaser.allReleases({ for await (const response of releaser.allReleases({
owner, owner,
repo repo,
})) { })) {
let release = response.data.find(release => release.tag_name === tag); let release = response.data.find((release) => release.tag_name === tag);
if (release) { if (release) {
return release; return release;
} }
} }
} }
console.log(`fetching existing release for tag ${owner}/${repo}/${tag}`);
let existingRelease = await releaser.getReleaseByTag({ let existingRelease = await releaser.getReleaseByTag({
owner, owner,
repo, repo,
tag tag,
}); });
console.log(`found release ${existingRelease.data.id}`);
const release_id = existingRelease.data.id; const release_id = existingRelease.data.id;
let target_commitish: string; let target_commitish: string;
@ -237,6 +247,21 @@ export const release = async (
? config.input_prerelease ? config.input_prerelease
: existingRelease.data.prerelease; : existingRelease.data.prerelease;
console.log(
`attemping update of release_id ${release_id} tag_name ${tag_name} target_commitish ${target_commitish} discussion_category_name ${discussion_category_name}`
);
console.log({
owner,
repo,
release_id,
tag_name,
target_commitish,
name,
body,
draft,
prerelease,
discussion_category_name,
});
const release = await releaser.updateRelease({ const release = await releaser.updateRelease({
owner, owner,
repo, repo,
@ -246,11 +271,15 @@ export const release = async (
name, name,
body, body,
draft, draft,
prerelease prerelease,
discussion_category_name,
}); });
console.log(`updated release ${release_id}`);
return release.data; return release.data;
} catch (error) { } catch (error) {
if (error.status === 404) { if (error.status === 404) {
console.log(`update failed with 404`);
console.log(JSON.stringify(error.response.data.errors));
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 body = releaseBody(config);
@ -264,6 +293,18 @@ export const release = async (
console.log( console.log(
`👩‍🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...` `👩‍🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...`
); );
console.log({
owner,
repo,
tag_name,
name,
body,
draft,
prerelease,
target_commitish,
discussion_category_name,
});
try { try {
let release = await releaser.createRelease({ let release = await releaser.createRelease({
owner, owner,
@ -273,7 +314,8 @@ export const release = async (
body, body,
draft, draft,
prerelease, prerelease,
target_commitish target_commitish,
discussion_category_name,
}); });
return release.data; return release.data;
} catch (error) { } catch (error) {
@ -281,7 +323,9 @@ export const release = async (
console.log( console.log(
`⚠️ GitHub release failed with status: ${ `⚠️ GitHub release failed with status: ${
error.status error.status
}, retrying... (${maxRetries - 1} retries remaining)` }\n${JSON.stringify(
error.response.data.errors
)}\nretrying... (${maxRetries - 1} retries remaining)`
); );
return release(config, releaser, maxRetries - 1); return release(config, releaser, maxRetries - 1);
} }

View File

@ -16,6 +16,7 @@ export interface Config {
input_prerelease?: boolean; input_prerelease?: boolean;
input_fail_on_unmatched_files?: boolean; input_fail_on_unmatched_files?: boolean;
input_target_commitish?: string; input_target_commitish?: string;
input_discussion_category_name?: string;
} }
export const uploadUrl = (url: string): string => { export const uploadUrl = (url: string): string => {
@ -41,8 +42,8 @@ export const parseInputFiles = (files: string): string[] => {
(acc, line) => (acc, line) =>
acc acc
.concat(line.split(",")) .concat(line.split(","))
.filter(pat => pat) .filter((pat) => pat)
.map(pat => pat.trim()), .map((pat) => pat.trim()),
[] []
); );
}; };
@ -62,14 +63,16 @@ export const parseConfig = (env: Env): Config => {
? env.INPUT_PRERELEASE == "true" ? env.INPUT_PRERELEASE == "true"
: undefined, : undefined,
input_fail_on_unmatched_files: env.INPUT_FAIL_ON_UNMATCHED_FILES == "true", input_fail_on_unmatched_files: env.INPUT_FAIL_ON_UNMATCHED_FILES == "true",
input_target_commitish: env.INPUT_TARGET_COMMITISH input_target_commitish: env.INPUT_TARGET_COMMITISH || undefined,
input_discussion_category_name:
env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
}; };
}; };
export const paths = (patterns: string[]): string[] => { export const paths = (patterns: string[]): string[] => {
return patterns.reduce((acc: string[], pattern: string): string[] => { return patterns.reduce((acc: string[], pattern: string): string[] => {
return acc.concat( return acc.concat(
glob.sync(pattern).filter(path => lstatSync(path).isFile()) glob.sync(pattern).filter((path) => lstatSync(path).isFile())
); );
}, []); }, []);
}; };
@ -77,7 +80,7 @@ export const paths = (patterns: string[]): string[] => {
export const unmatchedPatterns = (patterns: string[]): string[] => { export const unmatchedPatterns = (patterns: string[]): string[] => {
return patterns.reduce((acc: string[], pattern: string): string[] => { return patterns.reduce((acc: string[], pattern: string): string[] => {
return acc.concat( return acc.concat(
glob.sync(pattern).filter(path => lstatSync(path).isFile()).length == 0 glob.sync(pattern).filter((path) => lstatSync(path).isFile()).length == 0
? [pattern] ? [pattern]
: [] : []
); );