Aren't the standard actions going too far for you? Write your own one!
Tags: actionshackathon21, github, node, typescript
Published: 2021-11-25 18:15:02

[Instructions]: # (To submit to the GitHub Actions x DEV Hackathon 2021, please fill out all sections.)

With my Github Action I want to show you how easy it is to write your own action. I use Github Workflows in several projects that don't need more than the use of already existing actions. In this case, I wanted more freedom and decided to write my own Action that can be used by other projects as well.

*TL;DR* to the Use Case: I wrote a small service that can be used to take screenshots of web pages automatically. This is useful for example if you build a release of your product and then want to update all screenshots for your documentation or landing page. That the service can be included in other workflows and a user does not have to deal with the API, I wrote a separate action for it.

### Motivation

Why do you build something like that? The reason is quite simple: everything that I have to do regularly and is essentially always the same, I automate. Tests run automated, linter checks run automated, the CI pipeline runs automated. So why not automate the screenshots as well? ;)

### My Workflow
[Note]: # (Please make sure the project links to the appropriate GitHub Actions repository, and includes [an open source license](https://choosealicense.com/) and README.)

My Github Action is essentially a small `NodeJS` app that ships as a Dockerfile and can be found in the Marketplace. It uses Github's `@actions/core` [package](https://www.npmjs.com/package/@actions/core), which makes interacting with the infrastructure a breeze.

Those who have already implemented `NodeJS` applications will have no problems building their own Github Action. I would like to highlight a few things to make it even easier for others to get started.

You need an `action.yaml` which describes the action:

```yaml
name: "Websiteshot"

description: "Github Action to schedule a new Screenshot Job with Websiteshot."

branding:
  icon: "camera"
  color: "blue"

runs:
  using: "docker"
  image: "Dockerfile"
```

The associated `Dockerfile` contains a few labels that are necessary for the Marketplace:

```docker
FROM node:slim

# A bunch of `LABEL` fields for GitHub to index
LABEL "com.github.actions.name"="Websiteshot"
LABEL "com.github.actions.description"="Github Action to schedule a new Screenshot Job with Websiteshot."
LABEL "com.github.actions.icon"="gear"
LABEL "com.github.actions.color"="blue"
LABEL "repository"="https://github.com/websiteshot/github-action"
LABEL "homepage"="https://websiteshot.app"
LABEL "maintainer"="Adam Urban <adam@websiteshot.app>"

# Copy over project files
COPY . .

# Install dependencies
RUN npm install

# Build Project
RUN npm run build

# This is what GitHub will run
ENTRYPOINT ["node", "/dist/index.js"]
```

The app itself is quite manageable, because it uses the also existing `NodeJS` [package](https://www.npmjs.com/package/@websiteshot/nodejs-client) of websiteshot and creates new jobs with the service:

```ts
import { Runner } from "./controller/runner.controller";
import { Validation } from "./controller/validation.controller";
const core = require("@actions/core");

async function run() {
  try {
    Validation.checkEnvVars();
    const jobId: string = await Runner.run();
    core.info(`Created Job with Id: ${jobId}`);
  } catch (error) {
    core.setFailed(error.message);
  }
}

run();
```

In this code snippet you can see how the `@actions/core` package makes it very easy to end an action with an error or to write a log output.

### Submission Category: Maintainer Must-Haves

[Note]: # (Maintainer Must-Haves, DIY Deployments, Interesting IoT, Phone Friendly, or Wacky Wildcards)


### Yaml File or Link to Code

[Note]: # (Our markdown editor supports pretty embeds. Try this syntax: `{% github link_to_your_repo %}` to share a GitHub repository)

But now to the workflow itself, which is also used by Websiteshot itself to generate new screenshots. After the CI pipeline has run, the last step is to start the Websiteshot action. You have to set a some environment variables that are used by the action.

```yaml
name: Publish

on: [push]

# ...

jobs:
  create-screenshot:
    runs-on: ubuntu-latest
    name: "Create Screenshot via Template"
    steps:
      - uses: websiteshot/github-action@main
        env:
          PROJECT_ID: ${{ secrets.PROJECT_ID }}
          API_KEY: ${{ secrets.API_KEY }}
          TEMPLATE_ID: "abcdef-ghi..."
```

- Marketplace: [https://github.com/marketplace/actions/websiteshot](https://github.com/marketplace/actions/websiteshot)
- Repository: [https://github.com/websiteshot/github-action](https://github.com/websiteshot/github-action)
- Eat your own dogfood: used to generate screenshots for documentation of Websiteshot: [https://docs.websiteshot.app/](https://docs.websiteshot.app/)

### Additional Resources / Info

[Note:] # (Be sure to link to any open source projects that are using your workflow!)

[Note]: # (Be sure to include the DEV usernames of your collaborators, if any. )

[Reminder]: # (Submissions are due on December 8th, 2021 (11:59 PM PT or 2 AM ET/6 AM UTC on December 9th).

- Github Core NodeJS Package: [https://www.npmjs.com/package/@actions/core](https://www.npmjs.com/package/@actions/core)

### Disclaimer

While writing this post I noticed that it could be interpreted as an ad for Websiteshot. It's not meant to be, it's one of my side projects and I think the description of the action can help others or serve as inspiration to build your own action for your own use case.

Of course, it's also possible to create all the screenshots within a Github action (without using an external service). All you need is a headless browser and you're ready to go.

Have fun!