@action-class/core
v1.0.0
Published
Framework to write object oriented GitHub Actions
Downloads
2
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/core
Usage
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.json
if 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 eithertrue
if 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 withfromInput
andtoInput
methods 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-ym
l 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.json
file that calls thegenerate-action-yml
tool. You'll need to provide the action class name and, optionally, the paths to yourpackage.json
and main JavaScript file.In your
package.json
, add the following line under the scripts section:{ "scripts": { "action-yml": "generate-action-yml ExampleAction" } }
Replace
ExampleAction
with the name of your action class.In this example, the
generate-action-yml
tool will automatically locate yourpackage.json
and main JavaScript file (using themain
field in yourpackage.json
). If you need to specify custom paths, you can do so using the--package-json | -p
and--action-js | -a
options:{ "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.json
file 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.yml
file:npm run action-yml
This command will execute the
generate-action-yml
script and create anaction.yml
file in the directory of yourpackage.json
file. The generatedaction.yml
file 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.