GitHub Actions: Create your own actions

how to create your own github actions

GitHub Actions is a service that allows you to implement any type of customized solutions for your CI/CD workflows. However, they went even further and created modular actions that allow you to re-use the already written functionality. As well as allowing others to use and appreciate public actions you have created. I have given you an introduction to GitHub Actions as well as a more detailed description of GitHub Actions` functionalities. Now let’s check out a bit more about the service!

Two ways to create your own actions

At the moment of writing this blog post, there are two ways to create your own actions:

  • Docker based actions that are usable only on Linux OS
  • Javascript based actions that are possible to use in Linux, MacOS, Windows.

We are going to show you the advantages and disadvantages of both options.

Docker Actions

In the case of Docker Actions you are free to choose the OS, dependencies and toolchain for your added functionality. The whole workflow is encapsulated into the docker image you have created. That gives you more control over the environment, programming language selection and the packages you use.

Javascript Actions

In case of JavaScript actions require only pure javascript code and run directly on the same machine where your workflow starts. If you plan to use such a type of action on self hosted runners this will require the installation of NodeJs. The main advantage of Javascript actions is the ability to run on every GitHub Action’s supported OS. And also the speed: Javascript actions run way faster than Docker based actions.

The repository becomes an action

The repository is considered to be an action when it contains a metadata file (action.yml or action.yaml). Here is an example of action.yml file from the action created by the PM Agency.

name: 'PM Slack Notifier'
description: 'Send slack notifications easily'
author: 'Aram Kocharyan '
using: 'docker'
image: 'Dockerfile'
icon: 'bell'
color: 'blue'

The arguments are pretty clear from their names.

LESEN SIE AUCH:  Machine learning case study: street sign detection

Let’s continue with this example and explain the logic behind this specific example. Logically, your Docker based action must have a Dockerfile that defines the specifications of the container we are going to use. Here is the Dockerfile for our slack notifier action:

FROM golang:1.11-alpine3.9 AS builder

LABEL "com.github.actions.icon"="bell"
LABEL "com.github.actions.color"="blue"

LABEL ""="Slack Notifier"
LABEL "com.github.actions.description"="Send slack notifications easily"

COPY main.go ${GOPATH}/src/pm

ENV GOOS linux

RUN go get -v ./...
RUN go build -a -installsuffix cgo -ldflags '-w -extldflags "-static"' -o /go/bin/slack-notify .

# alpine:latest at 2019-01-04T21:27:39IST
FROM alpine@sha256:46e71df1e5191ab8b8034c5189e325258ec44ea739bba1e5645cff83c9048ff1

COPY --from=builder /go/bin/slack-notify /usr/bin/slack-notify


RUN apk update \
&& apk upgrade \
&& apk add \
bash \
jq \
ca-certificates \
python \
py2-pip && \
pip install shyaml && \
rm -rf /var/cache/apk/*

# fix the missing dependency -
RUN mkdir /lib64 && ln -s /lib/ /lib64/

COPY *.sh /

RUN chmod +x /*.sh

Our notifier is written in golang, thus we require the golang image for the building phase. Then what is happening is just the installation of several dependencies (you have to define yours) and the copying of files to the Docker image. And of course the entry point of the Docker image that is going to be executed on the start of the Docker image:

#!/usr/bin/env bash

# Check required env variables
if [[ -z "$SLACK_WEBHOOK" ]]; then
if [[ -n "$VAULT_ADDR" ]] && [[ -n "$VAULT_TOKEN" ]]; then
if [[ -n "$VAULT_ADDR" ]] || [[ -n "$VAULT_TOKEN" ]]; then
missing_secret="VAULT_ADDR and/or VAULT_TOKEN"

if [[ "$flag" -eq 1 ]]; then
printf "[\e[0;31mERROR\e[0m] Secret \`$missing_secret\` is missing. Please add it to this action for proper execution.\n"
exit 1

# custom path for files to override default files

if [[ -d "$custom_path" ]]; then
rsync -av "$custom_path/" /
chmod +x /*.sh

bash "$main_script"

What is important at this point is that you can access and use the environmental variables passed to your action from the workflow YAML file. For example, in our case we check if some of the required environment variables exist in our contexts (e.g. SLACK_WEBHOOK). You may prefer to use the github secrets to pass some of the variables.

LESEN SIE AUCH:  Github Actions: Build and deploy react native iOS apps

Publishing your own actions

Whenever your action is ready you may publish it to Github Marketplace. To do so, you just need to create a release in your action repository after which the action source is located. Usually Github will suggest you to do so after it located the action.yml file on your repository. During the release creation process you will be asked a few simple questions and the action will pass very simple checks for compatibility (if all necessary files exist etc.).

The last but not least point is the readme file. Don’t forget to specify all the used parameters and give a couple of nice examples on how to use your action. Do not forget that after publishing the action to Github Marketplace it becomes publicly available and many user might use, rate and contribute to it.

Join the open source development on GitHub Actions

In this context, we are also supporting open source projects and invite all interested parties to use and contribute to our actions. In the meantime, we are going to create new and even more useful actions. Check our docker image builder and slack notifier actions.

Über den Autor

Dr. Aram Kocharyan

Dr. Aram Kocharyan ist bei P&M für den Bereich DevOps zuständig. Aram stammt aus dem wunderschönen Armenien, lebt nun aber in Hamburg. Für den P&M Blog schreibt er auf Englisch.

Scroll to Top