⚡️ Create your first GitHub action in 6 minutes
Tags: github, webdev, tutorial, javascript
Published: 2020-06-07 22:56:28

## Introduction

Hello, DEV community! 😉 New day and new useful information about GitHub Actions. Earlier, we figured out how to [build & deploy a static 11ty website to remote virtual server after pushing](https://dev.to/koddr/automate-that-a-practical-guide-to-github-actions-build-deploy-a-static-11ty-website-to-remote-virtual-server-after-push-d19) and, I hope, you've learned the principles I set out in that article.

Using _ready-made_ GitHub Actions from Marketplace is good, but... what if they are **not available** or/and your configuration is **too specific**? 

That's right! 👌 Let's write your own first action.

<a name="toc"></a>
### 📝 Table of contents

- [The basis for the example](#ch-0)
- [GitHub action basics](#ch-1)
  - [`action.yml`](#ch-1-1)
  - [`Dockerfile`](#ch-1-2)
  - [`entrypoint.sh`](#ch-1-3)
  - [Other files & folders](#ch-1-4)
- [Documentation](#ch-2)
- [Publish action to GitHub Marketplace](#ch-3)
  - [Final result](#ch-3-1)
- [Questions for better understanding](#ch-4)
- [Exercises for independent execution](#ch-5)

<a name="ch-0"></a>
## The basis for the example

Let's take GitHub action, what I created for build **Sapper-based** website:

{% github truewebartisans/actions-sapper %}

<a name="ch-1"></a>
## GitHub action basics

Usually, the structure of a project for GitHub action, looks like this:

```console
.
├── .gitignore
├── .github
│   ├── gh-cover.png
│   └── workflows
│       └── test_deploy.yml
├── action.yml
├── Dockerfile
├── entrypoint.sh
├── LICENSE
└── README.md
```

Now, let's take apart the most basic files. In the code samples below, I specifically separated sections and marked them to make it easier to read. 

> But, you may not do this in your actions... 😏

[↑ Table of contents](#toc)

<a name="ch-1-1"></a>
### `├── action.yml`

This is the settings file for the action.

```yml
# Action's main info
name: "Sapper Action"
description: "Build your Sapper-based static website"

# Action's author name
author: "Vic Shóstak"

# Action's branding data for GitHub Marketplace
# See docs: [1]
branding:
  icon: "package" # icon name from Feather open source icons pack
  color: "blue"

# Action's inputs (options)
# See docs: [2]
inputs:

  # First input (option) name
  # See docs: [3]
  build_mode:

    # Input's description
    description: "Build mode to the Sapper (could be `build` or `export`, by default `export`)"

    # Specify, if this input is required to define
    required: false

    # Input's default value
    default: "export"

  # Second input (option) name
  args:
    description: "Arguments to pass to the Sapper invocation (by default `--legacy`)"
    required: false
    default: "--legacy"

# Configures the image (used for the Docker action)
# See docs: [4]
runs:

  # Use Docker to run the action 
  using: "docker"

  # The Docker image to use as the container to run the action
  # or path to 'Dockerfile' with settings
  image: "Dockerfile"
```

🔗 Links to docs: [[1]](https://help.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#branding), [[2]](https://help.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs), [[3]](https://help.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputsinput_id), [[4]](https://help.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-docker-actions).

[↑ Table of contents](#toc)

<a name="ch-1-2"></a>
### `├── Dockerfile`

Yeah, as you have already understood, this is a regular `Dockerfile` with container settings (_the same as you usually use in your projects_):

```dockerfile
# Select the Docker image
FROM node:10-alpine

# Copy `entrypoint.sh` file to container's root
COPY entrypoint.sh /

# Set permissions for `entrypoint.sh` file execution 
RUN chmod +x /entrypoint.sh

# Define an entrypoint to be called after the container is created
ENTRYPOINT ["/entrypoint.sh"]
```

> ☝️ **Tip**: please read _The Best practices for writing Dockerfiles_ [here](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/).

[↑ Table of contents](#toc)

<a name="ch-1-3"></a>
### `├── entrypoint.sh`

The entrypoint, wich will be called after the container is created. In our case, it's just a simple `bash` script.

```bash
#!/bin/sh

echo "Running \`npm install\`"
npm install

echo "Build Sapper"
npx sapper $INPUT_BUILD_MODE $INPUT_ARGS
```

Pay attention, `$INPUT_BUILD_MODE` is equal to `inputs.build_mode` in `actions.yml` file and the same logic also applies to `$INPUT_ARGS` (`inputs.args`). In other words, all variables, that you would allow for definition to your users should be defined as `$INPUT_<OPTION_NAME>`.

#### Conditional operator example

If some variable is specific, you can define it with a `boolean` variable in `action.yml` and then, check in `entrypoint.sh`.

- Specify a new input for `inputs` section into `action.yml`:

```yml
# ...

inputs: 
  npm_install:
    description: 'If set to `true`, `npm install` will be run'
    required: false
    default: false

# ...
```

> ☝️ **Tip**: it doesn't matter, what case the variable name is in `action.yml` file, but there should be either only uppercase or only lowercase letters!

- And now, just add `if...then` section to `entrypoint.sh`:

```bash
#!/bin/sh

if [ "$INPUT_NPM_INSTALL" = "true" ]; then
  echo "Running \`npm install\`"
  npm install
fi

# ...
```

[↑ Table of contents](#toc)

<a name="ch-1-4"></a>
### Other files & folders

- `.github/workflows/test_build.yml` — test for your action (optional).
- `.github/gh-cover.png` — cover image for preview, like this:

![sapper github action](https://dev-to-uploads.s3.amazonaws.com/i/43wt4yfqioa6nyxqj5yg.png)

[↑ Table of contents](#toc)

<a name="ch-2"></a>
## Documentation

Documentation and usage examples in `README.md` are the most important parts of your GitHub action. Because, your action (_possibly_) will be used by other developers! Always remember that, when you create a new action.

Here are some _simple_ rules to help you write really good docs:

- Write a detailed start guide right at the beginning.
- Format all optional values (`inputs`) in tabular format, following the string structure: `Input name`, `Is required?`, `Default value`, `Description`.
- Add more examples, especially, if your action can be built into a chain of actions or used only in combination with another GitHub action. 

![add more examples](https://dev-to-uploads.s3.amazonaws.com/i/ggiax8y6ay62n55ls1a9.png)

- Add beautiful and understandable image cover for preview of your GitHub repository. This is also important, because when people sharing link of your GitHub action, will see an attractive preview that can create a great conversion!

![gh repository settings](https://dev-to-uploads.s3.amazonaws.com/i/td7batqjfbn7oe9o2s52.png)

> ☝️ **Tip**: You can download a special template (with safe indents) to create a cover image for preview of your repository.

- (_advanced_) Add a demo repository with an example of _how to apply your GitHub action_, such as I did for action of this example:

{% github truewebartisans/actions-sapper-demo no-readme %}

[↑ Table of contents](#toc)

<a name="ch-3"></a>
## Publish action to GitHub Marketplace

Okay! 👍 We are now fully ready to publish your first action to the GitHub Actions Marketplace.

1. Go to _Releases_ page in your repository and draft new release.
2. Check `Publish this Action to the GitHub Marketplace`.
3. GitHub will check all the files related to the action and will show warnings, if something doesn't comply with _best practices_ or/and _community agreements_.
4. Add `Security contact email`.
5. Add `Primary` and `Secondary` action categories.
6. Specify tag version (use a [Semantic versioning](https://semver.org/)), title and description.
7. Click `Publish release`.

![publish to gh marketplace](https://dev-to-uploads.s3.amazonaws.com/i/4xe2x25mkmsgm9tpwykc.png)

If you did everything right, then on the main page of your repository will be added a badge with an invitation to view this action on the GitHub Marketplace:

![gh actions badget](https://dev-to-uploads.s3.amazonaws.com/i/171gf3cwdmizbcj55ane.png)

[↑ Table of contents](#toc)

<a name="ch-3-1"></a>
### Final result

In fact, that's it! 😎 You have just **created your first GitHub action**, written excellent documentation for it and published it on the Marketplace.

![gh action page on marketplace](https://dev-to-uploads.s3.amazonaws.com/i/27bbll2ma5hlf5fm7qet.png)

🎉 Congratulations! **We did it!**

[↑ Table of contents](#toc)

<a name="ch-4"></a>
## 💬 Questions for better understanding

1. In what case should you write the name of each `input`?
2. Which collection of icons does GitHub Actions use for `branding` section on `action.yml` file?
3. What are the best practices, when selecting a tag for a release version?
4. How can you define environment variables in `input`? _Read this section in the GitHub Actions [docs](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#env)_.

[↑ Table of contents](#toc)

<a name="ch-5"></a>
## ✏️ Exercises for independent execution

- Try to repeat everything you have seen in the article, but with your own action. _Please, write about your results in the comments to this article!_
- Change color and icon of your action at GitHub Marketplace.

[↑ Table of contents](#toc)

<a name=""></a>
## Photos/Images by

- GitHub Actions promo website ([link](https://github.com/features/actions))
- GitHub repository settings ([link](https://github.com))
- True web artisans `actions-sapper` repository ([link](https://github.com/truewebartisans/actions-sapper))

<a name=""></a>
## P.S.

If you want more articles (like this) on this blog, then post a comment below and subscribe to me. Thanks! 😻

And of course, you can help me make developers' lives even better! Just connect to one of my projects as a contributor. It's easy!

My projects that need your help (and stars) 👇

- 🔥 [gowebly][gowebly_url]: A next-generation CLI tool for easily build amazing web applications with Go on the backend, using htmx & hyperscript and the most popular atomic/utility-first CSS frameworks on the frontend.
- ✨ [create-go-app][cgapp_url]: Create a new production-ready project with Go backend, frontend and deploy automation by running one CLI command.
- 🏃 [yatr][yatr_url]: Yet Another Task Runner allows you to organize and automate your routine operations that you normally do in Makefile (or else) for each project.
- 📚 [gosl][gosl_url]: The Go Snippet Library provides snippets collection for working with routine operations in your Go programs with a super user-friendly API and the most efficient performance.
- 🏄‍♂️ [csv2api][csv2api_url]: The parser reads the CSV file with the raw data, filters the records, identifies fields to be changed, and sends a request to update the data to the specified endpoint of your REST API.
- 🚴 [json2csv][json2csv_url]: The parser can read given folder with JSON files, filtering and qualifying input data with intent & stop words dictionaries and save results to CSV files by given chunk size.

<!-- Footer links -->

[gowebly_url]: https://github.com/gowebly
[cgapp_url]: https://github.com/create-go-app
[yatr_url]: https://github.com/koddr/yatr
[gosl_url]: https://github.com/koddr/gosl
[csv2api_url]: https://github.com/koddr/csv2api
[json2csv_url]: https://github.com/koddr/json2csv