Create a Custom GitHub Action in Typescript
Tags: github, githubactions, tutorial, typescript
Published: 2023-08-10 09:33:26

**GitHub Actions** are a powerful tool to automate your workflow. They can be used to **run tests**, **deploy** your code, **publish** a package, and much more.

The cool thing is, there's a GitHub Actions Marketplace where you can find a lot of actions created by... the community.

_But what if you can't find the action you need?_ You can create your own and publish it there!

## How to use this tutorial

{% details Read more... %} 


In this tutorial we're going to see in detail how to:

- Create a GitHub Action in Typescript
- Expand our Action to support custom inputs
- Integrate with GitHub's API to add labels to Pull Requests
- Unit testing our action
- Debugging in Visual Studio Code
- Publishing our action to the GitHub Marketplace
- Using our action in another repository
- Some final touches to make our project more robust

The articles will be split into separate bite-sized chapters as technically each one can be a little tutorial by itself.

If you're interested in the full text all at once, you can find it here: https://leonardomontini.dev/typescript-github-action/

One more great piece of advice is to create a new repository and follow along with the steps. This way you'll have a working action at the end of the post and you'll be able to play with it and experiment, rather than just reading a long tutorial and forgetting about 90% of it.

The full code of this tutorial is available on GitHub on [this repo](https://github.com/Balastrong/ga-label-issue), so you can always refer to it if you get stuck.

{% enddetails %}

The full tutorial (all chapters at once) is also available as a video, which you can find here:

{% youtube N26xgQ7kLKo %}

## Chapter 1: Building an MVP

Let's begin with an MVP (Minimum Viable Product) of our GitHub Action.

We'll start simple with an action having only the required parts to understand the basics, then we'll add more features to it.

### Action Definition

The definition is stored in the `action.yml` file, put directly in the root of the repository.

```yaml
name: 'My Custom Action'
description: 'Say Hello'
author: 'Leonardo Montini'

runs:
  using: 'node16'
  main: 'dist/index.js'
```

The most minimal action definition is composed of a name and a `runs` object to define how the action is executed and what file to run. `description` and `author` are optional.

In case your action has some inputs, they will be defined in the `action.yml` file as well, in the `inputs` object.

```yaml
inputs:
  name:
    description: 'The name of the person to greet'
    required: true
    default: 'World'
```

When publishing the action to the store, you might want to customize the appearance of the action in the marketplace. This can be done by adding a `branding` object to the `action.yml` file.

```yaml
branding:
  icon: 'activity'
  color: 'green'
```

Anyway, for this MVP the first snippet will be enough.

### Project setup

Let's create an empty node project with `npm init -y`.

You can now open `package.json` and add the build script.

```json
{
  "scripts": {
    "build": "tsc"
  }
}
```

Since we want to use Typescript, we'll need to install it as a dev dependency.

```bash
npm install -D typescript
```

Then we'll create a `tsconfig.json` by running `npx tsc --init` and we'll edit it to match our needs.

```json
{
  "compilerOptions": {
    "target": "ES2019",
    "module": "commonjs",
    "outDir": "lib",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}
```

### Project code

We can now create the `src/index.ts` file and start writing our action.

```ts
console.log('Hello World!');
```

We're building an MVP, right? So let's keep it simple for now and focus on all the required steps. We'll have time to expand it later.

### Building the action

We can now build the action by running `npm run build` which will execute the `tsc` command as we defined in the `package.json` file.

This will create a `dist` folder containing the compiled code.

```bash
dist
└── index.js
```

In case you see `index.js` generated in the root of the project or inside `src/`, you might want to add make sure the `outDir` option to the `tsconfig.json` file is properly set to `dist`.

### Creating the repository

In case you haven't done it yet, it's time to create a git repository as we'll need to push our code to GitHub soon.

```bash
git init
```

Don't forget to add a `.gitignore` file to the project to avoid committing files that shouldn't be tracked by git, for example, the `node_modules` folder.

A quick way to do it is by running `npx gitignore node` which will create a `.gitignore` file with the most common entries for a node project.

**Note**: in this particular case we want to push the `dist` folder to GitHub, so we'll need to remove the `dist` entry from the `.gitignore` file.

```bash
git add .
git commit -m "Initial commit"
git remote add origin
git push -u origin main
```

## Closing

And that was it for today! if you have any question or suggestion, feel free to add a comment :)

See you in the next chapter!

---

Thanks for reading this article, I hope you found it interesting!

I recently launched my Discord server to talk about Open Source and Web Development, feel free to join: https://discord.gg/bqwyEa6We6

Do you like my content? You might consider subscribing to my YouTube channel! It means a lot to me ❤️
You can find it here:
[![YouTube](https://img.shields.io/badge/YouTube:%20Dev%20Leonardo-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UC-KqnO3ez7vF-kyIQ_22rdA?sub_confirmation=1)

Feel free to follow me to get notified when new articles are out ;)
{% embed https://dev.to/balastrong %}