Custom GitHub Action
This guide explains how to create a simple custom GitHub Action that can be used to build or deploy a containerized app. It includes a minimal repository layout, corrected example files, build instructions and a sample workflow.
Overview
- Goal: provide a reusable action that runs Node code packaged with ncc.
- Output: a repository containing action.yml, a main script (index.js), and package.json. Build with ncc to produce dist/index.js.
Prerequisites
- Node.js (for local development)
- npm
- Basic GitHub Actions knowledge
Repository layout
- action.yml # Action metadata and inputs
- index.js # Action implementation (source)
- package.json # Dependencies and build step
- dist/ # Built bundle (generated by npm run build)
Files
- action.yml — metadata and inputs
name: "deploy-container"
description: "Builds and deploys a container (example)"
inputs:
deploy:
description: "Whether to perform a deploy (true/false)"
required: false
default: "false"
image:
description: "Container image name (required if deploy=true)"
required: false
runs:
using: "node20"
main: "dist/index.js"
- index.js — minimal, robust implementation
// This is the source file; build with `npm run build` to produce dist/index.js
const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
try {
const deploy = core.getInput('deploy') === 'true';
const image = core.getInput('image');
core.info(`Action started. deploy=${deploy}, image=${image || '<none>'}`);
core.info(`Event: ${github.context.eventName}`);
// Validate inputs
if (deploy && !image) {
throw new Error('Input "image" is required when deploy is true.');
}
// ... perform your logic here ...
// Example: build image, push, call an API to deploy, etc.
// Use environment secrets via process.env and core.getInput for safe access.
// Simulate async operation
await new Promise((resolve) => setTimeout(resolve, 250));
core.info('Operation completed successfully.');
// Optionally set outputs:
core.setOutput('deployed', deploy ? 'true' : 'false');
} catch (err) {
// If the error is recoverable you can use core.warning
if (err && err.isWarn) {
core.warning(err.message || String(err));
} else {
core.setFailed(err.message || String(err));
}
}
}
run();
- package.json — dependencies and build script
{
"name": "deploy-container-action",
"version": "1.0.0",
"description": "A simple GitHub Action that builds/deploys a container",
"main": "index.js",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1"
},
"scripts": {
"build": "npx @vercel/ncc build index.js -o dist"
},
"devDependencies": {
"@vercel/ncc": "^0.38.3"
},
"license": "MIT"
}
Building the action
- Install deps:
npm ci - Build the bundle:
npm run build - Commit the resulting dist directory (or produce it in your CI pipeline).
Example workflow using the action
name: Example deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use custom action
uses: your-org/your-action-repo@v1
with:
deploy: "true"
image: "registry.example.com/your-image:latest"
# secrets can be set in repository settings and passed automatically to the action via environment variables
Tips & troubleshooting
- Keep secrets in GitHub Secrets (do not hard-code tokens).
- Test your action locally with act or by running the workflow in a test repository.
- Use core.info / core.warning / core.setFailed for clear logs and status.
Further reading
- GitHub Actions: creating actions: https://docs.github.com/actions/creating-actions
- Packaging JavaScript actions with ncc: https://www.npmjs.com/package/@vercel/ncc