docs
GitHub Artifact

GitHub Artifact Viewer

A GitHub OAuth app which can take a workflow artifact and turn it into a browseable static site. Useful for:

  • viewing HTML test output from a CI run (e.g. playwright, vitest, jest, ava, pytest, golang)
  • browsing a static site without having to deploy it anywhere
  • viewing images/PDFs/other files generated by a workflow

This should really be a feature built into GitHub, but it isn't (opens in a new tab). It is built into some other CI providers like CircleCI. Note: The artifact is downloaded and extracted on the fly, so this should be used by developers for debugging, not for anything user-facing or frequently-accessed.

Get Started

Just add a print statement to your GitHub workflow:

name: CI
on: [push]
jobs:
  run:
    steps:
       - uses: actions/checkout@v3
       - run: npm install
       - run: npm test
       - uses: actions/upload-artifact@v3
         if: always()
         with:
           name: test-report
           path: test-output
+     - name: print artifact url
+       if: always()
+       run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/test-report'

This will print out a link for the artifact named test-report. Clicking it will:

  1. Prompt you to sign in with your GitHub account
  2. Serve the files that are in the test-report artifact uploaded with actions/upload-artifact.

That's it!

How this might look with playwright

Examples

Test Frameworks

Playwright

Don't pay for Cypress! Playwright has a built in HTML reporter, which is interactable, and renders detailed failure information, step-by-step traces including console logs, network calls, as well as screenshots and videos. Just add reporter: 'html' to your playwright.config.ts, run playwright test --reporter html via the CLI, or see playwright docs (opens in a new tab) to customize the output folder. Then upload an artifact and print the URL:

- run: npx playwright test
- uses: actions/upload-artifact@v3
  if: always()
  with:
      name: playwright
      path: playwright-report
- if: always()
  run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/playwright'

Playwright example

Jest

First install jest-reporters-html

npm install --save-dev jest-reporters-html

Then you can run jest with npx jest --reporters jest-reporters-html or add it to your jest.config.js:

module.exports = {
  reporters: [
    'default',
    'jest-reporters-html',
  ],
}
- run: npx jest
- uses: actions/upload-artifact@v3
  if: always()
  with:
      name: jest
      path: jest_html_reporters.html
- if: always()
  run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/jest'

Jest example

vitest

Use vitest's built-in HTML reporter:

vitest --reporter html

Vitest example

ava

There's no great HTML reporter for AVA, but there's an ok-ish one for tap:

npm install tap-html --save-dev
- run: npx ava --tap | npx tap-html --out output.html
- uses: actions/upload-artifact@v3
  if: always()
  with:
      name: ava
      path: output.html
- if: always()
  run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/ava'

AVA example

mocha

Mocha's doc (opens in a new tab) reporter outputs simple HTML. Their documentation has some pointers on how to add styling to the output.

- run: npx mocha --reporter doc > output.html
- uses: actions/upload-artifact@v3
  if: always()
  with:
      name: mocha
      path: output.html
- if: always()
  run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/mocha'

Mocha example

Other languages

python

pytest-html (opens in a new tab) outputs a useful document.

pip install pytest-html
- run: pytest tests --html report/index.html
- uses: actions/upload-artifact@v3
  if: always()
  with:
      name: pytest
      path: output.html
- if: always()
  run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/pytest'

pytest example

go

Go's default test output can be piped to go-test-report (opens in a new tab).

go get github.com/vakenbolt/go-test-report
go install github.com/vakenbolt/go-test-report
- run: go test -json | go-test-report
- uses: actions/upload-artifact@v3
  with:
    name: go
    path: test_report.html
- run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/go'

go example

Other use-cases

Static site

If you're building a static site, you can upload the files as an artifact, and then view it with this tool. This is useful for previewing a site without having to deploy it anywhere. e.g. using https://github.com/shuding/nextra-docs-template (opens in a new tab):

