Writing your first Github action
Tags: github, javascript, tutorial, githubaction
Published: 2020-03-13 16:19:15

Two days back I came to know about [hackathon by Github](https://githubhackathon.com/) and I thought of making some useful action. But before that, I decided to do something fun and learn about the basics of Github action. So I created [action-pr-gifs](https://github.com/koushikmohan1996/action-pr-gifs) Inspired from [action-cats](https://github.com/marketplace/actions/action-cats). **action-pr-gifs** will post gif as a comment in PR based on the type of the PR. Check out my action and have fun! 

Let's make a simple GitHub action to post a comment in a PR!

<p align="center"><img width="300"src="https://media.giphy.com/media/LmNwrBhejkK9EFP504/giphy.gif"></a></p>


# Setting the repo

 You can create an action in 2 ways
 
- Docker container action
- Javascript action 

### Docker container

This type of action is ideal if you want to run your actions with a particular Operating system, environments, etc. Note that they are slow when compared with javascript action as it has to retrieve the container.

### Javascript action

JavaScript actions can run directly on a runner machine. This is much simpler and faster and I will be using javascript action in this tutorial.


Instead of creating a node repo from scratch I will recommend using [template](https://github.com/actions/javascript-action) provided by the GitHub team. It has almost everything to start your first GitHub action. But if you want to start everything from scratch like me, you can always do that.

Before writing any actual code, please make sure to configure eslint with your project. It will make sure that you use the same coding style across the project.


# action.yml

Add a file action.yml in your root folder and add the following line.

```yml
name: 'Action name'
description: 'A sample description'
inputs:
  github-token:
    description: 'Pass in secrets.GITHUB_TOKEN'
    required: true
runs:
  using: 'node12'
  main: 'dist/index.js'
```

Did you note that I added `dist/index.js` as main? I will come to that later.

# Actual code

Add a new function `run` in index.js or `src/index.js` whatever you prefer. This is a simple function to post a comment `You are awesome` on every pull request. Note that this should be triggered for PR event only. So if it triggered for any other event, the function should throw an error.

```js
const core = require('@actions/core');
const github = require('@actions/github');

async function run() {
  try {
    const githubToken = core.getInput('GITHUB_TOKEN');

    const { context } = github;
    if (context.payload.pull_request == null) {
      core.setFailed('No pull request found.');
    }

    const pullRequestNumber = context.payload.pull_request.number;
    const octokit = new github.GitHub(githubToken);
    const message = 'Wow! you are awesome';

    octokit.issues.createComment({
      ...context.repo,
      issue_number: pullRequestNumber,
      body: message,
    });
  } catch (error) {
    core.setFailed(error.message);
  }
}

run();
```

# Build

GitHub downloads each action run in a workflow during runtime and executes it as a complete package of code. So you need `node_modules` to run your code. If you added it to `.gitignore`, please remove it. Alternatively, you can use `zeit/ncc` to build your source code so that you don't need `node modules`.

Install ncc using the following command

```sh
yarn add @zeit/ncc --dev
```
Build your source using 
```sh
ncc build index.js (or) ncc build src/index.js 
```

This will build your source files to the `dist` folder. This will be your main file and remember to build and commit this file every time you make a change in the source file.  

# Testing
There is nothing much in this action to test. But it is always recommended to write tests for your GitHub action. You can check my repository for some examples.


*That is it, You have written your first Github action. It is time to test it*


### Adding action to repositories

Before listing the action in the marketplace you can test it once in the same repository. Create a file `.github/workflows/main.yml` with the same structure and add the following line.

```yml
name: PR

# Controls when the action will run. Triggers the workflow on push or pull request 
# events but only for the master branch
on:
  pull_request:
    branches: [ master ]
jobs:
  pr_check:
    runs-on: ubuntu-latest
    name: A job to Post comment on PR
    steps:
    - uses: actions/checkout@v2
    - name: PR Action
      uses: koushikmohan1996/action-pr-gifs@master
      with:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

```

Based on your action you should change `koushikmohan1996/action-pr-gifs@master` with your `username/reponame@master`. Here I used `branches: [master]` so the action will trigger only if the PR is created to master branch. You can remove this if you want this in all branches.

After you tested everything, you can add this action to Marketplace by creating a release. Note that you need a readme file and license file to make a release in the Marketplace.

Check this sample pr of [action-pr-gifs](https://github.com/koushikmohan1996/action-pr-gifs/pull/3). Drop a comment if you have created any cool Github action or if you come across one.

Signing off!

<p align="center"><img width="300"src="https://media.giphy.com/media/3ohs7KViF6rA4aan5u/giphy.gif"></a></p>