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
2 changes: 1 addition & 1 deletion codegen-examples/examples/linear_webhooks/.env.template
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
LINEAR_ACCESS_TOKEN="..."
LINEAR_SIGNING_SECRET="..."
LINEAR_TEAM_ID="..."
LINEAR_TEAM_ID="e30439bb-1547-4d4e-9934-eb757c9beb46" # Zeeeepa team ID
110 changes: 110 additions & 0 deletions codegen-examples/examples/linear_webhooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Linear Webhooks Example

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

## Setup

### Prerequisites

- Python 3.10+
- Linear account with API access
- (Optional) ngrok or similar tool for exposing local endpoints

### Installation

1. Clone the repository:
```bash
git clone https://github.com/codegen-sh/codegen.git
cd codegen/codegen-examples/examples/linear_webhooks
```

2. Create a virtual environment:
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```

3. Install dependencies:
```bash
pip install -r requirements.txt
```

4. Create a `.env` file from the template:
```bash
cp .env.template .env
```

5. Edit the `.env` file with your Linear credentials:
```
LINEAR_ACCESS_TOKEN="your_linear_access_token"
LINEAR_SIGNING_SECRET="your_linear_signing_secret"
LINEAR_TEAM_ID="e30439bb-1547-4d4e-9934-eb757c9beb46" # Zeeeepa team ID
```

## Running the Example

### Standalone Version (No Modal)

Run the standalone version with:

```bash
python standalone.py
```

This will start a FastAPI server on http://0.0.0.0:8000.

To expose your local server to the internet (required for Linear webhooks), you can use ngrok:

```bash
ngrok http 8000
```

Then configure your Linear webhook to point to the ngrok URL + `/linear/events` (e.g., `https://your-ngrok-url.ngrok.io/linear/events`).

### Modal Version (Serverless)

To deploy the Modal version:

1. Install Modal:
```bash
pip install modal
```

2. Set up your Modal account:
```bash
modal token new
```

3. Deploy the app:
```bash
modal deploy webhooks.py
```

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

## Configuring Linear Webhooks

1. Go to your Linear workspace settings
2. Navigate to API → Webhooks
3. Click "Create webhook"
4. Enter your webhook URL (ngrok URL or Modal URL)
5. Select the events you want to receive (e.g., Issues)
6. Save the webhook

## Troubleshooting

- **Import Error**: If you get an import error for `codegen`, make sure you've installed it with `pip install codegen>=0.22.2`
- **Authentication Error**: Verify your Linear credentials in the `.env` file
- **Webhook Not Receiving Events**: Check that your ngrok URL is correct and that the Linear webhook is properly configured

## Customizing the Example

To handle different Linear events, modify the `@app.linear.event()` decorator in `webhooks.py` or add a new handler in `standalone.py`.

For example, to handle Project events:

```python
@app.linear.event("Project")
def handle_project(self, data: dict):
print(f"Project event: {data}")
```
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 @@
fastapi>=0.95.0
uvicorn>=0.22.0
python-dotenv>=1.0.0
codegen>=0.22.2
38 changes: 38 additions & 0 deletions codegen-examples/examples/linear_webhooks/standalone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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()

# Initialize the CodegenApp
app = CodegenApp(name="test-linear")

# Create a FastAPI app
fastapi_app = app.app

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

# Verify required environment variables
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 create a .env file with the following variables:")
print("\n".join([f"{var}=\"your_{var.lower()}\"" for var in required_vars]))
exit(1)
Comment on lines +28 to +31

Choose a reason for hiding this comment

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

Using print statements for error handling and exit(1) to terminate the application is not recommended for production environments. It's better to use a logging framework for error messages, which offers more flexibility and control over how messages are recorded and viewed. Additionally, consider handling missing environment variables more gracefully by using exceptions or a dedicated error handling mechanism.

Recommended Change:
Replace print statements with logging and consider using exceptions for error handling:

import logging
logging.error(f"Missing required environment variables: {', '.join(missing_vars)}")
raise EnvironmentError("Required environment variables are missing")


if __name__ == "__main__":
print("Starting Linear webhook server...")
print("Listening for Linear events at: http://0.0.0.0:8000/linear/events")
print("Use a tool like ngrok to expose this endpoint to the internet.")
print("Then configure your Linear webhook to point to: https://your-ngrok-url/linear/events")
uvicorn.run(fastapi_app, host="0.0.0.0", port=8000)

