1
0
Fork 0

Add requiredEnv config for Toolkit

pull/1/head
Jonathan Clem 2019-04-19 17:27:40 -04:00
parent 4381229e80
commit 4e7d45abe0
No known key found for this signature in database
GPG Key ID: 48C5B22E9FD6E80F
2 changed files with 90 additions and 33 deletions

View File

@ -1,6 +1,9 @@
import {Signale} from 'signale'
import {ExitCode} from '../src/exit'
import {Toolkit} from '../src/toolkit' import {Toolkit} from '../src/toolkit'
describe('Toolkit', () => { describe('Toolkit', () => {
describe('.run', () => {
it('runs a sync function', async () => { it('runs a sync function', async () => {
const cb = jest.fn(() => true) const cb = jest.fn(() => true)
const value = await Toolkit.run(cb) const value = await Toolkit.run(cb)
@ -26,4 +29,22 @@ describe('Toolkit', () => {
expect(exitFailure).toHaveBeenCalledWith(err) expect(exitFailure).toHaveBeenCalledWith(err)
}) })
})
it('asserts required keys are present', async () => {
const missingKey = '__DOES_NOT_EXIST__'
Reflect.deleteProperty(process.env, missingKey)
const logger = new Signale()
logger.fatal = jest.fn()
jest.spyOn(process, 'exit').mockImplementation()
new Toolkit({logger, requiredEnv: [missingKey]})
expect(process.exit).toHaveBeenCalledWith(ExitCode.Failure)
expect(logger.fatal)
.toHaveBeenCalledWith(`The following environment variables are required for this action to run:
- __DOES_NOT_EXIST__`)
})
}) })

View File

@ -3,6 +3,23 @@ import {Exit} from './exit'
export type ActionFn = (tools: Toolkit) => unknown export type ActionFn = (tools: Toolkit) => unknown
/**
* Options used to customize an instance of [[Toolkit]]
*/
export type ToolkitOptions = {
/**
* A custom Signale instance to use
*/
logger?: Signale
/**
* A list of environment variable names this action requires in order to run
*
* If any of them are missing, the action will fail and log the missing keys.
*/
requiredEnv?: string[]
}
/** /**
* A set of tools for the Actions runtime * A set of tools for the Actions runtime
*/ */
@ -13,8 +30,8 @@ export class Toolkit {
* If an error occurs, the error will be logged and the action will exit as a * If an error occurs, the error will be logged and the action will exit as a
* failure. * failure.
*/ */
static async run(func: ActionFn) { static async run(func: ActionFn, opts?: ToolkitOptions) {
const tools = new Toolkit() const tools = new Toolkit(opts)
try { try {
const ret = func(tools) const ret = func(tools)
@ -27,26 +44,45 @@ export class Toolkit {
/** /**
* A logger for the toolkit, an instance of [Signale](https://github.com/klaussinani/signale) * A logger for the toolkit, an instance of [Signale](https://github.com/klaussinani/signale)
*/ */
readonly logger: Signale & LoggerFunc = this.wrapLogger( readonly logger: Signale & LoggerFunc
new Signale({
config: {
underlineLabel: false
}
})
)
/** /**
* A wrapper around an instance of [[Exit]] * A wrapper around an instance of [[Exit]]
*/ */
readonly exit: Exit = new Exit(this.logger) readonly exit: Exit
/** /**
* The authentication token for the GitHub API * The authentication token for the GitHub API
*/ */
readonly token: string = process.env.GITHUB_TOKEN || '' readonly token: string = process.env.GITHUB_TOKEN || ''
constructor(opts: ToolkitOptions = {}) {
const logger = opts.logger || new Signale({config: {underlineLabel: false}})
this.logger = this.wrapLogger(logger)
this.exit = new Exit(this.logger)
if (opts.requiredEnv) {
this.checkRequiredEnv(opts.requiredEnv)
}
}
/** /**
* Wrap a Signale logger so that its a callable class * Ensure that the given keys are in the environment.
*/
private checkRequiredEnv(keys: string[]) {
const missingEnv = keys.filter(key => !process.env.hasOwnProperty(key))
if (missingEnv.length === 0) return
const list = missingEnv.map(key => `- ${key}`).join('\n')
this.exit.failure(
`The following environment variables are required for this action to run:\n${list}`
)
}
/**
* Wrap a Signale logger so that its a callable class.
*/ */
private wrapLogger(logger: Signale) { private wrapLogger(logger: Signale) {
// Create a callable function // Create a callable function