Skip to main content

Overview

The GitHub Webhook Server processes six core GitHub webhook events to automate repository management and pull request workflows. Each event triggers specialized handlers that perform specific automation tasks.

Supported GitHub Events

pull_request

Triggers: PR opened, reopened, edited, synchronized, ready_for_review Handler: PullRequestHandler (webhook_server/libs/handlers/pull_request_handler.py) Automation Actions:
  • Post welcome comment with available commands
  • Create tracking issue (if configured)
  • Assign reviewers based on OWNERS files
  • Apply labels (size, branch, WIP)
  • Queue CI/CD checks (tox, pre-commit, container builds)
  • Run conventional title validation
  • Trigger test oracle (if configured)
  • Update PR size labels
  • Re-run CI/CD checks
  • Update merge status labels
  • Check for conflicts
  • Trigger test oracle on approval (if configured)
  • Update WIP label based on title
  • Re-run conventional title check (if title changed)
  • Post welcome comment
  • Process as new PR (assign reviewers, labels, checks)
Example Event Data:
{
  "action": "opened",
  "pull_request": {
    "number": 123,
    "title": "Add new feature",
    "user": {"login": "developer"},
    "base": {"ref": "main"},
    "head": {"ref": "feature-branch"},
    "draft": false
  },
  "repository": {
    "name": "my-repo",
    "full_name": "org/my-repo"
  }
}

issue_comment

Triggers: Comment created on pull request Handler: IssueCommentHandler (webhook_server/libs/handlers/issue_comment_handler.py) User Commands:
CommandActionPermission Required
/verifiedMark PR as verifiedOWNERS
/verified cancelRemove verificationOWNERS
/holdBlock PR mergingAnyone
/hold cancelUnblock PR mergingAnyone
/wipMark as work in progressAnyone
/lgtmApprove changes (reviewers)OWNERS reviewers
/approveApprove PR (approvers)OWNERS approvers
/assign-reviewersRe-assign reviewers from OWNERSAnyone
/check-can-mergeCheck merge readinessAnyone
/reprocessRe-run entire PR workflowOWNERS
/retest <test-name>Run specific testOWNERS
/retest allRun all configured testsOWNERS
/cherry-pick <branch>Cherry-pick to branchOWNERS
/build-and-push-containerBuild and push containerOWNERS
/test-oracleAI test recommendationsAnyone
/automergeEnable auto-mergeMaintainers
Example Event Data:
{
  "action": "created",
  "issue": {
    "number": 123,
    "pull_request": {"url": "..."},
    "user": {"login": "reviewer"}
  },
  "comment": {
    "body": "/lgtm",
    "user": {"login": "reviewer"}
  },
  "repository": {
    "name": "my-repo",
    "full_name": "org/my-repo"
  }
}

pull_request_review

Triggers: Review submitted, dismissed Handler: PullRequestReviewHandler (webhook_server/libs/handlers/pull_request_review_handler.py) Automation Actions:
  • Review Submitted:
    • Add review labels (approved-reviewer, lgtm-reviewer, changes-requested-reviewer, commented-reviewer)
    • Update approval count
    • Check merge readiness
    • Trigger test oracle (if configured and approved)
  • Review Dismissed:
    • Remove corresponding review labels
    • Update approval count
    • Re-check merge status
Review States:

APPROVED

Adds approved-<username> label, counts toward minimum-lgtm requirement

CHANGES_REQUESTED

Adds changes-requested-<username> label, blocks merge

COMMENTED

Adds commented-<username> label, informational only

LGTM Comment

Comment with /lgtm adds lgtm-<username> label

check_run

Triggers: GitHub Actions workflow completion, external CI check completion Handler: CheckRunHandler (webhook_server/libs/handlers/check_run_handler.py) Automation Actions:
  • Check Completed:
    • Update merge eligibility based on required checks
    • Trigger auto-merge if all checks pass and automerge label present
    • Update can-be-merged check status
    • Re-evaluate branch protection rules
Optimized Processing:
# Early exit conditions (no repository clone needed)
if action != "completed":
    return  # Skip 'created' action

if check_run_name == "can-be-merged" and check_run_conclusion != "success":
    return  # Skip failed can-be-merged checks

# Only clone repository when actually processing
await self._clone_repository(pull_request=pull_request)
Example Event Data:
{
  "action": "completed",
  "check_run": {
    "name": "build",
    "status": "completed",
    "conclusion": "success"
  },
  "pull_requests": [
    {"number": 123}
  ]
}

push