jobs:
  website:
    runs-on: ubuntu-latest
    steps:
      - run: mkdir -p website
      - name: setup
        working-directory: ./website
        run: |
          # just an example, you can use any static site generator
          git clone https://github.com/shuding/nextra-docs-template
          cd nextra-docs-template
          echo 'module.exports = withNextra({
            images: {unoptimized: true},
            output: "export", // makes sure nextjs outputs the whole site as static files
            basePath: "/artifact/${{github.repository}}/${{github.run_id}}/website"
          })' >> next.config.js
          npm install
      - name: build site
        run: npm run build
        working-directory: website/nextra-docs-template
      - uses: actions/upload-artifact@v3
        with:
          name: website
          path: website/nextra-docs-template/out
      - run: echo 'https://mmkal.com/artifact/${{github.repository}}/${{github.run_id}}/website'

Note - as mentioned, this is not a good way to deploy a website! For very simple use cases it may help debug.

website example

Private Repos

You can use this with private repositories without configuring anything. Since it's an OAuth app, you can share the link with anyone - they will be prompted to sign in to browse the artifact. Anyone lacking permissions to view the repo or its artifacts will just get a 404 - similar to how they would if they tried to view the repo on github.com.

Source

Since this wasn't built by GitHub, you need to be aware that you're allowing the OAuth app itself to make GitHub API requests on your behalf. The GitHub API is only used for listWorkflowRunArtifacts and downloadArtifact. In future it may be used for checking sponsorship status and/or rate limiting.

DIY

If you don't want to pay, or authorizing an external app to download artifacts is a sticking point. You can absolutely do this yourself! The code isn't open-sourced because it's a bit of a mess, but here's roughly what it takes:

  • create a vercel project with app directory enabled
  • create a GitHub OAuth app with callback URL pointing at yourvercelurl.com/api/auth/callback
  • add a next-auth (opens in a new tab) route GET/POST handler with:
    • a GithubProvider set up with the client id and secret from your GitHub OAuth app
    • a jwt callback to copy the GitHub access token from the account to the JWT
    • a session callback to copy the access token from the JWT to the session
  • write a nextjs route GET handler under artifact/[...path]/route.ts which:
    • loads the session
    • redirects to your signin page with a callback URL of the current path if not logged in
    • gets the token otherwise
    • parses out the owner, repo, workflow run id, artifact name, and file path from the inbound URL
    • uses the GitHub API and the user's token to list workflow run artifacts
    • find the artifact matching the name specified in the URL
    • 404 if it's not found
    • fetch the archive download url
    • pipe the respnose to a zip reader
    • parse the entries
    • match the entry path to the path from the inbound request
    • if none is found, build an index HTML page listing the files under the path from the inbound request
    • map the path extension to a mime type to set a content-type response header
    • respond with the individual entry file data as a Buffer

Upcoming

Features missing that may be added soon:

  • Rate limiting/freemium-ness. Full discloure: I built this for me, and I'd be happy to share, but I don't want to run up a big bill. There might be some mechanism like allowing GitHub Sponsors to use it.
  • API Changes, including URL scheme changes. Existing URLs might break. At time of writing this has been up for all of a day. There's no API versioning - which means it's a very unstable "v0".
  • Caching/better CDN usage. The implementation is laughably inefficient, and hits multiple GitHub APIs and extracts a whole zip file, to serve every individual request.
  • Anonymous mode - for public repositories, allow unauthenticated users to view artifacts.
  • A GitHub Action. This would just be a very thin wrapper for actions/upload-artifact and echo 'https://mmkal.com/...', but could do stuff like writing to $GITHUB_STEP_SUMMARY too.
  • Switch to https://authjs.dev (opens in a new tab)
  • More recipes. My first use case for this was playwright test reporting, but there are plenty of other recipes that would be useful too:
    • deno test
    • bun test
    • java testing?
  • An autoinstaller. Sign in, select a repo, and a pull request to add the artifact viewer to all workflows that use upload-artifact is opened.