Compare commits

...

18 Commits

Author SHA1 Message Date
e234343e3e rebuild and fmt 2019-10-20 18:04:32 -04:00
c99850e5d1 back to minimal set 2019-10-20 18:03:30 -04:00
845942e04a setup integration test 2019-10-20 17:50:51 -04:00
1a522d88d8 Add the release HTML URL to outputs
This will allow subsequent actions to get access to the HTML URL for the
release created with this. Handy for composing multiple actions together
that are related to the release.

In my case I wanted to get the  URL into a slack message posted to the
team when a release is published.

The output can be referenced by using the `steps.release.ouput.url` in
the workflow yaml:

    - name: Release
      id: release
      uses: softprops/action-gh-release@v1
      with:
        name: "My Release"
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    - name: Slack
      uses: csexton/slack-message-action@v1
      with:
        message: New release posted at ${{ steps.release.outputs.url}}
2019-10-20 17:50:51 -04:00
2e7c800734 retry requests 2019-10-02 20:51:12 -04:00
6247f9299a update readme 2019-09-29 08:51:03 -04:00
5d578441a6 update changelog 2019-09-29 08:46:18 -04:00
42a316b84f sync body_path fmt 2019-09-29 08:45:47 -04:00
6ecc92f5ad bump version and update changelog 2019-09-29 08:25:51 -04:00
e7b71cc1a7 Merge pull request #23 from softprops/body_path_not_used
honor body_path input when provided.
2019-09-29 08:23:25 -04:00
f26a08096a commit latest build artifacts 2019-09-29 08:16:42 -04:00
ba42ad9139 honor body_path input when provided. fixes #22 2019-09-29 02:15:58 -04:00
07c8c20669 upgrade deps 2019-09-29 02:04:47 -04:00
00c56dd770 funding 2019-09-18 23:14:09 +09:00
50c843ac1c set a better example. dont refer to @master 2019-09-18 13:38:56 +09:00
ef036888ec update changelog 2019-09-18 13:26:04 +09:00
2758344bdf bump version 2019-09-18 13:25:04 +09:00
18d8be76a0 Merge pull request #19 from softprops/pre-releases
add support for prereleases
2019-09-17 23:35:48 +09:00
14 changed files with 188 additions and 33 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
ko_fi: softprops

View File

