Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions codegen-examples/examples/linear_webhooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Linear Webhooks Example

This example demonstrates how to set up a webhook endpoint to receive events from Linear using the Codegen framework.

## Prerequisites

- Python 3.13 or later
- [Modal](https://modal.com/) account
- Linear account with API access

## Setup

1. Install the required dependencies:

```bash
pip install -r requirements.txt
```

Or using uv:

```bash
uv pip install -r requirements.txt
```

2. Create a `.env` file with your Linear credentials:

```
LINEAR_ACCESS_TOKEN="your_linear_access_token"
LINEAR_SIGNING_SECRET="your_linear_signing_secret"
LINEAR_TEAM_ID="your_linear_team_id"
```

You can find your Linear Team ID in your Linear workspace settings → Teams → Select your team → The Team ID will be in the URL (e.g., `https://linear.app/your-workspace/team/team-id/settings`).

## Running the Example

### Local Development

For local development and testing, you can run the example using Modal:

```bash
modal serve webhooks.py
```

This will start a local server that you can use for testing.

### Deployment

To deploy the example to Modal:

```bash
modal deploy webhooks.py
```

After deployment, Modal will provide a URL that you can use as your webhook endpoint in Linear.

## Setting Up the Linear Webhook

1. Go to your Linear workspace settings → API → Webhooks → Create webhook
2. Enter the Modal URL provided after deployment
3. Select the events you want to receive (e.g., Issue created, Issue updated)
4. Save the webhook

## How It Works

The example sets up a webhook endpoint that listens for Linear events. When an event is received, it prints the event data to the console. You can extend this example to perform custom actions based on the event data.

The key components are:

- `CodegenApp`: Handles the webhook events
- `@app.linear.event("Issue")`: Decorator that registers a handler for Issue events
- `app.linear.subscribe_all_handlers()`: Subscribes to all registered handlers
- `app.linear.unsubscribe_all_handlers()`: Unsubscribes from all handlers when the app is shut down

## Troubleshooting

If you encounter any issues, check the following:

- Make sure your Linear credentials are correct
- Verify that the webhook URL is accessible from the internet
- Check the Modal logs for any errors

## Further Reading

- [Linear API Documentation](https://developers.linear.app/docs/)
- [Modal Documentation](https://modal.com/docs/)
4 changes: 4 additions & 0 deletions codegen-examples/examples/linear_webhooks/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
codegen>=0.22.2
modal>=0.73.25
fastapi[standard]
python-dotenv
50 changes: 50 additions & 0 deletions codegen-examples/examples/linear_webhooks/standalone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Standalone version of the Linear webhooks example that can be run without Modal.
This is useful for local development and testing.
"""

import os
from dotenv import load_dotenv
from fastapi import FastAPI, Request
import uvicorn
from codegen.extensions.events.codegen_app import CodegenApp

# Load environment variables from .env file
load_dotenv()

# Create the CodegenApp instance
app = CodegenApp(name="linear-webhook-standalone")

# Get the FastAPI app from the CodegenApp
fastapi_app = app.app

@fastapi_app.get("/")
async def root():
return {"message": "Linear Webhook Server is running"}

@fastapi_app.post("/linear/webhook")
async def linear_webhook(request: Request):
"""Handle incoming Linear webhook events."""
payload = await request.json()
print(f"Received Linear webhook event: {payload}")
return {"status": "success"}

def main():
"""Run the FastAPI application."""
# Check if required environment variables are set
required_vars = ["LINEAR_ACCESS_TOKEN", "LINEAR_SIGNING_SECRET", "LINEAR_TEAM_ID"]
missing_vars = [var for var in required_vars if not os.getenv(var)]

if missing_vars:
print(f"Error: Missing required environment variables: {', '.join(missing_vars)}")
print("Please set these variables in your .env file or environment.")
return

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling for missing environment variables could be improved. Currently, the function simply returns without terminating the program, which could lead to further execution without the necessary configurations. Consider using sys.exit(1) to exit the program with a non-zero status code, indicating an error condition.

Suggested Change:

import sys
if missing_vars:
    print(f"Error: Missing required environment variables: {', '.join(missing_vars)}")
    print("Please set these variables in your .env file or environment.")
    sys.exit(1)


print("Starting Linear webhook server...")
print(f"LINEAR_TEAM_ID: {os.getenv('LINEAR_TEAM_ID')}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Printing sensitive information such as LINEAR_TEAM_ID directly to the console can lead to security risks if the logs are accessed by unauthorized users. Consider removing this print statement or ensuring that such sensitive information is handled securely and not exposed in logs or console outputs.

Suggested Change:
Remove or modify the print statement to avoid exposing sensitive information:

# print(f"LINEAR_TEAM_ID: {os.getenv('LINEAR_TEAM_ID')}")


# Run the FastAPI application
uvicorn.run(fastapi_app, host="0.0.0.0", port=8000)

if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions codegen-examples/examples/linear_webhooks/webhooks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import modal.running_app
from codegen.extensions.events.app import CodegenApp
from codegen.extensions.events.codegen_app import CodegenApp
import modal

image = modal.Image.debian_slim(python_version="3.13").apt_install("git").pip_install("fastapi[standard]", "codegen>=v0.22.2")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of a specific Python version (python_version="3.13") in the modal.Image.debian_slim method might lead to issues if this version becomes deprecated or unsupported. It's generally a good practice to allow for some flexibility in versioning unless there is a specific requirement for this exact version.

Recommendation: Consider using a version range or a more commonly supported version of Python to ensure long-term compatibility and ease of maintenance.

app = CodegenApp(name="test-linear", modal_api_key="", image=image)
app = CodegenApp(name="test-linear")

# Here is an example implementation of setting up an endpoint for receiving webhook events from Linear.
# The @app.linear.event() decorator takes care of subscribing to the webhook and also unsubscribing when the deployment spun
Expand Down