The github-script action lets you run arbitrary JavaScript code directly within your GitHub Actions workflows, giving you a powerful way to automate tasks that go beyond simple YAML configurations.
Let’s see it in action. Imagine you have a workflow that triggers on every push to the main branch. After the push, you want to create a new GitHub issue with some details about the recent commit.
name: Create Issue on Push
on:
push:
branches:
- main
jobs:
create_issue:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create issue with github-script
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { owner, repo } = context.repo;
const latestCommit = await github.rest.repos.getCommit({
owner,
repo,
ref: context.sha,
});
const commitMessage = latestCommit.data.message;
const commitAuthor = latestCommit.data.commit.author.name;
await github.rest.issues.create({
owner,
repo,
title: `New commit pushed to main`,
body: `A new commit was pushed to the main branch.\n\nCommit Message: ${commitMessage}\nAuthor: ${commitAuthor}\nSHA: ${context.sha}`,
});
In this workflow, the github-script action is used in the create_issue job. It receives the GITHUB_TOKEN as a secret, which grants it permissions to interact with the GitHub API. The script parameter contains the JavaScript code.
Inside the script, context.repo provides the repository owner and name, and context.sha gives us the SHA of the latest commit. We use github.rest.repos.getCommit to fetch details about that commit, and then github.rest.issues.create to open a new issue with the commit message and author.
The core problem github-script solves is bridging the gap between declarative YAML and imperative logic. You can express complex conditional logic, interact with external services, or manipulate data in ways that are cumbersome or impossible with just YAML. It’s essentially an embedded Node.js environment tailored for GitHub Actions.
The github object available within the script is an authenticated Octokit client. This client is pre-configured with the GITHUB_TOKEN and has methods corresponding to the GitHub REST API (github.rest.issues.create, github.rest.pulls.list, etc.) and GraphQL API (github.graphql). You also have access to the context object, which contains information about the workflow run, the event that triggered it, and the repository.
The most surprising thing most people don’t know is that you can use import statements within the github-script action, allowing you to leverage external npm packages directly. For example, you could import moment from 'moment' to work with dates and times, or import _ from 'lodash' for utility functions. You just need to ensure the package is installed in your local environment if you’re running it locally for testing, or rely on its availability within the Action’s execution environment.
This flexibility means you can build sophisticated automation directly within your CI/CD pipeline. For instance, you could automatically label issues based on commit messages, post updates to Slack, or even trigger deployments based on specific conditions met in your JavaScript logic.
The next step is exploring how to use the GraphQL API with github-script for more complex data retrieval.