@ -1,3 +1,7 @@
## 0.1.3
* Fixed where `with: body_path` was not being used in generated GitHub releases
## 0.1.2
* Add support for merging draft releases [#16](https://github.com/softprops/action-gh-release/pull/16)
@ -22,7 +26,7 @@ GitHub actions inputs don't inherently support lists of things and one might lik
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
* Add support for prerelease annotated GitHub releases with the new input field `with.prerelease: true`
* Add support for prerelease annotated GitHub releases with the new input field `with.prerelease: true` [#19](https://github.com/softprops/action-gh-release/pull/19)
---

View File

@ -1,9 +1,28 @@
# action gh-release [![](https://github.com/softprops/action-gh-release/workflows/Main/badge.svg)](https://github.com/softprops/action-gh-release/actions)
<div align="center">
📦 :octocat:
</div>
<h1 align="center">
action gh-release
</h1>
> A GitHub Action for creating GitHub Releases on Linux, Windows, and OSX virtual environments
<p align="center">
A GitHub Action for creating GitHub Releases on Linux, Windows, and OSX virtual environments
</p>
<div align="center">
<img src="demo.png"/>
</div>
<div align="center">
<a href="https://github.com/softprops/action-gh-release/actions">
<img src="https://github.com/softprops/action-gh-release/workflows/Main/badge.svg"/>
</a>
</div>
<br />
![Screenshot](demo.png)
> **⚠️ Note:** To use this action, you must have access to the [GitHub Actions](https://github.com/features/actions) feature. GitHub Actions are currently only available in public beta. You can [apply for the GitHub Actions beta here](https://github.com/features/actions/signup/).
@ -28,7 +47,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
uses: actions/checkout@v1
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
@ -51,7 +70,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
uses: actions/checkout@v1
- name: Release
uses: softprops/action-gh-release@v1
env:
@ -80,7 +99,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
uses: actions/checkout@v1
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
@ -106,7 +125,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
uses: actions/checkout@v1
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
@ -140,7 +159,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
uses: actions/checkout@v1
- name: Generate Changelog
run: echo "# Good things have arrived" > ${{ github.workflow }}-CHANGELOG.txt
- name: Release

1
__tests__/release.txt Normal file
View File

@ -0,0 +1 @@
bar

View File

@ -1,4 +1,10 @@
import { isTag, paths, parseConfig, parseInputFiles } from "../src/util";
import {
releaseBody,
isTag,
paths,
parseConfig,
parseInputFiles
} from "../src/util";
import * as assert from "assert";
describe("util", () => {
@ -16,6 +22,56 @@ describe("util", () => {
);
});
});
describe("releaseBody", () => {
it("uses input body", () => {
assert.equal(
"foo",
releaseBody({
github_ref: "",
github_repository: "",
github_token: "",
input_body: "foo",
input_body_path: undefined,
input_draft: false,
input_prerelease: false,
input_files: [],
input_name: undefined
})
);
});
it("uses input body path", () => {
assert.equal(
"bar",
releaseBody({
github_ref: "",
github_repository: "",
github_token: "",
input_body: undefined,
input_body_path: "__tests__/release.txt",
input_draft: false,
input_prerelease: false,
input_files: [],
input_name: undefined
})
);
});
it("defaults to body when both body and body path are provided", () => {
assert.equal(
"foo",
releaseBody({
github_ref: "",
github_repository: "",
github_token: "",
input_body: "foo",
input_body_path: "__tests__/release.txt",
input_draft: false,
input_prerelease: false,
input_files: [],
input_name: undefined
})
);
});
});
describe("parseConfig", () => {
it("parses basic config", () => {
assert.deepStrictEqual(parseConfig({}), {

View File

@ -6,7 +6,7 @@ inputs:
body:
description: 'Note-worthy description of changes in release'
required: false
body-path:
body_path:
description: 'Path to load note-worthy description of changes in release from'
required: false
name:
@ -23,6 +23,9 @@ inputs:
required: false
env:
'GITHUB_TOKEN': 'As provided by Github Actions'
outputs:
url:
description: 'URL to the Release HTML Page'
runs:
using: 'node12'
main: 'lib/main.js'

View File

@ -16,6 +16,7 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("./util");
const fs_1 = require("fs");
const mime_1 = require("mime");
const path_1 = require("path");
@ -30,7 +31,8 @@ class GitHubReleaser {
return this.github.repos.createRelease(params);
}
allReleases(params) {
return this.github.paginate.iterator(this.github.repos.listReleases.endpoint.merge(params));
const updatedParams = Object.assign({ per_page: 100 }, params);
return this.github.paginate.iterator(this.github.repos.listReleases.endpoint.merge(updatedParams));
}
}
exports.GitHubReleaser = GitHubReleaser;
@ -98,7 +100,7 @@ exports.release = (config, releaser) => __awaiter(void 0, void 0, void 0, functi
try {
const tag_name = tag;
const name = config.input_name || tag;
const body = config.input_body;
const body = util_1.releaseBody(config);
const draft = config.input_draft;
const prerelease = config.input_prerelease;
console.log(`👩‍🏭 Creating new GitHub release for tag ${tag_name}...`);

View File

@ -21,7 +21,21 @@ function run() {
if (!util_1.isTag(config.github_ref)) {
throw new Error(`⚠️ GitHub Releases requires a tag`);
}
const gh = new github_2.GitHub(config.github_token);
github_2.GitHub.plugin(require("@octokit/plugin-throttling"));
const gh = new github_2.GitHub(config.github_token, {
onRateLimit: (retryAfter, options) => {
console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
if (options.request.retryCount === 0) {
// only retries once
console.log(`Retrying after ${retryAfter} seconds!`);
return true;
}
},
onAbuseLimit: (retryAfter, options) => {
// does not retry, only logs a warning
console.warn(`Abuse detected for request ${options.method} ${options.url}`);
}
});
let rel = yield github_1.release(config, new github_1.GitHubReleaser(gh));
if (config.input_files) {
util_1.paths(config.input_files).forEach((path) => __awaiter(this, void 0, void 0, function* () {
@ -29,6 +43,7 @@ function run() {
}));
}
console.log(`🎉 Release ready at ${rel.html_url}`);
core_1.setOutput("url", rel.html_url);
}
catch (error) {
core_1.setFailed(error.message);

View File

@ -9,6 +9,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
Object.defineProperty(exports, "__esModule", { value: true });
const glob = __importStar(require("glob"));
const fs_1 = require("fs");
exports.releaseBody = (config) => {
return (config.input_body ||
(config.input_body_path &&
fs_1.readFileSync(config.input_body_path).toString("utf8")));
};
exports.parseInputFiles = (files) => {
return files.split(/\r?\n/).reduce((acc, line) => acc
.concat(line.split(","))

34
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "action-gh-release",
"version": "0.1.1",
"version": "0.1.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -440,6 +440,14 @@
"universal-user-agent": "^2.0.3"
}
},
"@octokit/plugin-throttling": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-2.6.0.tgz",
"integrity": "sha512-E0xQrcD36sVEeBhut6j9nWX38vm/1LKMRSUqjvJ/mqGLXfHr4jYMsrR3I/nT2QC0eJL1/SKMt7zxOt7pZiFhDA==",
"requires": {
"bottleneck": "^2.15.3"
}
},
"@octokit/request": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.1.0.tgz",
@ -943,6 +951,11 @@
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz",
"integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A=="
},
"bottleneck": {
"version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -3437,6 +3450,12 @@
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"dev": true
},
"lodash.set": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
@ -4826,15 +4845,16 @@
"dev": true
},
"ts-jest": {
"version": "24.0.2",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.0.2.tgz",
"integrity": "sha512-h6ZCZiA1EQgjczxq+uGLXQlNgeg02WWJBbeT8j6nyIBRQdglqbvzDoHahTEIiS6Eor6x8mK6PfZ7brQ9Q6tzHw==",
"version": "24.1.0",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.1.0.tgz",
"integrity": "sha512-HEGfrIEAZKfu1pkaxB9au17b1d9b56YZSqz5eCVE8mX68+5reOvlM93xGOzzCREIov9mdH7JBG+s0UyNAqr0tQ==",
"dev": true,
"requires": {
"bs-logger": "0.x",
"buffer-from": "1.x",
"fast-json-stable-stringify": "2.x",
"json5": "2.x",
"lodash.memoize": "4.x",
"make-error": "1.x",
"mkdirp": "0.x",
"resolve": "1.x",
@ -4884,9 +4904,9 @@
}
},
"typescript": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz",
"integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==",
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
"dev": true
},
"typescript-formatter": {

View File

@ -1,6 +1,6 @@
{
"name": "action-gh-release",
"version": "0.1.1",
"version": "0.1.3",
"private": true,
"description": "GitHub Action for creating GitHub Releases",
"main": "lib/main.js",
@ -21,19 +21,20 @@
"dependencies": {
"@actions/core": "^1.1.0",
"@actions/github": "^1.1.0",
"@octokit/plugin-throttling": "^2.6.0",
"glob": "^7.1.4",
"mime": "^2.4.4"
},
"devDependencies": {
"@types/glob": "^7.1.1",
"@types/jest": "^24.0.13",
"@types/jest": "^24.0.18",
"@types/mime": "^2.0.1",
"@types/node": "^12.7.4",
"jest": "^24.8.0",
"jest-circus": "^24.7.1",
"jest": "^24.9.0",
"jest-circus": "^24.9.0",
"prettier": "1.18.2",
"ts-jest": "^24.0.2",
"typescript": "^3.5.1",
"ts-jest": "^24.1.0",
"typescript": "^3.6.3",
"typescript-formatter": "^7.2.2"
}
}

View File

@ -1,5 +1,5 @@
import { GitHub } from "@actions/github";
import { Config } from "./util";
import { Config, releaseBody } from "./util";
import { lstatSync, readFileSync } from "fs";
import { getType } from "mime";
import { basename } from "path";
@ -70,8 +70,9 @@ export class GitHubReleaser implements Releaser {
owner: string;
repo: string;
}): AsyncIterableIterator<{ data: Release[] }> {
const updatedParams = { per_page: 100, ...params };
return this.github.paginate.iterator(
this.github.repos.listReleases.endpoint.merge(params)
this.github.repos.listReleases.endpoint.merge(updatedParams)
);
}
}
@ -138,7 +139,7 @@ export const release = async (
try {
const tag_name = tag;
const name = config.input_name || tag;
const body = config.input_body;
const body = releaseBody(config);
const draft = config.input_draft;
const prerelease = config.input_prerelease;
console.log(`👩‍🏭 Creating new GitHub release for tag ${tag_name}...`);

View File

@ -1,6 +1,6 @@
import { paths, parseConfig, isTag } from "./util";
import { release, upload, GitHubReleaser } from "./github";
import { setFailed } from "@actions/core";
import { setFailed, setOutput } from "@actions/core";
import { GitHub } from "@actions/github";
import { env } from "process";
@ -10,7 +10,25 @@ async function run() {
if (!isTag(config.github_ref)) {
throw new Error(`⚠️ GitHub Releases requires a tag`);
}
const gh = new GitHub(config.github_token);
GitHub.plugin(require("@octokit/plugin-throttling"));
const gh = new GitHub(config.github_token, {
onRateLimit: (retryAfter, options) => {
console.warn(
`Request quota exhausted for request ${options.method} ${options.url}`
);
if (options.request.retryCount === 0) {
// only retries once
console.log(`Retrying after ${retryAfter} seconds!`);
return true;
}
},
onAbuseLimit: (retryAfter, options) => {
// does not retry, only logs a warning
console.warn(
`Abuse detected for request ${options.method} ${options.url}`
);
}
});
let rel = await release(config, new GitHubReleaser(gh));
if (config.input_files) {
paths(config.input_files).forEach(async path => {
@ -18,6 +36,7 @@ async function run() {
});
}
console.log(`🎉 Release ready at ${rel.html_url}`);
setOutput("url", rel.html_url);
} catch (error) {
setFailed(error.message);
}

View File

@ -1,5 +1,5 @@
import * as glob from "glob";
import { lstatSync } from "fs";
import { lstatSync, readFileSync } from "fs";
export interface Config {
github_token: string;
@ -14,6 +14,14 @@ export interface Config {
input_prerelease?: boolean;
}
export const releaseBody = (config: Config): string | undefined => {
return (
config.input_body ||
(config.input_body_path &&
readFileSync(config.input_body_path).toString("utf8"))
);
};
type Env = { [key: string]: string | undefined };
export const parseInputFiles = (files: string): string[] => {