@action-class/core
v1.0.0
Published
Framework to write object oriented GitHub Actions
Downloads
15
Readme
@action-class/core
A library for creating GitHub Actions with a class-based approach.
This library simplifies the process of defining inputs, outputs, and other action properties, as well as handling the pre, main, and post steps of the action.
Installation
npm install @action-class/coreUsage
Create a new GitHub Action class by extending the constructor returned by the action call from '@action-class/core'.
Define action properties, inputs, and outputs in the action call argument.
To complete a runnable action you need to implement at least a main and optionally a pre, and a post method.
import { action, runAction } from '@action-class/core';
export class ExampleAction extends action({
name: 'name',
description: 'description',
author: 'author',
branding: {
color: 'orange',
icon: 'sunset',
},
inputs: {
// Define your inputs here
},
outputs: {
// Define your outputs here
},
}) {
// Define your class properties and constructor here
async pre(): Promise<void> {
// Define the pre step logic here
}
async main(): Promise<void> {
// Define the main step logic here
}
async post(): Promise<void> {
// Define the post step logic here
}
}
// Execute the action with the constructor arguments
runAction(TestAction, 'test');API
action(options: ActionOptions): constructor
The action function is a higher-order function that takes an ActionOptions object as an argument and returns a class
constructor. The ActionOptions object defines the properties, inputs, outputs, and branding for the action.
runAction(ActionClass: Class, ...args: any[]): Promise<void>
The runAction function takes a GitHub Action class and its constructor arguments, then executes the action.
This async function needs to be called at the end of the action file and not being awaited.
ActionOptions
name(optional): The name of the action. Defaults to the name from thepackage.json.description(optional): A short description of the action. Defaults to the description from thepackage.json.author(optional): The author of the action. Defaults to the author from thepackage.jsonif present.branding(optional): An object with branding properties for the action. See GitHub branding guidelines for valid values.inputs(optional): An object with the action inputs. See Inputs for more information.outputs(optional): An object with the action outputs. See Outputs for more information.
Inputs and Outputs
The inputs and outputs properties of the ActionOptions object define the inputs and outputs of your GitHub Action.
Inputs and outputs are defined using key-value pairs, where the key is the name of the input or output, and the value is
an object with specific properties.
Inputs
Inputs are defined in the inputs property of the ActionOptions object.
Each input is represented by an object with the following properties:
description: A string describing the input.required(optional): A boolean indicating whether the input is required. Defaults tofalse.defaultValue(optional): The default value for the input if it's not provided.trimWhitespace(optional): A boolean indicating whether to trim whitespace from the input value. Defaults totrue.validate(optional): A validation function for the input value. It takes the input value as an argument and returns eithertrueif the value is valid or an error message string if it's not.
As well as maximum of one of the following mutually exclusive properties:
type: The data type of the input. Can be one of 'string', 'number', 'boolean', or 'string[]'.converter: An object withfromInputandtoInputmethods for converting the input value from a string to a custom type and vice versa.
Outputs
Outputs are defined in the outputs property of the ActionOptions object. Each output is represented by an object
with the following properties:
description: A string describing the output.type(optional): The data type of the output. Can be one of 'string', 'number', 'boolean', or 'string[]'. Defaults to 'string'initValue(optional): The initial value for the output.converter(optional): A conversion function for the output value. It takes the output value as an argument and returns the converted value.
Example
export class ExampleAction extends action({
inputs: {
a: { description: 'description a', required: true },
b: { description: 'description b', trimWhitespace: false, type: 'string[]' },
c: { description: 'description c', defaultValue: true, type: 'boolean' },
d: {
description: 'description d',
defaultValue: 123,
validate: (value?: number) => (!!value && value > 0 ? true : 'Value must be greater than 0'),
},
e: { description: 'description e', type: 'number', deprecationMessage: 'e is deprecated' },
f: {
description: 'description f',
required: true,
converter: {
fromInput: (value: string) => JSON.parse(value) as Repo,
toInput: (value: Repo) => JSON.stringify(value),
},
},
g: {
description: 'description g',
required: true,
converter: {
fromInput: (value: string) => new Date(value),
toInput: (value: Date) => value.toISOString(),
},
},
},
outputs: {
a: { description: 'description a' },
b: { description: 'description b', type: 'boolean' },
c: { description: 'description c', type: 'number' },
d: { description: 'description d', converter: (value: Repo) => JSON.stringify(value) },
e: { description: 'description e', type: 'number', initValue: 123 },
},
}) {
/// rest of the action class
}All input values are evaluated before the main method is called and stored in a readonly inputs property of the
action class. The inputs property is an object with the same keys as the inputs property of the ActionOptions.
All validations for required inputs and input values are performed during this initialization and error messages are
produced if any of the validations fail. If an input marked as deprecated, but a value is supplied by the user, a
warning message will be produced.
All output values are stored in a readonly outputs property of the action class. The outputs property is an object
with the same keys as the outputs property of the ActionOptions. The outputs property is initialized with the
initValue property of each output, if present.
When a value is assigned to an output property, the value is converted to a string using the converter property of
the output, if present, and automatically send to back to the workflow as the actions output.
export class ExampleAction {
async main(): Promise<void> {
console.log(this.inputs);
this.outputs.a = this.inputs.a;
this.outputs.b = this.inputs.c;
this.outputs.c = this.inputs.d;
this.outputs.d = this.inputs.f;
console.log(JSON.stringify(this.outputs));
}
}Fluent API
Alternatively, you can use the ActionBuilder class to define your action. This class provides a fluent API for
defining the action properties, inputs, and outputs.
actionBuilder(): ActionBuilder
The actionBuilder function returns a new ActionBuilder instance.
ActionBuilder
The ActionBuilder class provides a fluent API for defining the action properties, inputs, and outputs.
name(name: string): ActionBuilder
Sets the name of the action.
description(description: string): ActionBuilder
Sets the description of the action.
author(author: string, email?: string): ActionBuilder
Sets the author of the action.
If the email argument is provided, it will be added to the author string using the format author <email>.
branding(color: ActionYmlBranding['color'], icon: ActionYmlBranding['icon']): ActionBuilder
Sets the branding properties of the action.
The color and icon arguments are restricted to the values defined in
GitHub branding guidelines.
input(name: string, description: string, options?: ActionInputOptions): ActionBuilder
Adds an input to the action. The options argument recognizes the same properties as described in Inputs
except for description.
If the options argument is not provided, the input will be defined as an optional string input.
inputs(inputs: { [name]: ActionInputOptions }): ActionBuilder
Adds multiple inputs to the action. The inputs argument is an object with the input names as keys and the input
options as values. This structure is equivalent to the inputs property of the ActionOptions object as described in
Inputs.
output(name: string, description: string, options?: ActionOutputOptions): ActionBuilder
Adds an output to the action. The options argument recognizes the same properties as described in Outputs
except for description.
If the options argument is not provided, the output will be of type string.
outputs(outputs: { [name]: ActionOutputOptions }): ActionBuilder
Adds multiple outputs to the action. The outputs argument is an object with the output names as keys and the output
options as values. This structure is equivalent to the outputs property of the ActionOptions object as described in
Outputs.
build(): ActionConstructor
Builds the action class and returns it.
Fluent Example
import { actionBuilder } from '@action-class/core';
export class ExampleAction extends actionBuilder()
.name('name')
.description('description')
.author('author')
.branding('orange', 'sunset')
.input('a', 'description a', { required: true })
.input('b', 'description b', { trimWhitespace: false, type: 'string[]' })
.input('c', 'description c')
.output('a', 'description a')
.output('b', 'description b', { type: 'boolean' })
.build() {
// Define your class properties and constructor here
async pre(): Promise<void> {
// Define the pre step logic here
}
async main(): Promise<void> {
// Define the main step logic here
}
async post(): Promise<void> {
// Define the post step logic here
}
}Generating the action.yml with generate-action-yml tool
generate-action-yml is a utility script provided by the '@action-class/action-yml' package.
It helps you automatically generate an action.yml file from your action class definition.
This ensures that your action's metadata stays in sync with the actual code, reducing the chance of errors and
inconsistencies.
To integrate the generate-action-yml tool into your action project, follow these steps:
Add a script to your
package.jsonfile that calls thegenerate-action-ymltool. You'll need to provide the action class name and, optionally, the paths to yourpackage.jsonand main JavaScript file.In your
package.json, add the following line under the scripts section:{ "scripts": { "action-yml": "generate-action-yml ExampleAction" } }Replace
ExampleActionwith the name of your action class.In this example, the
generate-action-ymltool will automatically locate yourpackage.jsonand main JavaScript file (using themainfield in yourpackage.json). If you need to specify custom paths, you can do so using the--package-json | -pand--action-js | -aoptions:{ "scripts": { "action-yml": "generate-action-yml -p <path-to-package-json> -a <path-to-action-js> ExampleAction" } }Replace
<path-to-package-json>with the path to yourpackage.jsonfile and<path-to-action-js>with the path to your main JavaScript file relative to the location of thepackage.json.Run the script to generate the
action.ymlfile:npm run action-ymlThis command will execute the
generate-action-ymlscript and create anaction.ymlfile in the directory of yourpackage.jsonfile. The generatedaction.ymlfile will contain the metadata from your action class, such as the name, description, inputs, and outputs.
With the generate-action-yml tool integrated into your action project, you can easily keep your action.yml file
up-to-date with your action class definition. Make sure to run the script every time you make changes to your action
class to ensure that the action.yml file remains consistent with your code.
License
This library is published under the MIT license.
