diff --git a/__tests__/Action.test.ts b/__tests__/Action.test.ts index 3822436..fe24cd9 100644 --- a/__tests__/Action.test.ts +++ b/__tests__/Action.test.ts @@ -6,6 +6,8 @@ const createMock = jest.fn() const uploadMock = jest.fn() const artifactPath = 'a/path' +const artifactName = 'path' +const artifactData = Buffer.from('blob','utf-8') const body = 'body' const commit = 'commit' const contentType = "raw" @@ -35,14 +37,14 @@ describe("Action", () => { const action = createAction(true) createMock.mockResolvedValue({ data: { - assets_url: url + upload_url: url } }) await action.perform() expect(createMock).toBeCalledWith(tag, body, commit, draft, name) - expect(uploadMock).toBeCalledWith(url, contentLength, contentType, artifactPath, 'path') + expect(uploadMock).toBeCalledWith(url, contentLength, contentType, artifactData, 'path') }) it('throws error when create fails', async () => { @@ -64,7 +66,7 @@ describe("Action", () => { const action = createAction(true) createMock.mockResolvedValue({ data: { - assets_url: url + upload_url: url } }) uploadMock.mockRejectedValue("error") @@ -77,7 +79,7 @@ describe("Action", () => { } expect(createMock).toBeCalledWith(tag, body, commit, draft, name) - expect(uploadMock).toBeCalledWith(url, contentLength, contentType, artifactPath, 'path') + expect(uploadMock).toBeCalledWith(url, contentLength, contentType, artifactData, 'path') }) function createAction(hasArtifact: boolean): Action { @@ -96,6 +98,7 @@ describe("Action", () => { const MockInputs = jest.fn(() => { return { artifact: artifact, + artifactName: artifactName, artifactContentType: contentType, artifactContentLength: contentLength, body: body, @@ -103,7 +106,8 @@ describe("Action", () => { draft: draft, name: name, tag: tag, - token: token + token: token, + readArtifact: () => artifactData } }) const inputs = new MockInputs() diff --git a/__tests__/Inputs.test.ts b/__tests__/Inputs.test.ts index 1e7dd68..194b1ce 100644 --- a/__tests__/Inputs.test.ts +++ b/__tests__/Inputs.test.ts @@ -26,6 +26,12 @@ describe('Inputs', () => { inputs = new CoreInputs(context) }) + it('reads artifact', () => { + mockGetInput.mockReturnValue("a/path") + mockReadFileSync.mockReturnValue('file') + expect(inputs.artifact).toBe("a/path") + }) + it('returns artifact', () => { mockGetInput.mockReturnValue("a/path") expect(inputs.artifact).toBe("a/path") @@ -37,6 +43,11 @@ describe('Inputs', () => { expect(inputs.artifactContentLength).toBe(100) }) + it('returns artifactName', () => { + mockGetInput.mockReturnValue("a/path") + expect(inputs.artifactName).toBe("path") + }) + it('returns targetCommit', () => { mockGetInput.mockReturnValue("42") expect(inputs.commit).toBe("42") diff --git a/action.yml b/action.yml index 5663a97..2c87329 100644 --- a/action.yml +++ b/action.yml @@ -15,13 +15,16 @@ inputs: description: 'An optional body file for the release. This should be the path to the file' default: '' commit: - description: 'An optional commit reference. This will be used to create the tag if it doesn't exist.' + description: "An optional commit reference. This will be used to create the tag if it does not exist." + default: '' + draft: + description: "Optionally marks this release as a draft release. Set to true to enable." default: '' name: description: 'An optional name for the release. If this is omitted the tag will be used.' default: '' tag: - description: 'An optional tag for the release. If this is omitted the git ref will be used (if it's a tag).' + description: 'An optional tag for the release. If this is omitted the git ref will be used (if it is a tag).' default: '' token: description: 'The Github token.' @@ -29,4 +32,4 @@ inputs: default: '' runs: using: 'node12' - main: 'lib/main.js' + main: 'lib/Main.js' diff --git a/lib/Action.js b/lib/Action.js new file mode 100644 index 0000000..a504318 --- /dev/null +++ b/lib/Action.js @@ -0,0 +1,31 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const path_1 = require("path"); +const fs_1 = require("fs"); +class Action { + constructor(inputs, releases) { + this.inputs = inputs; + this.releases = releases; + } + perform() { + return __awaiter(this, void 0, void 0, function* () { + const createResult = yield this.releases.create(this.inputs.tag, this.inputs.body, this.inputs.commit, this.inputs.draft, this.inputs.name); + if (this.inputs.artifact) { + const artifactData = this.readArtifact(this.inputs.artifact); + yield this.releases.uploadArtifact(createResult.data.upload_url, this.inputs.artifactContentLength, this.inputs.artifactContentType, artifactData, path_1.basename(this.inputs.artifact)); + } + }); + } + readArtifact(path) { + return fs_1.readFileSync(path); + } +} +exports.Action = Action; diff --git a/lib/Inputs.js b/lib/Inputs.js new file mode 100644 index 0000000..8f04171 --- /dev/null +++ b/lib/Inputs.js @@ -0,0 +1,73 @@ +"use strict"; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const core = __importStar(require("@actions/core")); +const fs_1 = require("fs"); +class CoreInputs { + constructor(context) { + this.context = context; + } + get artifact() { + return core.getInput('artifact'); + } + get artifactContentType() { + const type = core.getInput('artifactContentType'); + if (type) { + return type; + } + return 'raw'; + } + get artifactContentLength() { + return fs_1.statSync(this.artifact).size; + } + get body() { + const body = core.getInput('body'); + if (body) { + return body; + } + const bodyFile = core.getInput('bodyFile'); + if (bodyFile) { + return this.stringFromFile(bodyFile); + } + return ''; + } + get commit() { + return core.getInput('commit'); + } + get draft() { + const draft = core.getInput('draft'); + return draft == 'true'; + } + get name() { + const name = core.getInput('name'); + if (name) { + return name; + } + return this.tag; + } + get tag() { + const tag = core.getInput('tag'); + if (tag) { + return tag; + } + const ref = this.context.ref; + const tagPath = "refs/tags/"; + if (ref && ref.startsWith(tagPath)) { + return ref.substr(tagPath.length, ref.length); + } + throw Error("No tag found in ref or input!"); + } + get token() { + return core.getInput('token', { required: true }); + } + stringFromFile(path) { + return fs_1.readFileSync(path, 'utf-8'); + } +} +exports.CoreInputs = CoreInputs; diff --git a/lib/main.js b/lib/Main.js similarity index 71% rename from lib/main.js rename to lib/Main.js index 5b22f78..f08e5d1 100644 --- a/lib/main.js +++ b/lib/Main.js @@ -17,25 +17,26 @@ var __importStar = (this && this.__importStar) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const github = __importStar(require("@actions/github")); const core = __importStar(require("@actions/core")); -const releases_1 = require("./releases"); +const Inputs_1 = require("./Inputs"); +const Releases_1 = require("./Releases"); +const Action_1 = require("./Action"); function run() { return __awaiter(this, void 0, void 0, function* () { try { - const token = core.getInput('token'); - const context = github.context; - const git = new github.GitHub(token); - const releases = new releases_1.Releases(context, git); - yield releases.create() - .catch(error => { - core.warning(error); - }) - .then(response => { - core.warning(`response: ${response}`); - }); + const action = createAction(); + yield action.perform(); } catch (error) { core.setFailed(error.message); } }); } +function createAction() { + const token = core.getInput('token'); + const context = github.context; + const git = new github.GitHub(token); + const releases = new Releases_1.GithubReleases(context, git); + const inputs = new Inputs_1.CoreInputs(context); + return new Action_1.Action(inputs, releases); +} run(); diff --git a/lib/releases.js b/lib/Releases.js similarity index 58% rename from lib/releases.js rename to lib/Releases.js index 7f5e68d..ef3b4ad 100644 --- a/lib/releases.js +++ b/lib/Releases.js @@ -8,22 +8,36 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -class Releases { +class GithubReleases { constructor(context, git) { this.context = context; this.git = git; } - create() { + create(tag, body, commitHash, draft, name) { return __awaiter(this, void 0, void 0, function* () { return this.git.repos.createRelease({ - name: "Test release", - draft: true, + body: body, + name: name, + draft: draft, owner: this.context.repo.owner, repo: this.context.repo.repo, - target_commitish: "master", - tag_name: "0.0.666" + target_commitish: commitHash, + tag_name: tag + }); + }); + } + uploadArtifact(assetUrl, contentLength, contentType, file, name) { + return __awaiter(this, void 0, void 0, function* () { + return this.git.repos.uploadReleaseAsset({ + url: assetUrl, + headers: { + "content-length": contentLength, + "content-type": contentType + }, + file: file, + name: name }); }); } } -exports.Releases = Releases; +exports.GithubReleases = GithubReleases; diff --git a/src/Action.ts b/src/Action.ts index f3d18ef..9881e21 100644 --- a/src/Action.ts +++ b/src/Action.ts @@ -1,6 +1,7 @@ import { Inputs } from "./Inputs"; import { Releases } from "./Releases"; import { basename } from "path"; +import { readFileSync } from "fs"; export class Action { private inputs: Inputs @@ -21,12 +22,13 @@ export class Action { ) if (this.inputs.artifact) { + const artifactData = this.inputs.readArtifact() await this.releases.uploadArtifact( - createResult.data.assets_url, + createResult.data.upload_url, this.inputs.artifactContentLength, this.inputs.artifactContentType, - this.inputs.artifact, - basename(this.inputs.artifact) + artifactData, + this.inputs.artifactName ) } } diff --git a/src/Inputs.ts b/src/Inputs.ts index c7a2d29..d3300e7 100644 --- a/src/Inputs.ts +++ b/src/Inputs.ts @@ -1,9 +1,11 @@ import * as core from '@actions/core'; import { Context } from "@actions/github/lib/context"; import { readFileSync, statSync } from 'fs'; +import { basename } from 'path'; export interface Inputs { readonly artifact: string + readonly artifactName: string readonly artifactContentType: string readonly artifactContentLength: number readonly body: string @@ -12,6 +14,8 @@ export interface Inputs { readonly name: string readonly tag: string readonly token: string + + readArtifact(): Buffer } export class CoreInputs implements Inputs { @@ -25,6 +29,10 @@ export class CoreInputs implements Inputs { return core.getInput('artifact') } + get artifactName(): string { + return basename(this.artifact) + } + get artifactContentType(): string { const type = core.getInput('artifactContentType') if(type) { @@ -89,6 +97,10 @@ export class CoreInputs implements Inputs { return core.getInput('token', { required: true }) } + readArtifact(): Buffer { + return readFileSync(this.artifact) + } + stringFromFile(path: string): string { return readFileSync(path, 'utf-8') } diff --git a/src/Releases.ts b/src/Releases.ts index 193ac57..4b92cca 100644 --- a/src/Releases.ts +++ b/src/Releases.ts @@ -15,7 +15,7 @@ export interface Releases { assetUrl: string, contentLength: number, contentType: string, - file: string, + file: string | object, name: string ): Promise> } @@ -51,7 +51,7 @@ export class GithubReleases implements Releases{ assetUrl: string, contentLength: number, contentType: string, - file: string, + file: string | object, name: string ): Promise> { return this.git.repos.uploadReleaseAsset({