Triggers: Branch push, tag creation Handler: PushHandler (webhook_server/libs/handlers/push_handler.py) Automation Actions:
  • Tag Push:
    • Build and publish container (if configured)
    • Publish to PyPI (if configured)
    • Create GitHub release
  • Branch Push:
    • Update branch labels on related PRs
    • Trigger branch-specific CI/CD
Example Event Data:
{
  "ref": "refs/tags/v1.0.0",
  "repository": {
    "name": "my-repo",
    "full_name": "org/my-repo"
  },
  "pusher": {
    "name": "maintainer"
  }
}

Other Events

While the server can receive any GitHub webhook event, only the six events above trigger active processing. Other events are logged but not processed.

Event Processing Flow

High-Level Flow Diagram

Detailed Processing Steps

1

Webhook Reception

FastAPI receives webhook at /webhook_server endpoint with event data in JSON body and headers (X-GitHub-Event, X-GitHub-Delivery, X-Hub-Signature-256)
2

Security Validation

  • Verify client IP against GitHub/Cloudflare allowlist (if configured)
  • Validate HMAC-SHA256 signature using webhook secret
  • Check required headers and fields
3

Context Creation

Create structured logging context with webhook metadata (hook_id, event_type, repository, action, sender)
4

GithubWebhook Initialization

  • Load repository configuration (global + .github-webhook-server.yaml)
  • Select GitHub token with highest rate limit
  • Initialize repository API clients
  • Track initial rate limit for metrics
5

Repository Data Pre-Fetch

Fetch comprehensive repository data once (collaborators, protected branches, labels) to minimize API calls
6

Repository Cloning

Clone repository to temporary directory (optimized with early exits for check_run events)
7

Handler Routing

Route event to specialized handler based on X-GitHub-Event header:
  • push → PushHandler
  • pull_request → PullRequestHandler
  • issue_comment → IssueCommentHandler
  • pull_request_review → PullRequestReviewHandler
  • check_run → CheckRunHandler
8

Event Processing

Handler performs event-specific automation (assign reviewers, apply labels, run checks, post comments)
9

Metrics & Logging

  • Calculate token spend (rate limit consumption)
  • Write structured JSON log to webhooks_YYYY-MM-DD.json
  • Update context with final metrics
10

Cleanup

  • Remove temporary repository clone
  • Close GitHub API connections
  • Clear logging context

Event-Specific Processing Examples

Example 1: Pull Request Opened

{
  "action": "opened",
  "pull_request": {
    "number": 456,
    "title": "feat: Add user authentication",
    "user": {"login": "developer"},
    "base": {"ref": "main"},
    "head": {"ref": "feat/auth"},
    "additions": 85,
    "deletions": 12
  }
}

Example 2: Issue Comment with /lgtm

{
  "action": "created",
  "issue": {"number": 456},
  "comment": {
    "body": "/lgtm",
    "user": {"login": "reviewer1"}
  }
}

Example 3: Check Run Completed

{
  "action": "completed",
  "check_run": {
    "name": "build",
    "status": "completed",
    "conclusion": "success"
  },
  "pull_requests": [{"number": 456}]
}

Event Filtering & Optimization

Draft PR Handling

if await asyncio.to_thread(lambda: pull_request.draft):
    allow_commands = self.config.get_value("allow-commands-on-draft-prs")
    
    # Only allow issue_comment events when explicitly configured
    if allow_commands is None or self.github_event != "issue_comment":
        logger.debug("Pull request is draft, skipping")
        return None

Check Run Optimization

Performance Impact: Early exit conditions reduce repository cloning by 90-95%, saving 5-30 seconds per webhook.
# Skip cloning for non-completed check runs
if action != "completed":
    return None

# Skip cloning for failed can-be-merged checks
if check_run_name == "can-be-merged" and check_run_conclusion != "success":
    return None

# Only clone when actually needed
await self._clone_repository(pull_request=pull_request)

Event Configuration

Configure which events trigger specific automation in config.yaml:
repositories:
  my-repository:
    name: my-org/my-repository
    
    # Enable specific features
    verified-job: true        # Enable verified label automation
    pre-commit: true          # Run pre-commit on PR events
    
    # Test oracle triggers
    test-oracle:
      triggers:
        - approved            # Run on approval
        - pr-opened          # Run on PR opened
        - pr-synchronized    # Run on new commits
    
    # Auto-merge configuration
    set-auto-merge-prs:
      - main                  # Enable auto-merge for main branch
    
    # Required checks for merge
    protected-branches:
      main:
        include-runs:
          - build
          - test
          - pre-commit

Architecture

Event-driven handler architecture overview

User Commands

Complete list of issue comment commands

Configuration

Event-specific configuration options

API Reference

Webhook endpoint specifications

Build docs developers (and LLMs) love