Starting Github Action Workflows From Observable
Tags: observable, programming, github, devops
Published: 2021-12-27 09:21:25

---
title: Starting Github Action Workflows From Observable
published: true
date: 2021-12-27 09:06:51 UTC
tags: observable, programming, github, devops
canonical_url: https://observablehq.com/@tomlarkworthy/repository-dispatch
---

Using Observable as the front end for Github Actions is a great way to provide a nice interface without the hassle of hosting anything. Recently I developed a [notebook library](https://observablehq.com/@tomlarkworthy/repository-dispatch) which allows authenticated *and* unauthenticated users to kick off Action workflow via a repository dispatch.

A [repository dispatch](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#repository_dispatch) triggers [Github Action](https://docs.github.com/en/actions) workflows via an authenticated HTTP request. See the [documentation](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#repository_dispatch) on Github. From there you can do all kinds of things, even programmatically creating commits.

We document two major ways to trigger actions from an [Observable](https://observablehq.com) notebook.

1. authenticated, where notebook **readers** provide the access token to trigger a workflow
2. pre-authenticated, where the notebook **author** configures a proxy using their own creds, so anybody can trigger workflows on the author's blessed path.

To use

```
import {dispatch, createDispatchProxy} from '@tomlarkworthy/repository-dispatch'
```

## Repository Dispatch Client Library for Observable

The authenticated dispatch function takes an access token, plus the other options, to perform the dispatch

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ne31cnluhffriull1edr.png)

```
async function dispatch(
  token,
  { owner, repo, event_type = "event_type", client_payload = undefined } = {}
)

```

## Example Usecase 1: Pass Personal Token In Notebook

To use our simple dispatch function, we need a Github API access token. A simple way is to ask the reader for one.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6y1rdvl4pjk4q1pqg1h8.png)

Note: If you use [localStorageView](https://observablehq.com/@tomlarkworthy/local-storage-view#localStorageView) you can remember the input across page sessions in local storage.

There are situations where you don't want the reader to provide a token. For this, we need to introduce a secure environment.

## Example Usecase 2: Use Shared Secret Stored in [Webcode.run](https://webcode.run) to pre-authorize a configuration

Code executed on [webcode.run](https://webcode.run) is remote, and so secrets are not exposed to notebook readers. By creating a proxy to do the request, we can expose Github workflows to the public without requiring them to supply tokens. Instead, the secret can be set in the inline UI (or at [@endpointservices/secrets](https://observablehq.com/@endpointservices/secrets)). But default, the secret should be called `github_token`, but you can override this in the `createDispatchProxy` arguments.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nymisa4jwsbazl2cpaxu.png)


which you can call to invoke a github workflow

Note, configuration of the dispatch function has to be done when creating the proxy so that the endpoint cannot be used against arbitrary repositories. An opt-in exception is that when the `client_payload` arg is set to undefined, the client can pass a value of `client_payload` as the first argument (this is to enable passing data into a workflow).

```
viewof remoteDispatch = createDispatchProxy({
  owner: "tomlarkworthy",
  repo: "octokit-test"
})
```

The result of a `createDispatchProxy` call is a view. The UI is the default [webcode.run](https://webcode.run) UI, which provides a method of setting the secret once you are logged in. You will need to create a stored secret called `github_token` **and** bind it to the endpoint. If you forget to configure the secret, the underlying Octokit API will throw `HTTPError: Not Found` exceptions. Your notebook needs to be published for it to work when you are logged out.

The data channel of the returned `createDispatchProxy` view is a dispatch function. When called, it will run the dispatch remotely, but importantly, you do not need to pass any authentication credentials. So you can just place it in a button for anybody to use. Try mine below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lmawy3o0kkzll1khbmd.png)
*Refer to the [source notebook](https://observablehq.com/@tomlarkworthy/repository-dispatch) for the interactive demo*

The above workflow will trigger [this workflow](https://github.com/tomlarkworthy/octokit-test/blob/main/.github/workflows/log-http.yml) which in turn write back into the repository as a log entry found [here](https://github.com/tomlarkworthy/octokit-test/blob/main/log/http.log). So you can see for yourself that your triggers are registered by inspecting the timestamps in the logs!

The example here will cause a commit to occur in a repository you would not normally have permissions to! Now imagine what is possible when you can offload storage into git repositories for public users on [Observablehq](https://observablehq.com)!

## Writing workflows

I recommend [Triggering GitHub Actions Using Repository Dispatches](https://dev.to/teamhive/triggering-github-actions-using-repository-dispatches-39d1) for a good overview of the technique.

At the beginning of a workflow file (stored in `/.github/workflows/<name>.yml`) you announce how the workflow is triggered. For an externally HTTP triggered workflow you use `repository_dispatch`. You also can _optionally_ restrict what the `event_type` must be through the `types` array property:-

```
name: HTTP triggered workflow
on:
  repository_dispatch:
  types: [start-example-workflow]

```

Next, you list jobs with steps. Steps can include anything off the vast Github Actions [marketplace](https://github.com/marketplace?type=actions) or just simple shell scripting!

```
jobs:
  commit-timestamp:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Log workflow execution in log
        run: |
          mkdir -p ./log
          echo "$(date '+%Y-%m-%d %H:%M:%S') inbound HTTP" >> ./log/http.log
      - name: Commit updated log
        run: |
          git config --global user.name 'Log External HTTP'
          git config --global user.email 'robot@webcode.run'
          git add ./log/http.log
          git commit -am "Log inbound HTTP"
          git push

```

### Observable + Github Actions

Observable is a great way to provide a lightweight interactive UI with minimal development effort. When paired with Github actions you can use Observable to create a nice GUI over the Action primitives. You can also use Actions to enhance the Observable experience, for example, auto-backing up notebooks into a Github repo using the [onversion hook](https://observablehq.com/@endpointservices/onversion).