GitHub Integration Setup Guide

GitHub Integration Setup Guide

This guide walks you through connecting Lathe Studio to GitHub for CI/CD pipeline integration and issue tracking.


Prerequisites#

  • GitHub account (personal or organization)
  • GitHub repository with Actions workflows
  • Project admin access in Lathe Studio

Overview#

The GitHub integration enables:

  • CI/CD Webhooks: Automatically create builds when GitHub Actions workflows complete
  • Issue Sync: Link test failures to GitHub Issues
  • Pull Request Status: Display test results directly in PRs

Connecting GitHub#

Step 1: Create an API Key

  1. Go to Settings > Organization > API Keys
  2. Click Create API Key
  3. Give it a name (e.g., "GitHub Actions")
  4. Select scopes:
    • builds:read - View builds
    • builds:create - Create new builds
  5. Copy the generated key (shown only once)

Step 2: Configure GitHub Webhook

  1. In GitHub, go to your repository
  2. Navigate to Settings > Webhooks
  3. Click Add webhook
  4. Configure:
    • Payload URL: https://lathestudio.dev/api/webhooks/github
    • Content type: application/json
    • Secret: (optional) Add a webhook secret for signature verification
    • SSL verification: Enable
  5. Events: Select "Workflow runs" or "Send me everything"
  6. Click Add webhook

Step 3: Add API Key to Headers

In the webhook configuration, add a custom header:

  • Name: Authorization
  • Value: Bearer <your-api-key>

Alternatively, use the X-Pt-Org-Id header with your organization ID.

Step 4: Test the Integration

  1. Trigger a workflow run in GitHub Actions
  2. Go to Releases page in Lathe Studio
  3. You should see the build in the Build Queue section
  4. Assign it to a release

Authentication Methods#

Include the API key in the Authorization header:

Authorization: Bearer pt_live_xxxxxxxxxxxxxxxx

Benefits:

  • Rate limiting per key
  • Usage tracking
  • Scoped permissions

Method 2: Organization ID

Include your organization ID in a custom header:

X-Pt-Org-Id: your-org-uuid

Note: This method has basic rate limiting and is less secure. Use API keys for production.


How It Works#

  1. Workflow Completes → GitHub sends webhook to /api/webhooks/github
  2. Authentication → Webhook verifies API key or org ID
  3. Project Matching → System tries to match repo URL to a project
  4. Queue or Create:
    • If project + active release found → Build created directly
    • If project found but no release → Queued for release assignment
    • If no project match → Queued for project + release assignment
  5. Assignment → User assigns queued builds via Releases page

Build Queue UI#

The Build Queue appears on the Releases page when there are pending builds:

  • Shows build name, source (GitHub), project, commit/branch
  • Assign to Release: Select an active release for the project
  • Select Project: Navigate to projects if project not auto-detected
  • Reject: Remove build from queue (no build created)

GitHub Actions Example#

Add this step to your existing .github/workflows/test.yml after your test runner finishes. The if: always() ensures results are sent even if tests fail.

name: Test and Report

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Tests
        run: npm test -- --reporter=json --outputFile=test-results.json

      - name: Upload Results to Lathe Studio
        if: always()
        env:
          LATHE_API_KEY: ${{ secrets.LATHE_STUDIO_API_KEY }}
        run: |
          # Parse your test framework's JSON output into the Lathe Studio format.
          # Below is an example for Jest — adapt the jq filter to your framework.
          RESULTS=$(jq -c '
            [.testResults[] | .assertionResults[] | select(.status != "pending") | {
              test_identifier: .ancestorTitles + [.title] | join(" > "),
              name: .title,
              status: (if .status == "passed" then "passed" elif .status == "failed" then "failed" else "skipped" end),
              duration_ms: .duration,
              error: (if .failureMessages | length > 0 then .failureMessages[0] else null end)
            }]
          ' test-results.json)

          curl -X POST https://perpetualtest.dev/api/v1/results/ingest \
            -H "Authorization: Bearer $LATHE_API_KEY" \
            -H "Content-Type: application/json" \
            -d "{
              \"build\": {
                \"identifier\": \"${{ github.ref_name }}-${{ github.run_number }}\",
                \"branch\": \"${{ github.ref_name }}\",
                \"commit_sha\": \"${{ github.sha }}\",
                \"url\": \"${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}\"
              },
              \"source\": {
                \"pipeline\": \"github_actions\",
                \"run_id\": \"${{ github.run_id }}\",
                \"run_url\": \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"
              },
              \"results\": $RESULTS
            }"

What this does:

  1. Runs your tests and outputs JSON (Jest example shown)
  2. Parses the JSON into Lathe Studio's IngestResult format
  3. Sends everything to POST /api/v1/results/ingest
  4. Lathe Studio automatically:
    • Creates a Build (or re-uses an existing one by identifier)
    • Creates a completed Test Run linked to that Build
    • Matches results to existing Test Cases by test_identifier
    • Auto-creates new Test Cases for unknown identifiers

Response:

{
  "build_id": "uuid",
  "build_display_id": "main-1042",
  "test_run_id": "uuid",
  "test_run_display_id": "RUN-MOB-0123",
  "test_run_url": "/projects/.../runs/...",
  "test_cases_created": 3,
  "test_cases_linked": 47,
  "results_imported": 50
}

Adapting to other test frameworks:

FrameworkApproach
JestUse --json --outputFile= then jq to map fields
PytestUse pytest-json-report plugin, map nodeidtest_identifier
JUnit XMLConvert XML to JSON with xq or a Python script first
CypressUse cypress-multi-reporters with mocha-junit-reporter, then convert
PlaywrightUse blob reporter + npx playwright merge-reports --reporter=json

The only requirement is that each result has a stable test_identifier string. Use your existing display codes (TC-MOB-0042) or any unique ID — Lathe Studio will match them automatically.


Troubleshooting#

Builds not appearing

  1. Check webhook delivery in GitHub (Settings > Webhooks > Recent Deliveries)
  2. Verify API key is not expired or revoked
  3. Ensure the workflow run event is being sent
  4. Check that the repository URL matches your project settings

Wrong project assigned

The system matches by:

  1. Repository URL (exact match)
  2. Repository name (partial match)

You can manually assign to the correct project from the queue.

Rate limiting

API keys are limited to 60 requests per minute by default. Contact support to increase limits.

Webhook signature verification fails

If using webhook secrets:

  1. Verify the secret is correctly configured in both GitHub and Lathe Studio
  2. Check that the signature header is being sent
  3. Ensure the payload hasn't been modified

Security#

  • API keys are hashed using SHA-256 before storage
  • Only the first 12 characters are stored for identification
  • Keys can be revoked at any time
  • Webhook signatures (HMAC-SHA256) are supported for verification
  • All webhook communications use HTTPS

Unlinking GitHub#

To disconnect:

  1. Go to your GitHub repository
  2. Navigate to Settings > Webhooks
  3. Find the Lathe Studio webhook
  4. Click Delete

Note: Previously created builds remain in Lathe Studio. New builds will not be created until reconnected.


Advanced Configuration#

Custom Build Names

Override the default build name by adding metadata to your workflow:

- name: Set Build Name
  run: echo "PT_BUILD_NAME=Release ${{ github.ref_name }}" >> $GITHUB_ENV

Branch Filtering

Configure which branches trigger builds in Project Settings > CI/CD:

  • Include: main, develop, release/*
  • Exclude: dependabot/*, hotfix/*

For additional help, contact support.