mirror of https://github.com/actions/toolkit
Add requiredEnv config for Toolkit
parent
4381229e80
commit
4e7d45abe0
|
@ -1,29 +1,50 @@
|
||||||
|
import {Signale} from 'signale'
|
||||||
|
import {ExitCode} from '../src/exit'
|
||||||
import {Toolkit} from '../src/toolkit'
|
import {Toolkit} from '../src/toolkit'
|
||||||
|
|
||||||
describe('Toolkit', () => {
|
describe('Toolkit', () => {
|
||||||
it('runs a sync function', async () => {
|
describe('.run', () => {
|
||||||
const cb = jest.fn(() => true)
|
it('runs a sync function', async () => {
|
||||||
const value = await Toolkit.run(cb)
|
const cb = jest.fn(() => true)
|
||||||
expect(cb).toHaveBeenCalledWith(expect.any(Toolkit))
|
const value = await Toolkit.run(cb)
|
||||||
expect(value).toBe(true)
|
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)
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
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__`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue