-
Couldn't load subscription status.
- Fork 1
Fix Linear Webhooks and other examples #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 |
| 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}") | ||
| ``` |
| 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 |
| 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) | ||
|
|
||
| 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) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Listening on all network interfaces ( Recommended Change: uvicorn.run(fastapi_app, host="127.0.0.1", port=8000) |
||
| 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") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The chaining of |
||
| app = CodegenApp(name="test-linear", modal_api_key="", image=image) | ||
| app = CodegenApp(name="test-linear") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The application name |
||
|
|
||
| # 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 | ||
|
|
||
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant ImportsThe import statements for 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 | ||
|
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Error Handling in Event RegistrationThe event handler for 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}") |
||
|
|
||
| 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 | ||
|
|
@@ -17,7 +17,7 @@ | |
|
|
||
| image = modal.Image.debian_slim(python_version="3.13").apt_install("git").pip_install("fastapi[standard]", "codegen==v0.26.3") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The specified Python version '3.13' in the 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) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Recommendation: Review the necessity and impact of the |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
printstatements for error handling andexit(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
printstatements with logging and consider using exceptions for error handling: