DevOps / GitHub Actions Interview Questions
How do you write a custom JavaScript action for GitHub Actions?
A JavaScript action consists of two files at minimum: action.yml (the action metadata) and an entry-point JavaScript file. It runs directly on the runner (no container spin-up), which makes it fast. The @actions/core and @actions/github npm packages provide the toolkit for reading inputs, setting outputs, and interacting with the GitHub API.
action.yml:
name: 'Post PR Comment' description: 'Posts a comment on the triggering pull request' inputs: message: description: 'Comment body' required: true outputs: comment-id: description: 'ID of the created comment' runs: using: 'node20' main: 'dist/index.js'
src/index.js:
const core = require('@actions/core'); const github = require('@actions/github'); async function run() { try { const message = core.getInput('message', { required: true }); const token = core.getInput('github-token'); const octokit = github.getOctokit(token); const { context } = github; const issue_number = context.payload.pull_request?.number; const { data: comment } = await octokit.rest.issues.createComment({ ...context.repo, issue_number, body: message, }); core.setOutput('comment-id', comment.id); } catch (err) { core.setFailed(err.message); } } run();
Key points:
- Bundle all dependencies into
dist/index.jsusing@vercel/ncc— do not rely onnpm installat runtime. Commit thedist/folder to the action repository. core.setFailed()both logs the error message and exits with code 1, marking the step as failed.- Use
using: 'node20'(ornode16) inaction.ymlto declare the Node.js version. - Test locally with
INPUT_MESSAGE="hello" node dist/index.js— inputs are injected asINPUT_<NAME>environment variables.
More Related questions...