mirror of https://github.com/actions/toolkit
Add Toolkit class w/logging & exits
parent
d90e9d7582
commit
39f7667028
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
packages/*/node_modules/
|
||||
packages/*/lib/
|
|
@ -1434,6 +1434,15 @@
|
|||
"integrity": "sha512-/OMMBnjVtDuwX1tg2pkYVSqRIDSmNTnvVvmvP/2xiMAAWf4a5+JozrApCrO4WCAILmXVxfNoQ3E+0HJbNpFVGg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/signale": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/signale/-/signale-1.2.1.tgz",
|
||||
"integrity": "sha512-mV6s2VgcBC16Jb+1EwulgRrrZBT93V4JCILkNPg31rvvSK6LRQQGU8R/SUivgHjDZ5LJZu/yL2kMF8j85YQTnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/stack-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import {Signale} from 'signale'
|
||||
import {Exit, ExitCode} from '../src/exit'
|
||||
|
||||
describe('Exit', () => {
|
||||
const tests: [keyof Exit, keyof Signale, ExitCode][] = [
|
||||
['success', 'success', ExitCode.Success],
|
||||
['neutral', 'info', ExitCode.Neutral],
|
||||
['failure', 'fatal', ExitCode.Failure]
|
||||
]
|
||||
|
||||
describe.each(tests)('%s', (method, log, code) => {
|
||||
let logger: Signale
|
||||
let exit: Exit
|
||||
|
||||
beforeEach(() => {
|
||||
// Create a logger to mock
|
||||
logger = new Signale()
|
||||
logger.success = jest.fn()
|
||||
logger.info = jest.fn()
|
||||
logger.fatal = jest.fn()
|
||||
|
||||
process.exit = jest.fn<never, [number]>()
|
||||
exit = new Exit(logger)
|
||||
})
|
||||
|
||||
it('exits with the expected code', () => {
|
||||
exit[method]()
|
||||
expect(process.exit).toHaveBeenCalledWith(code)
|
||||
})
|
||||
|
||||
it('logs the expected message', () => {
|
||||
exit[method]('hello')
|
||||
expect(logger[log]).toHaveBeenCalledWith('hello')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,7 +1,29 @@
|
|||
import {github} from '../src/toolkit'
|
||||
import {Toolkit} from '../src/toolkit'
|
||||
|
||||
describe('@actions/toolkit', () => {
|
||||
it('needs tests', () => {
|
||||
expect(github()).toBe(true)
|
||||
describe('Toolkit', () => {
|
||||
it('runs a sync function', async () => {
|
||||
const cb = jest.fn(() => true)
|
||||
const value = await Toolkit.run(cb)
|
||||
expect(cb).toHaveBeenCalledWith(expect.any(Toolkit))
|
||||
expect(value).toBe(true)
|
||||
})
|
||||
|
||||
it('runs an async function', async () => {
|
||||
const cb = jest.fn(async () => true)
|
||||
const value = await Toolkit.run(cb)
|
||||
expect(cb).toHaveBeenCalledWith(expect.any(Toolkit))
|
||||
expect(value).toBe(true)
|
||||
})
|
||||
|
||||
it('logs and fails when an error occurs', async () => {
|
||||
const err = new Error()
|
||||
const exitFailure = jest.fn()
|
||||
|
||||
await Toolkit.run(async tk => {
|
||||
tk.exit.failure = exitFailure
|
||||
throw err
|
||||
})
|
||||
|
||||
expect(exitFailure).toHaveBeenCalledWith(err)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -47,6 +47,14 @@
|
|||
"url-template": "^2.0.8"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"atob-lite": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
|
||||
|
@ -62,6 +70,29 @@
|
|||
"resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
|
||||
"integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
|
@ -92,6 +123,19 @@
|
|||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"execa": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
|
||||
|
@ -106,6 +150,22 @@
|
|||
"strip-eof": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"figures": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
|
||||
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
|
||||
"requires": {
|
||||
"escape-string-regexp": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"find-up": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
|
||||
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
|
||||
"requires": {
|
||||
"locate-path": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||
|
@ -114,6 +174,21 @@
|
|||
"pump": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.1.15",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
|
||||
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
|
@ -137,6 +212,31 @@
|
|||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"parse-json": "^4.0.0",
|
||||
"pify": "^3.0.0",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
|
||||
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
|
||||
"requires": {
|
||||
"p-locate": "^2.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
|
@ -202,11 +302,60 @@
|
|||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
|
||||
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
|
||||
"requires": {
|
||||
"p-try": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
|
||||
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
|
||||
"requires": {
|
||||
"p-limit": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
|
||||
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"requires": {
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
|
||||
},
|
||||
"path-key": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
|
||||
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
|
||||
},
|
||||
"pkg-conf": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
|
||||
"integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=",
|
||||
"requires": {
|
||||
"find-up": "^2.0.0",
|
||||
"load-json-file": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
|
@ -239,11 +388,34 @@
|
|||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
||||
},
|
||||
"signale": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz",
|
||||
"integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==",
|
||||
"requires": {
|
||||
"chalk": "^2.3.2",
|
||||
"figures": "^2.0.0",
|
||||
"pkg-conf": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
|
||||
},
|
||||
"strip-eof": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-2.0.3.tgz",
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
"url": "https://github.com/actions/toolkit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/rest": "^16.25.0"
|
||||
}
|
||||
"@octokit/rest": "^16.25.0",
|
||||
"signale": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import {Signale} from 'signale'
|
||||
|
||||
/**
|
||||
* The code to exit an action
|
||||
*/
|
||||
export enum ExitCode {
|
||||
Success = 0,
|
||||
Failure = 1,
|
||||
Neutral = 78
|
||||
}
|
||||
|
||||
// TODO: These exit codes may not behave as expected on the new runtime, due to
|
||||
// complexities of async logging and sync exiting.
|
||||
|
||||
/**
|
||||
* A class that wraps some basic methods of exiting from an action
|
||||
*/
|
||||
export class Exit {
|
||||
constructor(private readonly logger: Signale) {}
|
||||
|
||||
/**
|
||||
* Stop the action with a "success" status.
|
||||
*/
|
||||
success(message?: string) {
|
||||
if (message) this.logger.success(message)
|
||||
process.exit(ExitCode.Success)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the action with a "neutral" status.
|
||||
*/
|
||||
neutral(message?: string) {
|
||||
if (message) this.logger.info(message)
|
||||
process.exit(ExitCode.Neutral)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the action with a "failed" status.
|
||||
*/
|
||||
failure(message?: string) {
|
||||
if (message) this.logger.fatal(message)
|
||||
process.exit(ExitCode.Failure)
|
||||
}
|
||||
}
|
|
@ -1,3 +1,55 @@
|
|||
export function github() {
|
||||
return true
|
||||
import {LoggerFunc, Signale} from 'signale'
|
||||
import {Exit} from './exit'
|
||||
|
||||
export type ActionFn = (tools: Toolkit) => unknown
|
||||
|
||||
/**
|
||||
* A set of tools for the Actions runtime
|
||||
*/
|
||||
export class Toolkit {
|
||||
/**
|
||||
* Run an asynchronous function that accepts a toolkit as its argument.
|
||||
*
|
||||
* If an error occurs, the error will be logged and the action will exit as a
|
||||
* failure.
|
||||
*/
|
||||
static async run(func: ActionFn) {
|
||||
const tools = new Toolkit()
|
||||
|
||||
try {
|
||||
const ret = func(tools)
|
||||
return ret instanceof Promise ? await ret : ret
|
||||
} catch (err) {
|
||||
tools.exit.failure(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A logger for the toolkit, an instance of [Signale](https://github.com/klaussinani/signale)
|
||||
*/
|
||||
readonly logger: Signale & LoggerFunc = this.wrapLogger(
|
||||
new Signale({
|
||||
config: {
|
||||
underlineLabel: false
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* A wrapper around an instance of [[Exit]]
|
||||
*/
|
||||
readonly exit: Exit = new Exit(this.logger)
|
||||
|
||||
/**
|
||||
* Wrap a Signale logger so that its a callable class
|
||||
*/
|
||||
private wrapLogger(logger: Signale) {
|
||||
// Create a callable function
|
||||
const fn = logger.info.bind(logger)
|
||||
// Add the log methods onto the function
|
||||
const wrapped = Object.assign(fn, logger)
|
||||
// Clone the prototype
|
||||
Object.setPrototypeOf(wrapped, logger)
|
||||
return wrapped
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue