How to create and test a GitHub Action that generates Supabase database types

Estee Tey - May 7 '22 - - Dev Community

How to generate types from a Supabase database

On the Supabase documentation, there is a page on generating types. Following the instructions, the script to run looks something like this.

Note the additional --version=2 parameter. This probably became a mandatory prop after some update to the openapi-typescript tool.

npx openapi-typescript https://{projectId}.supabase.co/rest/v1/?apikey={specialApiKey} --output=types/supabase.ts --version=2
Enter fullscreen mode Exit fullscreen mode

The values for the anon key and URL can be found in the Supabase dashboard.

Screenshot of Supabase project dashboard

Running the script generates a file like this. With the definitions that are generated there, I could create a type for Bill with just the code block below.

import {definitions} from '../types/supabase';

export type Bill = definitions['Bill'];
Enter fullscreen mode Exit fullscreen mode

Most of my project source code still works fine after changing the type. The only code I had to refactor is related to the deadline field which is Date type. The definitions has the field declared as a string, even though they do acknowledge it is a Date format.

Bill: {
    /** Format: date */
    deadline?: string;
}
Enter fullscreen mode Exit fullscreen mode

Personally I think this is ok, since this forces you to convert date objects to appropriate ISO strings, so there is less ambiguity about passing the Date object that you have constructed in JS to Supabase. If you don’t like this you could override it in your self-declared type.

In the same documentation, they also included a section on how to update types automatically with GitHub Actions. This ensures that whenever you update the database, your GitHub action will automatically update the types that you have in your DB. Then, the next time you pull your source code, you would know what are the new changes and how to accommodate them.

In the docs, there’s a script to be added to the package.json as such.

"update-types": "npx openapi-typescript https://your-project.supabase.co/rest/v1/?apikey=your-anon-key --output types/database/index.ts"
Enter fullscreen mode Exit fullscreen mode

However, I wasn’t too sure how to replace the values in the package.json script safely with environmental variables when I push the source code. I’m not very familiar with bash syntax, but I assume the script should look something like this for my project.

"update-types": : "npx openapi-typescript https://${SUPABASE_URL}/rest/v1/?apikey=${ANON_KEY} --version=2 --output types/database/index.ts"
Enter fullscreen mode Exit fullscreen mode

To double confirm the syntax, I decided to use the Sourcegraph Visual Studio Code plugin to look for projects that have implemented this GitHub action.

Cross-reference code with Sourcegraph Visual Studio Code plugin

The Sourcegraph Visual Studio Code plugin can be installed through the Extensions panel.

Once you have it installed, you can find the Sourcegraph icon at the side bar. When you click it, you will see the usual UI to do a universal code search. To find other projects that also generate types, we can pass in a query npx openapi-typescript.

We see quite a few results, and luckily, in the 3rd project called tone-row/flowchart-fun, I see that they have package.json script that looks like a promising candidate. They have variables such as SB_URL and SB_ANON_KEY which resemble Supabase stuff ✨

"generate:types": "export $(cat .env.local | xargs) && npx openapi-typescript \"${SB_URL}/rest/v1/?apikey=${SB_ANON_KEY}\" --output types/database/index.ts",
Enter fullscreen mode Exit fullscreen mode

With this cross-reference and knowledge, we know that we are missing out on wrapping the whole API endpoint in a string with escape characters. Then, we can modify our previous script to match this script.

"update-types": "npx openapi-typescript \"${SUPABASE_URL}/rest/v1/?apikey=${SUPABASE_ANON_KEY}\" --version=2 --output types/database/index.ts"
Enter fullscreen mode Exit fullscreen mode

If we run this script locally via npm run update-types , we can see it generates the same output that we have done previously ✨

Out of curiosity, I also want to know if their GitHub workflow follows the same structure that was given in the example given in Supabase docs. The cool thing is with the Sourcegraph plugin, I can explore the repository in the editor itself.

Sadly, this project is not using the generate:types script that they have written in a GitHub workflow. They’re probably only running the npm script locally. Thankfully with the help of the Supabase documentation folks, at least we don’t have to write the action from scratch.

How to create the GitHub workflow

This section has been merged to Supabase documentation here after publication of this article.

To add GitHub action workflows to your project, you need a new folder .github/workflows to store the workflows. For the workflow.yml that consist the steps for the GitHub action workflow, we will be using the sample GitHub action workflow on the Supabase documentation as a base. I have modified it a little to insert some GitHub secrets as environment variables, you can refer to the comments below.

name: Update database types

on:
  schedule:
    # sets the action to run daily. You can modify this to run the action more or less frequently
    - cron: '0 0 * * *'
    # for the workflow to be dispatched manually via GitHub actions dashboards.
  workflow_dispatch:

jobs:
  update:
    runs-on: ubuntu-latest
    env:
        SUPABASE_URL: ${{secrets.SUPABASE_URL}}
        SUPABASE_ANON_KEY: ${{secrets.SUPABASE_URL}}
    steps:
      - uses: actions/checkout@v2
        with:
          persist-credentials: false
          fetch-depth: 0
      - uses: actions/setup-node@v2.1.5
        with:
          node-version: 14
      # -- add echo -- #
      - run: |
          npm run update-types 
          echo "$(cat types/database/index.ts)"
      - name: check for file changes
        id: git_status
        run: |
          echo "::set-output name=status::$(git status -s)"
      - name: Commit files
        if: ${{contains(steps.git_status.outputs.status, ' ')}}
        # -- change git stage filename -- #
        run: |
          git add types/database/index.ts
          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --local user.name "billy-github-actions[bot]"
          git commit -m "Update database types" -a
      - name: Push changes
        if: ${{contains(steps.git_status.outputs.status, ' ')}}
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ github.ref }}
Enter fullscreen mode Exit fullscreen mode

The changes include:

  • Addition of a trigger workflow_dispatch so that the workflow can be dispatched manually via GitHub actions dashboards if necessary.
  • Addition of an echo statement to see the content of the result file from running update-types script
  • Pass GitHub action secrets into environment variables.
  • Change the filename to be staged

If you are not familiar with GitHub action secrets, think of it as separate environment variables solely for GitHub actions. This is a screenshot of where you can add them at the settings of your GitHub project.

Settings > Secrets > GitHub secrets

To deploy the workflow, simply push the .github/workflows folder.

Then you will see the new workflow available in the Actions tab of your GitHub project. When you click on the additional options button, you can manually dispatch the workflow.

You can also view the logs of each workflow run if you encounter any issues. For example, here in the succeeded job, I can see the src/types/supabase.ts file content that is retrieved since we logged it out as part of the steps of the workflow.

You will see similar content as the definitions file you obtained by manually running the npm script

In the next section, I’ll introduce you to a handy tool that I learnt while building a custom composite GitHub action to test GitHub actions locally.

How to test GitHub Actions locally with act

act is a tool that lets you test GitHub actions locally. The benefit of this is that you get faster feedback without clogging up the GitHub Action Runner history on your project.

Refer to the GitHub repository README.md to see how to install act. You would need Docker installed too. The first time you start up act, you will be asked to choose the image that you want to create. For this GitHub Action, to test the functionality of updating the database types, the Micro image should be sufficient.

3 choices given to you for the image, can refer to docs.

After this config is completed, you can navigate to ~/.actrc to see the config for your docker image.

-P ubuntu-latest=node:16-buster-slim
-P ubuntu-20.04=node:16-buster-slim
-P ubuntu-18.04=node:16-buster-slim
Enter fullscreen mode Exit fullscreen mode

Note that the Micro image does not have the full capability of a GitHub Action runner, so you will see errors related to git commands. I don’t want to explode my computer’s memory with the Large image (~20GB), but you can try if you like.

To run this workflow locally with act, we can run this bash command.

act -j update --secret-file .env
Enter fullscreen mode Exit fullscreen mode


we can pass in the following parameters:

Explanation of parameters

  • -j ${jobName}
    • we only have 1 job declared in this workflow, so we can pass the update job
  • --secret-file ${filePath}

    • for the project, I am already using .env for all the environment variables, so I can pass this same file for secrets.
    SUPABASE_URL=your_url
    SUPABASE_ANON_KEY=hehe
    
    • If you rather not have .env files locally for some reason, you can also pass variables manually with the parameter -s SUPBASE_URL=your_url -s SUPABASE_ANON_KEY=hehe

After running the bash command, here’s a simplified extract of the terminal output

[Update database types/update]   ✅  Success - actions/setup-node@v2.1.5
[Update database types/update] ⭐  Run npm run update-types
echo "$(cat src/types/supabase.ts)"
[Update database types/update]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/2] user= workdir=
| 
| > billy@0.0.1 update-types /Users/lyqht/self-study/Billy
| > npx openapi-typescript "${SUPABASE_URL}/rest/v1/?apikey=${SUPABASE_ANON_KEY}" --version=2 --output src/types/supabase.ts
| 
| npx: installed 10 in 3.328s
| ✨ openapi-typescript 5.2.0
🚀 ***/rest/v1/?apikey=*** -> /Users/lyqht/self-study/Billy/src/types/supabase.ts [28ms]
| /**
|  * This file was auto-generated by openapi-typescript.
|  * Do not make direct changes to the file.
|  */
| 
| export interface paths {
|   "/": {
|     get: {
|       responses: {
|         /** OK */
|         200: unknown;
|       };
|     };
|   };
|   "/Bill": {
|     get: {
|     .... } // i won't show you all of it, but you will be able to see all these
[Update database types/update]   ✅  Success - npm run update-types
echo "$(cat src/types/supabase.ts)"
[Update database types/update] ⭐  Run check for file changes
[Update database types/update]   🐳  docker exec cmd=[bash --noprofile --norc -e -o pipefail /var/run/act/workflow/git_status] user= workdir=
| /var/run/act/workflow/git_status: line 2: git: command not found
[Update database types/update]   ⚙  ::set-output:: status=
[Update database types/update]   ✅  Success - check for file changes
Enter fullscreen mode Exit fullscreen mode

If you run this, you can can see the output contains the paths portion for '/Bill' as a result of running the update-types script. This meant that it worked correctly 🎉

⚠️ Remember that these changes happen on the docker instance itself, you will not see any changes on your local folder.

Bonus: In Action

On 7 Apr 2022, I added 2 new tables, and my bot was a good boi.

New definitions added to the src/types/supabase.ts file

Since publishing the original article, I also created a GitHub action that does what is listed above. Check it out here!

That's a wrap folks! 🎉

https://c.tenor.com/eoM1uCVuXtkAAAAM/yay-excited.gif

Thank you for reading, hope you enjoyed the article!

If you find the article awesome, hit the reactions 🧡 and share it 🐦~

To stay updated whenever I post new stuff, follow me on Twitter.

. . . . . . . . . . . . . . . . . . . . . . . . . . . .