Choose a reason for hiding this comment

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

Listening on all network interfaces (0.0.0.0) can expose the application to unnecessary security risks if not properly secured. It's recommended to bind the server to 127.0.0.1 if it's only meant to be accessed locally or ensure proper security measures are in place (like a firewall) when exposing it to the internet.

Recommended Change:
Change the host to 127.0.0.1 if local access is sufficient:

uvicorn.run(fastapi_app, host="127.0.0.1", port=8000)

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 chaining of apt_install and pip_install methods in the Docker image setup could lead to inefficient caching and larger image sizes. Consider splitting these into separate layers or optimizing the Dockerfile to leverage build caching effectively. This can be achieved by grouping package installations or using multi-stage builds to minimize the final image size.

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

Choose a reason for hiding this comment

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

The application name "test-linear" is hardcoded in the instantiation of CodegenApp. To enhance flexibility and maintainability, consider externalizing this configuration to an environment variable or a configuration file. This approach allows for easier adjustments in different deployment environments without modifying the codebase.


# 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
4 changes: 2 additions & 2 deletions codegen-examples/examples/pr_review_bot/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from logging import getLogger
Comment on lines 1 to 2

Choose a reason for hiding this comment

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

Redundant Imports

The import statements for logging and from logging import getLogger are redundant. You can remove the specific import of getLogger and use logging.getLogger() instead, which will make the import section cleaner and avoid redundancy.

Recommended Change:

import logging
# from logging import getLogger  # This line can be removed

import modal
from codegen.extensions.events.app import CodegenApp
from codegen.extensions.events.codegen_app import CodegenApp
from fastapi import Request
from codegen.extensions.github.types.events.pull_request import PullRequestLabeledEvent, PullRequestUnlabeledEvent
from helpers import remove_bot_comments, pr_review_agent
Expand All @@ -26,7 +26,7 @@
)
)

app = CodegenApp(name="github", image=base_image, modal_api_key="")
app = CodegenApp(name="github")


@app.github.event("pull_request:labeled")
Comment on lines 31 to 32

Choose a reason for hiding this comment

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

Missing Error Handling in Event Registration

The event handler for pull_request:labeled does not include any error handling. This could lead to unhandled exceptions if the event data is not as expected or if there are issues during the handling process. It's recommended to add error handling to ensure the application behaves gracefully under error conditions.

Suggested Improvement:

@app.github.event("pull_request:labeled")
def handle_labeled(event: PullRequestLabeledEvent):
    try:
        # existing code
    except Exception as e:
        logger.error(f"Error handling labeled event: {e}")

Expand Down
4 changes: 2 additions & 2 deletions codegen-examples/examples/ticket-to-pr/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from codegen import Codebase, CodeAgent
from codegen.extensions.clients.linear import LinearClient
from codegen.extensions.events.app import CodegenApp
from codegen.extensions.events.codegen_app import CodegenApp
from codegen.extensions.tools.github.create_pr import create_pr
from codegen.shared.enums.programming_language import ProgrammingLanguage
from helpers import create_codebase, format_linear_message, has_codegen_label, process_update_event
Expand All @@ -17,7 +17,7 @@

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

Choose a reason for hiding this comment

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

The specified Python version '3.13' in the modal.Image.debian_slim configuration may be incorrect or a typo, as Python 3.13 is not a released version. This could lead to issues when building the image or at runtime.

Recommendation: Verify the intended Python version and update it to a valid version, such as '3.9' or '3.10', to ensure compatibility and avoid deployment failures.


app = CodegenApp("linear-bot", image=image, modal_api_key="")
app = CodegenApp("linear-bot")


@app.cls(secrets=[modal.Secret.from_dotenv()], keep_warm=1)

Choose a reason for hiding this comment

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

The keep_warm=1 setting in the @app.cls decorator is used to keep the serverless function warm, potentially improving response times. However, this setting might incur additional costs or have other implications depending on the platform's billing and performance characteristics.

Recommendation: Review the necessity and impact of the keep_warm setting in this context. If it's essential for performance, consider documenting its benefits and potential costs. If not, you might want to adjust or remove this setting to optimize resource usage and cost.

Expand Down