Creating JavaScript Actions
1. Creating Node.js Action
| Property | Value | Description |
|---|---|---|
| name | "My Node.js Action" |
Name of the action as it appears in the UI |
| description | "A simple Node.js action example" |
Short description of what the action does |
| inputs | { greeting: { required: true, default: "Hello" } } |
Input parameters the action accepts |
| outputs | { message: { value: "${{ steps.my-step.outputs.message }}" } } |
Outputs that the action exposes |
| runs | { using: "node16", main: "dist/index.js" } |
How the action is executed |
Example: Node.js Action Structure
const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
const greeting = core.getInput('greeting');
const message = `${greeting}, World!`;
core.setOutput('message', message);
}
run().catch(error => core.setFailed(error.message));
Example: Action Manifest (action.yml)
name: 'My Node.js Action'
description: 'A simple Node.js action example'
inputs:
greeting:
required: true
default: 'Hello'
outputs:
message:
description: 'The generated message'
runs:
using: node16
main: dist/index.js
Note: Ensure that your action is built and transpiled to
dist/index.js before publishing.
2. Defining Action Entry Point
| Property | Value | Description |
|---|---|---|
| main | src/main.js |
Entry point for the JavaScript action |
| uses | actions/javascript@v1 |
Reference to the JavaScript action in the workflow |
Example: Defining Action Entry Point
const { getInput, setOutput } = require('@actions/core');
const input = getInput('input');
setOutput('output', `Processed: ${input}`);
3. Using Actions Toolkit
The Actions Toolkit is a JavaScript library that simplifies building GitHub Actions. It provides utilities for handling inputs, outputs, logging, and interacting with the GitHub Actions runtime.
| Feature | Description | Usage |
|---|---|---|
| core | Core utilities for input/output, logging, and environment handling. | const core = require('@actions/core'); |
| github | GitHub REST API client for interacting with GitHub. | const github = require('@actions/github'); |
| io | Utilities for file system operations. | const io = require('@actions/io'); |
Example: Reading Inputs
const core = require('@actions/core');
try {
const name = core.getInput('name');
core.setOutput('greeting', `Hello, ${name}!`);
} catch (error) {
core.setFailed(error.message);
}
Example: Setting Outputs
const core = require('@actions/core');
core.setOutput('result', 'success');
core.setOutput('timestamp', new Date().toISOString());
Example: Logging Messages
const core = require('@actions/core');
core.info('This is an info message');
core.warning('This is a warning');
core.error('This is an error');
Example: Using GitHub API
const { GitHub, getOctokitOptions } = require('@actions/github');
const core = require('@actions/core');
async function run() {
const token = core.getInput('token');
const octokit = new GitHub(token);
const { data } = await octokit.rest.repos.get({
owner: 'octocat',
repo: 'Hello-World'
});
core.setOutput('repo-name', data.name);
}
run().catch(error => core.setFailed(error.message));
4. Getting Action Inputs
| Input | Description | Type | Required |
|---|---|---|---|
| name | The name of the input parameter | string |
Yes |
| description | A description of the input parameter | string |
No |
| required | Whether the input parameter is required | boolean |
No |
| default | The default value if the input is not provided | string |
No |
| options | A list of valid values for the input parameter | array |
No |
Example: Using Inputs in a JavaScript Action
const core = require('@actions/core');
const input = core.getInput('my-input');
console.log(`Input value: ${input}`);
5. Setting Action Outputs
| Property | Description | Example |
|---|---|---|
| name | Name of the output | result |
| value | Value to set as output | ${{ steps.step1.outputs.result }} |
Example: Setting an Output in JavaScript Action
const core = require('@actions/core');
// Set output value
core.setOutput('result', 'success');
// Access output in workflow
// result: ${{ steps.myaction.outputs.result }}
Note: Outputs are available to subsequent steps in the same job.
6. Setting Failed Status
| Property | Description | Values |
|---|---|---|
| core.setFailed() | Sets the action's status to failed | string |
Example: Setting Failed Status
import { core } from '@actions/core';
try {
// Some operation that might fail
const result = performOperation();
if (!result) {
core.setFailed('Operation failed');
}
} catch (error) {
core.setFailed(error.message);
}
7. Logging Messages
Example: Using console.log in a JavaScript Action
const core = require('@actions/core');
function run() {
console.log("This is a debug message");
core.info("This is an info message");
core.warning("This is a warning message");
core.error("This is an error message");
}
run();
| Method | Description | Usage |
|---|---|---|
| core.info() | Logs an info-level message | core.info("Processing file...") |
| core.warning() | Logs a warning-level message | core.warning("File not found") |
| core.error() | Logs an error-level message | core.error("Failed to process") |
Note: Messages logged with
console.log are visible in the logs but not as structured messages. Use core.info, core.warning, and core.error for better visibility in the GitHub Actions UI.
Example: Logging with context
const core = require('@actions/core');
const fileName = 'data.json';
const fileSize = 1024;
core.info(`Processing file: ${fileName}`);
core.info(`File size: ${fileSize} bytes`);
if (fileSize > 512) {
core.warning(`File ${fileName} is larger than 512 bytes`);
}
8. Grouping Logs
GitHub Actions allows you to group related log output using the group and endgroup commands. This helps organize logs for better readability, especially in complex workflows.
| Command | Description | Usage |
|---|---|---|
| ::group::<name> | Starts a new log group with the specified name | ::group::Build Logs |
| ::endgroup:: | Ends the current log group | ::endgroup:: |
Example: Grouping Logs in a Workflow
name: Log Grouping Example
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Setup Node.js
uses: actions/checkout@v4
- name: Grouped Build Logs
run: |
echo "::group::Installing Dependencies"
npm install
echo "::endgroup::"
echo "::group::Running Tests"
npm test
echo "::endgroup::"
Note: Log groups are only visible in the GitHub Actions UI and do not affect the actual execution of the workflow.
9. Masking Values
When working with secrets or sensitive data in GitHub Actions, it's important to mask values to prevent them from being exposed in logs or outputs. GitHub Actions provides built-in masking capabilities to help secure sensitive information.
| Property | Description | Usage |
|---|---|---|
| log mask | Masks sensitive values in logs to prevent exposure | Use echo "::add-mask::<secret_value>" |
Example: Masking a Secret Value
echo "::add-mask::my-sensitive-token"
echo "Using token: my-sensitive-token"
Note: The mask is applied to the log output, so any sensitive values will be replaced with
*** in logs.
Warning: Masking only affects logs and does not prevent sensitive data from being used in workflows or stored in environment variables.
10. Using GitHub API
| Method | Endpoint | Description | Notes |
|---|---|---|---|
| GET | /repos/{owner}/{repo}/issues |
Retrieve issues from a repository | Supports pagination and filtering |
| POST | /repos/{owner}/{repo}/issues |
Create a new issue | Requires repo scope |
| PATCH | /repos/{owner}/{repo}/issues/{issue_number} |
Update an existing issue | Can update title, body, labels, etc. |
| GET | /repos/{owner}/{repo}/contents/{path} |
Retrieve file contents | Supports base64 decoding of content |
| PUT | /repos/{owner}/{repo}/contents/{path} |
Create or update a file | Requires repo scope and branch name |
Example: Create a new issue using GitHub API
const { Octokit } = require("@octokit/rest");
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
async function createIssue() {
const response = await octokit.rest.issues.create({
owner: "octocat",
repo: "Hello-World",
title: "Found a bug",
body: "I'm having a problem with this."
});
console.log("Issue created: " + response.data.html_url);
}
createIssue();
Note: The
GITHUB_TOKEN is automatically provided in GitHub Actions workflows and has appropriate permissions for the repository.
Warning: Be cautious with token permissions. Only grant the minimum required scopes to avoid security risks.
11. Compiling TypeScript
| Option | Values | Notes |
|---|---|---|
| main.ts | export async function run() { ... } |
Entry point for the action |
| tsconfig.json | { "compilerOptions": { "target": "ES2019", "module": "commonjs" } } |
Configuration for TypeScript compilation |
| package.json | { "scripts": { "build": "tsc" } } |
Build script to compile TypeScript |
Example: Compiling TypeScript Action
import { getInput, setOutput } from '@actions/core';
export async function run() {
const input = getInput('input');
setOutput('output', `Processed: ${input}`);
}
run().catch((err) => {
console.error(err);
});
Note: Ensure
node_modules is included in the action's distribution package for runtime dependencies.
Warning: Avoid using
async/await in the main function if not properly handling errors.
12. Handling Async Operations
| Operation | Description | Example |
|---|---|---|
| async/await | Use async/await for handling asynchronous operations in JavaScript actions | |
| Promise | Handle asynchronous operations using Promise syntax | |
Example: Using async/await in a GitHub Action
const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
try {
const token = core.getInput('token');
const octokit = new github.GitHub(token);
const { data: issues } = await octokit.issues.listForRepo({
owner: 'owner',
repo: 'repo',
state: 'open'
});
core.setOutput('issue-count', issues.length);
} catch (error) {
core.setFailed(error.message);
}
}
run();
Note: When writing JavaScript actions, always handle async operations properly to avoid hanging or incomplete workflows.
13. Publishing to Marketplace
| Field | Description | Required | Example |
|---|---|---|---|
| name | Action name displayed in the Marketplace | Yes | My JavaScript Action |
| description | Short description of the action's purpose | Yes | A simple action to greet users |
| icon | URL to an icon image (16x16px) | No | https://example.com/icon.png |
| categories | Array of categories for Marketplace search | No | ["utility", "notification"] |
| tags | Array of tags for Marketplace search | No | ["greeting", "hello"] |
Example: Publishing to Marketplace
name: My JavaScript Action
description: A simple action to greet users
icon: https://example.com/icon.png
categories:
- utility
- notification
tags:
- greeting
- hello
Note: The action must be published to a public repository to appear in the Marketplace.
Warning: Ensure all metadata fields are properly formatted to avoid Marketplace validation errors.